Added comment support to inja templates in links and tooltips

This commit is contained in:
Bartek Kryza
2022-03-23 21:59:02 +01:00
parent 8c0486240f
commit eed9fcaf66
7 changed files with 145 additions and 22 deletions

View File

@@ -35,16 +35,18 @@ void generator::generate_link(
if (e.file().empty()) if (e.file().empty())
return; return;
auto context = element_context(e);
if (!m_config.generate_links().link.empty()) { if (!m_config.generate_links().link.empty()) {
ostr << " [[["; ostr << " [[[";
inja::render_to( ostr << env().render(
ostr, m_config.generate_links().link, element_context(e)); std::string_view{m_config.generate_links().link}, context);
} }
if (!m_config.generate_links().tooltip.empty()) { if (!m_config.generate_links().tooltip.empty()) {
ostr << "{"; ostr << "{";
inja::render_to( ostr << env().render(
ostr, m_config.generate_links().tooltip, element_context(e)); std::string_view{m_config.generate_links().tooltip}, context);
ostr << "}"; ostr << "}";
} }
ostr << "]]]"; ostr << "]]]";

View File

@@ -248,6 +248,9 @@ void translation_unit_visitor::process_namespace(
p->set_name(e.name()); p->set_name(e.name());
p->set_namespace(package_parent); p->set_namespace(package_parent);
if (e.comment().has_value())
p->set_comment(e.comment().value());
if (e.location().has_value()) { if (e.location().has_value()) {
p->set_file(e.location().value().file); p->set_file(e.location().value().file);
p->set_line(e.location().value().line); p->set_line(e.location().value().line);
@@ -290,6 +293,9 @@ void translation_unit_visitor::process_enum_declaration(
e.set_name(enm.name()); e.set_name(enm.name());
e.set_namespace(ctx.get_namespace()); e.set_namespace(ctx.get_namespace());
if (enm.comment().has_value())
e.set_comment(enm.comment().value());
if (enm.location().has_value()) { if (enm.location().has_value()) {
e.set_file(enm.location().value().file); e.set_file(enm.location().value().file);
e.set_line(enm.location().value().line); e.set_line(enm.location().value().line);
@@ -347,8 +353,10 @@ void translation_unit_visitor::process_class_declaration(
c.set_name(cls.name()); c.set_name(cls.name());
c.set_namespace(ctx.get_namespace()); c.set_namespace(ctx.get_namespace());
if (cls.comment().has_value()) if (cls.comment().has_value()) {
c.set_comment(cls.comment().value());
c.add_decorators(decorators::parse(cls.comment().value())); c.add_decorators(decorators::parse(cls.comment().value()));
}
// Process class documentation comment // Process class documentation comment
if (cppast::is_templated(cls)) { if (cppast::is_templated(cls)) {
@@ -879,6 +887,9 @@ void translation_unit_visitor::process_method(
m.is_defaulted(false); m.is_defaulted(false);
m.is_static(false); m.is_static(false);
if (mf.comment().has_value())
m.set_comment(mf.comment().value());
if (mf.location().has_value()) { if (mf.location().has_value()) {
m.set_file(mf.location().value().file); m.set_file(mf.location().value().file);
m.set_line(mf.location().value().line); m.set_line(mf.location().value().line);
@@ -920,6 +931,9 @@ void translation_unit_visitor::process_template_method(
m.is_defaulted(false); m.is_defaulted(false);
m.is_static(false); m.is_static(false);
if (mf.comment().has_value())
m.set_comment(mf.comment().value());
if (mf.location().has_value()) { if (mf.location().has_value()) {
m.set_file(mf.location().value().file); m.set_file(mf.location().value().file);
m.set_line(mf.location().value().line); m.set_line(mf.location().value().line);
@@ -956,6 +970,9 @@ void translation_unit_visitor::process_static_method(
m.is_defaulted(false); m.is_defaulted(false);
m.is_static(true); m.is_static(true);
if (mf.comment().has_value())
m.set_comment(mf.comment().value());
if (mf.location().has_value()) { if (mf.location().has_value()) {
m.set_file(mf.location().value().file); m.set_file(mf.location().value().file);
m.set_line(mf.location().value().line); m.set_line(mf.location().value().line);
@@ -987,6 +1004,9 @@ void translation_unit_visitor::process_constructor(
m.is_defaulted(false); m.is_defaulted(false);
m.is_static(true); m.is_static(true);
if (mf.comment().has_value())
m.set_comment(mf.comment().value());
if (mf.location().has_value()) { if (mf.location().has_value()) {
m.set_file(mf.location().value().file); m.set_file(mf.location().value().file);
m.set_line(mf.location().value().line); m.set_line(mf.location().value().line);
@@ -1016,6 +1036,9 @@ void translation_unit_visitor::process_destructor(
m.is_defaulted(false); m.is_defaulted(false);
m.is_static(true); m.is_static(true);
if (mf.comment().has_value())
m.set_comment(mf.comment().value());
if (mf.location().has_value()) { if (mf.location().has_value()) {
m.set_file(mf.location().value().file); m.set_file(mf.location().value().file);
m.set_line(mf.location().value().line); m.set_line(mf.location().value().line);

View File

@@ -45,6 +45,7 @@ public:
, m_model{model} , m_model{model}
{ {
init_context(); init_context();
init_env();
} }
virtual ~generator() = default; virtual ~generator() = default;
@@ -64,17 +65,23 @@ public:
void generate_link(std::ostream &ostr, const model::element &e) const; void generate_link(std::ostream &ostr, const model::element &e) const;
protected:
const inja::json &context() const; const inja::json &context() const;
inja::Environment &env() const;
template <typename E> inja::json element_context(const E &e) const; template <typename E> inja::json element_context(const E &e) const;
private: private:
void init_context(); void init_context();
void init_env();
protected: protected:
ConfigType &m_config; ConfigType &m_config;
DiagramType &m_model; DiagramType &m_model;
inja::json m_context; inja::json m_context;
mutable inja::Environment m_env;
}; };
template <typename C, typename D> template <typename C, typename D>
@@ -90,17 +97,10 @@ const inja::json &generator<C, D>::context() const
return m_context; return m_context;
} }
template <typename C, typename D> void generator<C, D>::init_context() template <typename C, typename D>
inja::Environment &generator<C, D>::env() const
{ {
if (m_config.git) { return m_env;
m_context["git"]["branch"] = m_config.git().branch;
m_context["git"]["revision"] = m_config.git().revision;
m_context["git"]["commit"] = m_config.git().commit;
m_context["git"]["toplevel"] = m_config.git().toplevel;
}
m_context["diagram"]["name"] = m_config.name;
m_context["diagram"]["type"] = to_string(m_config.type());
} }
template <typename C, typename D> template <typename C, typename D>
@@ -125,6 +125,13 @@ inja::json generator<C, D>::element_context(const E &e) const
ctx["element"]["source"]["line"] = e.line(); ctx["element"]["source"]["line"] = e.line();
} }
if (e.comment().has_value()) {
std::string c = e.comment().value();
if (!c.empty()) {
ctx["element"]["comment"] = util::trim(c);
}
}
return ctx; return ctx;
} }
@@ -197,16 +204,18 @@ void generator<C, D>::generate_link(
if (!m_config.generate_links().link.empty()) { if (!m_config.generate_links().link.empty()) {
ostr << " [["; ostr << " [[";
inja::render_to( ostr << env().render(std::string_view{m_config.generate_links().link},
ostr, m_config.generate_links().link, element_context(e)); element_context(e));
} }
if (!m_config.generate_links().tooltip.empty()) { if (!m_config.generate_links().tooltip.empty()) {
ostr << "{"; ostr << "{";
inja::render_to( ostr << env().render(
ostr, m_config.generate_links().tooltip, element_context(e)); std::string_view{m_config.generate_links().tooltip},
element_context(e));
ostr << "}"; ostr << "}";
} }
ostr << "]]"; ostr << "]]";
} }
@@ -244,4 +253,53 @@ DiagramModel generate(const cppast::libclang_compilation_database &db,
return std::move(d); return std::move(d);
} }
template <typename C, typename D> void generator<C, D>::init_context()
{
if (m_config.git) {
m_context["git"]["branch"] = m_config.git().branch;
m_context["git"]["revision"] = m_config.git().revision;
m_context["git"]["commit"] = m_config.git().commit;
m_context["git"]["toplevel"] = m_config.git().toplevel;
}
m_context["diagram"]["name"] = m_config.name;
m_context["diagram"]["type"] = to_string(m_config.type());
}
template <typename C, typename D> void generator<C, D>::init_env()
{
// Add basic string functions to inja environment
m_env.add_callback("empty", 1, [](inja::Arguments &args) {
return args.at(0)->get<std::string>().empty();
});
m_env.add_callback("ltrim", 1, [](inja::Arguments &args) {
return util::ltrim(args.at(0)->get<std::string>());
});
m_env.add_callback("rtrim", 1, [](inja::Arguments &args) {
return util::rtrim(args.at(0)->get<std::string>());
});
m_env.add_callback("trim", 1, [](inja::Arguments &args) {
return util::trim(args.at(0)->get<std::string>());
});
m_env.add_callback("abbrv", 2, [](inja::Arguments &args) {
return util::abbreviate(
args.at(0)->get<std::string>(), args.at(1)->get<unsigned>());
});
m_env.add_callback("replace", 3, [](inja::Arguments &args) {
std::string result = args[0]->get<std::string>();
std::regex pattern(args[1]->get<std::string>());
return std::regex_replace(result, pattern, args[2]->get<std::string>());
});
m_env.add_callback("split", 2, [](inja::Arguments &args) {
return util::split(
args[0]->get<std::string>(), args[1]->get<std::string>());
});
}
} }

View File

@@ -87,4 +87,11 @@ void decorated_element::append(const decorated_element &de)
decorators_.push_back(d); decorators_.push_back(d);
} }
} }
std::optional<std::string> decorated_element::comment() const
{
return comment_;
}
void decorated_element::set_comment(const std::string &c) { comment_ = c; }
} }

View File

@@ -22,6 +22,7 @@
#include "decorators/decorators.h" #include "decorators/decorators.h"
#include <memory> #include <memory>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -45,8 +46,13 @@ public:
void append(const decorated_element &de); void append(const decorated_element &de);
std::optional<std::string> comment() const;
void set_comment(const std::string &c);
private: private:
std::vector<std::shared_ptr<decorators::decorator>> decorators_; std::vector<std::shared_ptr<decorators::decorator>> decorators_;
std::optional<std::string> comment_;
}; };
} }

View File

@@ -3,30 +3,50 @@
namespace clanguml { namespace clanguml {
namespace t00002 { namespace t00002 {
/// This is class A
class A { class A {
public: public:
/// Abstract foo_a
virtual void foo_a() = 0; virtual void foo_a() = 0;
/// Abstract foo_c
virtual void foo_c() = 0; virtual void foo_c() = 0;
}; };
/// This is class B
class B : public A { class B : public A {
public: public:
virtual void foo_a() override { } virtual void foo_a() override { }
}; };
/// @brief This is class C - class C has a long comment
///
/// Vivamus integer non suscipit taciti mus etiam at primis tempor sagittis sit,
/// euismod libero facilisi aptent elementum felis blandit cursus gravida sociis
/// erat ante, eleifend lectus nullam dapibus netus feugiat curae curabitur est
/// ad.
class C : public A { class C : public A {
public: public:
/// Do nothing unless override is provided
virtual void foo_c() override { } virtual void foo_c() override { }
}; };
/// This is class D
/// which is a little like B
/// and a little like C
class D : public B, public C { class D : public B, public C {
public: public:
/**
* Forward foo_a
*/
void foo_a() override void foo_a() override
{ {
for (auto a : as) for (auto a : as)
a->foo_a(); a->foo_a();
} }
/**
* Forward foo_c
*/
void foo_c() override void foo_c() override
{ {
for (auto a : as) for (auto a : as)
@@ -34,6 +54,7 @@ public:
} }
private: private:
/// All the A pointers
std::vector<A *> as; std::vector<A *> as;
}; };
@@ -44,12 +65,18 @@ private:
// //
class E : virtual public B, virtual public C { class E : virtual public B, virtual public C {
public: public:
///
/// Forward foo_a
///
void foo_a() override void foo_a() override
{ {
for (auto a : as) for (auto a : as)
a->foo_a(); a->foo_a();
} }
///
/// Forward foo_c
///
void foo_c() override void foo_c() override
{ {
for (auto a : as) for (auto a : as)
@@ -57,6 +84,7 @@ public:
} }
private: private:
/// All the A pointers
std::vector<A *> as; std::vector<A *> as;
}; };
} }

View File

@@ -24,9 +24,8 @@ void inject_diagram_options(std::shared_ptr<clanguml::config::diagram> diagram)
{ {
// Inject links config to all test cases // Inject links config to all test cases
clanguml::config::generate_links_config links_config{ clanguml::config::generate_links_config links_config{
"https://github.com/bkryza/clang-uml/blob/{{ git.commit }}/{{ " R"(https://github.com/bkryza/clang-uml/blob/{{ git.commit }}/{{ element.source.path }}#L{{ element.source.line }})",
"element.source.path }}#L{{ element.source.line }}", R"({% if "comment" in element %}{{ abbrv(trim(replace(element.comment, "\n+", " ")), 256) }}{% else %}{{ element.name }}{% endif %})"};
"{{ element.name }}"};
diagram->generate_links.set(links_config); diagram->generate_links.set(links_config);
} }