diff --git a/docs/configuration_file.md b/docs/configuration_file.md index 9d216993..13b99677 100644 --- a/docs/configuration_file.md +++ b/docs/configuration_file.md @@ -50,8 +50,15 @@ The following, are the `clang-uml` additional template functions: * `split(string)` - splits a string and returns a list of strings * `replace(string, regex, replacement)` - returns a string with replace matches to regex with replacement string * `abbrv(string, length)` - returns a string truncated to length including trailing ellipsis +* `element(string)` - returns the entire JSON context a given diagram element, including the following properties: + * `name` - name of the element + * `type` - type of diagram element (e.g. `class`, `enum`, `package`) + * `namespace` - fully qualified element namespace + * `full_name` - fully qualified element name + * `comment` [optional] - elements comment, if any + * `alias` - internal diagram element alias (e.g. PlantUML alias) * `alias(string)` - returns a PlantUML alias of an C++ entity represented by string name - +* `comment(string)` - returns a comment of an C++ entity represented by string name ## Example complete config diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 366f44c1..34c6eaae 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -386,22 +386,28 @@ template void generator::init_env() // // Add basic string functions to inja environment // + + // Check if string is empty m_env.add_callback("empty", 1, [](inja::Arguments &args) { return args.at(0)->get().empty(); }); + // Remove spaces from the left of a string m_env.add_callback("ltrim", 1, [](inja::Arguments &args) { return util::ltrim(args.at(0)->get()); }); + // Remove trailing spaces from a string m_env.add_callback("rtrim", 1, [](inja::Arguments &args) { return util::rtrim(args.at(0)->get()); }); + // Remove spaces before and after a string m_env.add_callback("trim", 1, [](inja::Arguments &args) { return util::trim(args.at(0)->get()); }); + // Make a string shorted with a limit to m_env.add_callback("abbrv", 2, [](inja::Arguments &args) { return util::abbreviate( args.at(0)->get(), args.at(1)->get()); @@ -422,28 +428,38 @@ template void generator::init_env() // Add PlantUML specific functions // + // Return the entire element JSON context based on element name + // e.g.: + // {{ element("clanguml::t00050::A").comment }} + // + m_env.add_callback("element", 1, [this](inja::Arguments &args) { + auto element_opt = m_model.get_with_namespace( + args[0]->get(), m_config.using_namespace()); + + return element_opt.value().context(); + }); + // Convert C++ entity to PlantUML alias, e.g. - // "note left of {{ alias("ClassA") }}: This is a note" - // is equivalent to the old syntax: - // "note left of @A(ClassA): This is a note" + // "note left of {{ alias("A") }}: This is a note" + // Shortcut to: + // {{ element("A").alias }} + // m_env.add_callback("alias", 1, [this](inja::Arguments &args) { - auto alias_match = - m_config.using_namespace() | args[0]->get(); - auto element_opt = m_model.get(alias_match.to_string()); + auto element_opt = m_model.get_with_namespace( + args[0]->get(), m_config.using_namespace()); return element_opt.value().alias(); }); + // Get elements' comment: + // "note left of {{ alias("A") }}: {{ comment("A") }}" + // Shortcut to: + // {{ element("A").comment }} + // m_env.add_callback("comment", 1, [this](inja::Arguments &args) { std::string res{}; - auto full_name = args[0]->get(); - auto element = m_model.get(full_name); - - if (!element.has_value()) { - // Try with current using namespace prepended - element = m_model.get(fmt::format( - "{}::{}", m_config.using_namespace().to_string(), full_name)); - } + auto element = m_model.get_with_namespace( + args[0]->get(), m_config.using_namespace()); if (element.has_value()) { auto comment = element.value().comment(); diff --git a/src/common/model/diagram.cc b/src/common/model/diagram.cc index 4f29e739..788cc444 100644 --- a/src/common/model/diagram.cc +++ b/src/common/model/diagram.cc @@ -31,6 +31,21 @@ diagram::diagram(diagram &&) = default; diagram &diagram::operator=(diagram &&) = default; +common::optional_ref +diagram::get_with_namespace(const std::string &name, const namespace_ &ns) const +{ + auto element_opt = get(name); + + if (!element_opt) { + // If no element matches, try to prepend the 'using_namespace' + // value to the element and search again + auto fully_qualified_name = ns | name; + element_opt = get(fully_qualified_name.to_string()); + } + + return element_opt; +} + std::string diagram::name() const { return name_; } void diagram::set_name(const std::string &name) { name_ = name; } diff --git a/src/common/model/diagram.h b/src/common/model/diagram.h index 0bca1643..1c2cbe80 100644 --- a/src/common/model/diagram.h +++ b/src/common/model/diagram.h @@ -45,6 +45,11 @@ public: virtual common::optional_ref get( const diagram_element::id_t id) const = 0; + /// \brief Find element in diagram which can have full name or be + /// relative to ns + common::optional_ref + get_with_namespace(const std::string &name, const namespace_ &ns) const; + diagram(const diagram &) = delete; diagram(diagram &&); diagram &operator=(const diagram &) = delete; diff --git a/tests/t00050/.clang-uml b/tests/t00050/.clang-uml index 62ef82ce..43084a27 100644 --- a/tests/t00050/.clang-uml +++ b/tests/t00050/.clang-uml @@ -13,9 +13,14 @@ diagrams: after: - > note left of {{ alias("A") }} - {{ comment("A") }} + {{ comment("clanguml::t00050::A") }} end note + - > + note right of {{ element("clanguml::t00050::A").alias }} + {{ element("A").comment }} + end note + - > {% for element in diagram.elements %} {% if element.type == "class" and existsIn(element, "comment") %} diff --git a/tests/t00050/test_case.h b/tests/t00050/test_case.h index 0ae81f49..07c8ad30 100644 --- a/tests/t00050/test_case.h +++ b/tests/t00050/test_case.h @@ -43,6 +43,7 @@ TEST_CASE("t00050", "[test-case][class]") REQUIRE_THAT(puml, HasNote(_A("A"), "left")); REQUIRE_THAT(puml, HasNote(_A("A"), "top")); + REQUIRE_THAT(puml, HasNote(_A("A"), "right")); REQUIRE_THAT(puml, HasNote(_A("B"), "top")); REQUIRE_THAT(puml, HasNote(_A("C"), "top")); REQUIRE_THAT(puml, HasNote(_A("utils::D"), "top"));