Added PlantUML links generation in class diagrams

This commit is contained in:
Bartek Kryza
2022-03-20 22:57:17 +01:00
parent 3c30350edc
commit d7e27841bc
15 changed files with 351 additions and 14 deletions

View File

@@ -23,11 +23,13 @@
#include <cppast/libclang_parser.hpp>
#include <glob/glob.hpp>
#include <inja/inja.hpp>
#include <ostream>
namespace clanguml::common::generators::plantuml {
using clanguml::common::model::element;
using clanguml::common::model::message_t;
using clanguml::common::model::relationship_t;
using clanguml::common::model::scope_t;
@@ -42,6 +44,7 @@ public:
: m_config{config}
, m_model{model}
{
init_context();
}
virtual ~generator() = default;
@@ -57,11 +60,21 @@ public:
std::ostream &ostr, const std::vector<std::string> &directives) const;
void generate_notes(
std::ostream &ostr, const model::element &decorators) const;
std::ostream &ostr, const model::element &element) const;
void generate_link(std::ostream &ostr, const model::element &e) const;
const inja::json &context() const;
template <typename E> inja::json element_context(const E &e) const;
private:
void init_context();
protected:
ConfigType &m_config;
DiagramType &m_model;
inja::json m_context;
};
template <typename C, typename D>
@@ -71,6 +84,50 @@ std::ostream &operator<<(std::ostream &os, const generator<C, D> &g)
return os;
}
template <typename C, typename D>
const inja::json &generator<C, D>::context() const
{
return m_context;
}
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>
template <typename E>
inja::json generator<C, D>::element_context(const E &e) const
{
auto ctx = context();
ctx["element"] = e.context();
if (!e.file().empty()) {
std::filesystem::path file{e.file()};
std::string relative_path = std::filesystem::relative(file);
if (ctx.template contains("git"))
relative_path =
std::filesystem::relative(file, ctx["git"]["toplevel"]);
ctx["element"]["source"]["path"] = relative_path;
ctx["element"]["source"]["full_path"] = file.string();
ctx["element"]["source"]["name"] = file.filename();
ctx["element"]["source"]["line"] = e.line();
}
return ctx;
}
template <typename C, typename D>
void generator<C, D>::generate_config_layout_hints(std::ostream &ostr) const
{
@@ -131,6 +188,28 @@ void generator<C, D>::generate_notes(
}
}
template <typename C, typename D>
void generator<C, D>::generate_link(
std::ostream &ostr, const model::element &e) const
{
if (e.file().empty())
return;
if (!m_config.generate_links().link.empty()) {
ostr << " [[";
inja::render_to(
ostr, m_config.generate_links().link, element_context(e));
}
if (!m_config.generate_links().tooltip.empty()) {
ostr << "{";
inja::render_to(
ostr, m_config.generate_links().tooltip, element_context(e));
ostr << "}";
}
ostr << "]]";
}
template <typename DiagramModel, typename DiagramConfig,
typename DiagramVisitor>
DiagramModel generate(const cppast::libclang_compilation_database &db,

View File

@@ -73,6 +73,15 @@ const std::vector<relationship> &element::relationships() const
void element::append(const element &e) { decorated_element::append(e); }
inja::json element::context() const {
inja::json ctx;
ctx["name"] = name();
ctx["alias"] = alias();
ctx["full_name"] = full_name(false);
ctx["namespace"] = get_namespace().to_string();
return ctx;
}
bool operator==(const element &l, const element &r)
{
return l.full_name(false) == r.full_name(false);

View File

@@ -20,8 +20,11 @@
#include "decorated_element.h"
#include "namespace.h"
#include "relationship.h"
#include "source_location.h"
#include "util/util.h"
#include <inja/inja.hpp>
#include <atomic>
#include <exception>
#include <string>
@@ -29,7 +32,7 @@
namespace clanguml::common::model {
class element : public decorated_element {
class element : public decorated_element, public source_location {
public:
element(const namespace_ &using_namespace);
@@ -74,6 +77,8 @@ public:
friend std::ostream &operator<<(std::ostream &out, const element &rhs);
virtual inja::json context() const;
protected:
const uint64_t m_id{0};
@@ -82,6 +87,7 @@ private:
namespace_ ns_;
namespace_ using_namespace_;
std::vector<relationship> relationships_;
type_safe::optional<source_location> location_;
static std::atomic_uint64_t m_nextId;
};

View File

@@ -0,0 +1,19 @@
/**
* src/common/model/source_location.cc
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "source_location.h"

View File

@@ -0,0 +1,46 @@
/**
* src/common/model/source_location.h
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <string>
namespace clanguml::common::model {
class source_location {
public:
source_location() = default;
source_location(const std::string &f, unsigned int l)
: file_{f}
, line_{l}
{
}
const std::string &file() const { return file_; }
void set_file(const std::string &file) { file_ = file; }
unsigned int line() const { return line_; }
void set_line(const unsigned line) { line_ = line; }
private:
std::string file_;
unsigned int line_{0};
};
}