diff --git a/src/cli/cli_handler.cc b/src/cli/cli_handler.cc index e08d1d58..5812045a 100644 --- a/src/cli/cli_handler.cc +++ b/src/cli/cli_handler.cc @@ -129,6 +129,8 @@ cli_flow_t cli_handler::parse(int argc, const char **argv) "instead of actual location of `.clang-uml` file."); app.add_flag("--no-metadata", no_metadata, "Skip metadata (e.g. clang-uml version) from diagrams"); + app.add_flag("--print-start-from", print_start_from, + "Print all possible 'start_from' values for a given diagram"); try { app.parse(argc, argv); @@ -143,7 +145,7 @@ cli_flow_t cli_handler::parse(int argc, const char **argv) exit(app.exit(e)); // NOLINT(concurrency-mt-unsafe) } - if (quiet || dump_config) + if (quiet || dump_config || print_start_from) verbose = 0; else verbose++; @@ -196,6 +198,16 @@ cli_flow_t cli_handler::handle_pre_config_options() return cli_flow_t::kError; } + if (print_start_from) { + if (diagram_names.size() != 1) { + LOG_ERROR( + "ERROR: '--print-start-from' requires specifying one diagram " + "name using '-n' option"); + + return cli_flow_t::kError; + } + } + if (initialize) { return create_config_file(); } @@ -319,6 +331,18 @@ cli_flow_t cli_handler::handle_post_config_options() return cli_flow_t::kContinue; } +runtime_config cli_handler::get_runtime_config() const +{ + runtime_config cfg; + cfg.generators = generators; + cfg.verbose = verbose; + cfg.print_start_from = print_start_from; + cfg.progress = progress; + cfg.thread_count = thread_count; + + return cfg; +} + cli_flow_t cli_handler::print_version() { ostr_ << "clang-uml " << clanguml::version::CLANG_UML_VERSION << std::endl; @@ -546,8 +570,8 @@ cli_flow_t cli_handler::add_config_diagram_from_template( return cli_flow_t::kError; } - // First, try to render the template using inja and create a YAML node from - // it + // First, try to render the template using inja and create a YAML node + // from it inja::json ctx; for (const auto &tv : template_variables) { const auto var = util::split(tv, "="); diff --git a/src/cli/cli_handler.h b/src/cli/cli_handler.h index 6eb946a0..b785b14a 100644 --- a/src/cli/cli_handler.h +++ b/src/cli/cli_handler.h @@ -25,6 +25,19 @@ #include namespace clanguml::cli { + +/** + * @brief This class holds command line parameters not directly related to + * specific diagram configurations. + */ +struct runtime_config { + int verbose{}; + std::vector generators{}; + bool print_start_from{}; + bool progress{}; + unsigned int thread_count{}; +}; + /** * This enum represents possible exit states of the command line parser. */ @@ -132,6 +145,13 @@ public: */ bool ensure_output_directory_exists(const std::string &dir); + /** + * @brief Combines runtime configuration parameters into a single structure + * + * @return Runtime config instance + */ + runtime_config get_runtime_config() const; + std::string config_path{".clang-uml"}; std::optional compilation_database_dir{}; std::vector diagram_names{}; @@ -155,6 +175,7 @@ public: std::optional add_include_diagram; std::optional add_diagram_from_template; bool dump_config{false}; + bool print_start_from{false}; std::optional paths_relative_to_pwd{}; std::vector template_variables{}; bool list_templates{false}; diff --git a/src/common/generators/generators.cc b/src/common/generators/generators.cc index 197072d1..5ed85c21 100644 --- a/src/common/generators/generators.cc +++ b/src/common/generators/generators.cc @@ -83,8 +83,7 @@ void generate_diagram_impl(const std::string &od, const std::string &name, std::shared_ptr diagram, const common::compilation_database &db, const std::vector &translation_units, - const std::vector &generators, - bool verbose, std::function &&progress) + const cli::runtime_config &rc, std::function &&progress) { using diagram_config = DiagramConfig; using diagram_model = typename diagram_model_t::type; @@ -92,10 +91,22 @@ void generate_diagram_impl(const std::string &od, const std::string &name, auto model = clanguml::common::generators::generate(db, diagram->name, - dynamic_cast(*diagram), translation_units, verbose, + dynamic_cast(*diagram), translation_units, rc.verbose, std::move(progress)); - for (const auto generator_type : generators) { + if constexpr (std::is_same_v) { + if (rc.print_start_from) { + auto start_from_values = model->list_start_from_values(); + + for (const auto &start_from : start_from_values) { + std::cout << start_from << std::endl; + } + + return; + } + } + + for (const auto generator_type : rc.generators) { if (generator_type == generator_type_t::plantuml) { generate_diagram_select_generator(od, name, diagram, model); @@ -112,8 +123,7 @@ void generate_diagram(const std::string &od, const std::string &name, std::shared_ptr diagram, const common::compilation_database &db, const std::vector &translation_units, - const std::vector &generators, - bool verbose, std::function &&progress) + const cli::runtime_config &runtime_config, std::function &&progress) { using clanguml::common::generator_type_t; using clanguml::common::model::diagram_t; @@ -125,36 +135,35 @@ void generate_diagram(const std::string &od, const std::string &name, if (diagram->type() == diagram_t::kClass) { detail::generate_diagram_impl(od, name, diagram, db, - translation_units, generators, verbose, std::move(progress)); + translation_units, runtime_config, std::move(progress)); } else if (diagram->type() == diagram_t::kSequence) { detail::generate_diagram_impl(od, name, diagram, db, - translation_units, generators, verbose, std::move(progress)); + translation_units, runtime_config, std::move(progress)); } else if (diagram->type() == diagram_t::kPackage) { detail::generate_diagram_impl(od, name, diagram, db, - translation_units, generators, verbose, std::move(progress)); + translation_units, runtime_config, std::move(progress)); } else if (diagram->type() == diagram_t::kInclude) { detail::generate_diagram_impl(od, name, diagram, db, - translation_units, generators, verbose, std::move(progress)); + translation_units, runtime_config, std::move(progress)); } } void generate_diagrams(const std::vector &diagram_names, config::config &config, const std::string &od, - const common::compilation_database_ptr &db, const int verbose, - const unsigned int thread_count, bool progress, - const std::vector &generators, + const common::compilation_database_ptr &db, + const cli::runtime_config &runtime_config, const std::map> &translation_units_map) { - util::thread_pool_executor generator_executor{thread_count}; + util::thread_pool_executor generator_executor{runtime_config.thread_count}; std::vector> futs; std::unique_ptr indicator; - if (progress) { + if (runtime_config.progress) { std::cout << termcolor::white << "Processing translation units and generating diagrams:\n"; indicator = std::make_unique(); @@ -184,17 +193,17 @@ void generate_diagrams(const std::vector &diagram_names, continue; } - auto generator = [&od, &generators, &name = name, &diagram = diagram, - &indicator, db = std::ref(*db), + auto generator = [&od, &name = name, &diagram = diagram, &indicator, + db = std::ref(*db), translation_units = valid_translation_units, - verbose]() mutable { + runtime_config]() mutable { try { if (indicator) indicator->add_progress_bar(name, translation_units.size(), diagram_type_to_color(diagram->type())); generate_diagram(od, name, diagram, db, translation_units, - generators, verbose != 0, [&indicator, &name]() { + runtime_config, [&indicator, &name]() { if (indicator) indicator->increment(name); }); @@ -217,7 +226,7 @@ void generate_diagrams(const std::vector &diagram_names, fut.get(); } - if (progress) { + if (runtime_config.progress) { indicator->stop(); std::cout << termcolor::white << "Done\n"; std::cout << termcolor::reset; diff --git a/src/common/generators/generators.h b/src/common/generators/generators.h index 96d967ce..8f36e386 100644 --- a/src/common/generators/generators.h +++ b/src/common/generators/generators.h @@ -374,13 +374,14 @@ std::unique_ptr generate(const common::compilation_database &db, * @param translation_units List of translation units for the diagram * @param generators List of generator types to be used for the diagram * @param verbose Log level + * @param progress Function to report translation unit progress */ void generate_diagram(const std::string &od, const std::string &name, std::shared_ptr diagram, const common::compilation_database &db, const std::vector &translation_units, - const std::vector &generators, - bool verbose); + const cli::runtime_config &runtime_config, + std::function &&progress); /** * @brief Generate diagrams @@ -397,9 +398,8 @@ void generate_diagram(const std::string &od, const std::string &name, */ void generate_diagrams(const std::vector &diagram_names, clanguml::config::config &config, const std::string &od, - const common::compilation_database_ptr &db, int verbose, - unsigned int thread_count, bool progress, - const std::vector &generators, + const common::compilation_database_ptr &db, + const cli::runtime_config &runtime_config, const std::map> &translation_units_map); diff --git a/src/main.cc b/src/main.cc index b6c69d23..e87670e5 100644 --- a/src/main.cc +++ b/src/main.cc @@ -78,8 +78,8 @@ int main(int argc, const char *argv[]) translation_units_map); common::generators::generate_diagrams(cli.diagram_names, cli.config, - cli.effective_output_directory, db, cli.verbose, cli.thread_count, - cli.progress, cli.generators, translation_units_map); + cli.effective_output_directory, db, cli.get_runtime_config(), + translation_units_map); } catch (error::compilation_database_error &e) { LOG_ERROR("Failed to load compilation database from {} due to: {}", diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 37562f94..6cc032c3 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -179,15 +179,15 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, else if (m.type() == message_t::kIf) { print_debug(m, ostr); ostr << "alt"; - if (m.condition_text()) - ostr << " " << m.condition_text().value(); + if (const auto &text = m.condition_text(); text.has_value()) + ostr << " " << text.value(); ostr << '\n'; } else if (m.type() == message_t::kElseIf) { print_debug(m, ostr); ostr << "else"; - if (m.condition_text()) - ostr << " " << m.condition_text().value(); + if (const auto &text = m.condition_text(); text.has_value()) + ostr << " " << text.value(); ostr << '\n'; } else if (m.type() == message_t::kElse) { @@ -200,8 +200,8 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, else if (m.type() == message_t::kWhile) { print_debug(m, ostr); ostr << "loop"; - if (m.condition_text()) - ostr << " " << m.condition_text().value(); + if (const auto &text = m.condition_text(); text.has_value()) + ostr << " " << text.value(); ostr << '\n'; } else if (m.type() == message_t::kWhileEnd) { @@ -210,8 +210,8 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, else if (m.type() == message_t::kFor) { print_debug(m, ostr); ostr << "loop"; - if (m.condition_text()) - ostr << " " << m.condition_text().value(); + if (const auto &text = m.condition_text(); text.has_value()) + ostr << " " << text.value(); ostr << '\n'; } else if (m.type() == message_t::kForEnd) { @@ -220,8 +220,8 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, else if (m.type() == message_t::kDo) { print_debug(m, ostr); ostr << "loop"; - if (m.condition_text()) - ostr << " " << m.condition_text().value(); + if (const auto &text = m.condition_text(); text.has_value()) + ostr << " " << text.value(); ostr << '\n'; } else if (m.type() == message_t::kDoEnd) { @@ -253,8 +253,8 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, else if (m.type() == message_t::kConditional) { print_debug(m, ostr); ostr << "alt"; - if (m.condition_text()) - ostr << " " << m.condition_text().value(); + if (const auto &text = m.condition_text(); text.has_value()) + ostr << " " << text.value(); ostr << '\n'; } else if (m.type() == message_t::kConditionalElse) { diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index 365adda7..ee74b694 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -181,6 +181,22 @@ bool diagram::should_include( dynamic_cast(p)); } +std::vector diagram::list_start_from_values() const +{ + std::vector result; + + for (const auto &[from_id, act] : sequences_) { + + const auto &from_activity = *(participants_.at(from_id)); + + result.push_back(from_activity.full_name(false)); + } + + std::sort(result.begin(), result.end()); + + return result; +} + void diagram::print() const { LOG_TRACE(" --- Participants ---"); diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index d5bf0f20..17db4ae5 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -212,6 +212,13 @@ public: */ bool should_include(const sequence_diagram::model::participant &p) const; + /** + * @brief Get list of all possible 'start_from' values in the model + * + * @return List of all possible 'start_from' values + */ + std::vector list_start_from_values() const; + /** * @brief Once the diagram is complete, run any final processing. *