Start adding markdown conversion to site generator.
This commit is contained in:
parent
f0091f9e04
commit
f44c79dc1f
31 changed files with 692 additions and 461 deletions
|
@ -2,19 +2,24 @@
|
||||||
list(APPEND website_generator_LIB_INCLUDES
|
list(APPEND website_generator_LIB_INCLUDES
|
||||||
ContentFile.h
|
ContentFile.h
|
||||||
ContentFile.cpp
|
ContentFile.cpp
|
||||||
|
ContentPage.h
|
||||||
|
ContentPage.cpp
|
||||||
MarkdownContentParser.h
|
MarkdownContentParser.h
|
||||||
MarkdownContentParser.cpp
|
MarkdownContentParser.cpp
|
||||||
|
SiteGeneratorConfig.h
|
||||||
|
SiteGeneratorConfig.cpp
|
||||||
WebsiteGenerator.h
|
WebsiteGenerator.h
|
||||||
WebsiteGenerator.cpp)
|
WebsiteGenerator.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
add_executable(website_generator main.cpp ${website_generator_LIB_INCLUDES})
|
add_executable(website_generator main.cpp ${website_generator_LIB_INCLUDES})
|
||||||
|
|
||||||
target_include_directories(website_generator PUBLIC
|
target_include_directories(website_generator PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(website_generator PUBLIC core web)
|
target_link_libraries(website_generator PUBLIC core web compiler)
|
||||||
|
|
||||||
set_property(TARGET website_generator PROPERTY FOLDER apps/website-generator)
|
set_property(TARGET website_generator PROPERTY FOLDER apps/website-generator)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#include "ContentFile.h"
|
||||||
|
|
||||||
|
#include "PathUtils.h"
|
||||||
|
#include "MarkdownDocument.h"
|
||||||
|
#include "MarkdownElement.h"
|
||||||
|
|
||||||
|
ContentFile::ContentFile(const Path& filename)
|
||||||
|
: mFilename(filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentFile::~ContentFile()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Path ContentFile::getFilename() const
|
||||||
|
{
|
||||||
|
return mFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ContentFile::getOutputLocation() const
|
||||||
|
{
|
||||||
|
const auto metadata_item = getMetadataItem("save_as");
|
||||||
|
return metadata_item.empty() ? PathUtils::getBaseFilename(mFilename) : metadata_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentFile::load()
|
||||||
|
{
|
||||||
|
MarkdownContentParser parser;
|
||||||
|
auto result = parser.run(mFilename);
|
||||||
|
|
||||||
|
mMetadata = result.first;
|
||||||
|
mContentBody = std::move(result.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ContentFile::getMetadataItem(const std::string& key) const
|
||||||
|
{
|
||||||
|
const auto check = mMetadata.find(key);
|
||||||
|
if (check == mMetadata.end())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return check->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentFile::write(const Path& path)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -7,73 +7,37 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class MarkdownDocument;
|
||||||
|
|
||||||
class ContentFile
|
class ContentFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using FileMetadata = std::unordered_map<std::string, std::string>;
|
using FileMetadata = std::unordered_map<std::string, std::string>;
|
||||||
using FileContentBody = std::vector<std::string>;
|
using FileContentBody = std::vector<std::string>;
|
||||||
|
|
||||||
ContentFile(const Path& filename)
|
ContentFile(const Path& filename);
|
||||||
: mFilename(filename)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
virtual ~ContentFile();
|
||||||
|
|
||||||
|
Path getFilename() const;
|
||||||
|
|
||||||
|
virtual void load();
|
||||||
|
|
||||||
|
std::string getMetadataItem(const std::string& key) const;
|
||||||
|
|
||||||
|
virtual std::string getOutputLocation() const;
|
||||||
|
|
||||||
|
MarkdownDocument* getContentBody() const
|
||||||
|
{
|
||||||
|
return mContentBody.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ContentFile() = default;
|
void write(const Path& path);
|
||||||
|
|
||||||
Path getFilename() const
|
|
||||||
{
|
|
||||||
return mFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void load()
|
|
||||||
{
|
|
||||||
MarkdownContentParser parser;
|
|
||||||
parser.run(mFilename);
|
|
||||||
|
|
||||||
mMetadata = parser.getFileMetadata();
|
|
||||||
mContentBody = parser.getContentBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getMetadataItem(const std::string& key) const
|
|
||||||
{
|
|
||||||
const auto check = mMetadata.find(key);
|
|
||||||
if (check == mMetadata.end())
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return check->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Path mFilename;
|
Path mFilename;
|
||||||
FileMetadata mMetadata;
|
FileMetadata mMetadata;
|
||||||
FileContentBody mContentBody;
|
std::unique_ptr<MarkdownDocument> mContentBody;
|
||||||
};
|
std::string mProcessedOutput;
|
||||||
|
|
||||||
class ContentPage : public ContentFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
ContentPage(const Path& filename)
|
|
||||||
: ContentFile(filename)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void load() override
|
|
||||||
{
|
|
||||||
ContentFile::load();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getOutputLocation() const
|
|
||||||
{
|
|
||||||
const auto metadata_item = getMetadataItem("save_as");
|
|
||||||
return metadata_item.empty() ? File::getBaseFilename(mFilename) : metadata_item;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContentArticle : public ContentFile
|
class ContentArticle : public ContentFile
|
||||||
|
|
14
apps/website-generator/ContentPage.cpp
Normal file
14
apps/website-generator/ContentPage.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "ContentPage.h"
|
||||||
|
|
||||||
|
ContentPage::ContentPage(const Path& filename)
|
||||||
|
: ContentFile(filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentPage::load()
|
||||||
|
{
|
||||||
|
ContentFile::load();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
11
apps/website-generator/ContentPage.h
Normal file
11
apps/website-generator/ContentPage.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ContentFile.h"
|
||||||
|
|
||||||
|
class ContentPage : public ContentFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContentPage(const Path& filename);
|
||||||
|
|
||||||
|
void load() override;
|
||||||
|
};
|
|
@ -1,11 +1,20 @@
|
||||||
#include "MarkdownContentParser.h"
|
#include "MarkdownContentParser.h"
|
||||||
|
|
||||||
void MarkdownContentParser::run(const Path& path)
|
#include "MarkdownParser.h"
|
||||||
|
#include "MarkdownDocument.h"
|
||||||
|
#include "MarkdownElement.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
std::pair<MarkdownContentParser::FileMetadata, std::unique_ptr<MarkdownDocument>> MarkdownContentParser::run(const Path& path)
|
||||||
{
|
{
|
||||||
FileMetadata metadata;
|
FileMetadata metadata;
|
||||||
|
FileMetadata output_metadata;
|
||||||
|
|
||||||
const auto lines = File(path).readLines();
|
const auto lines = File(path).readLines();
|
||||||
bool metadata_finished = false;
|
bool metadata_finished = false;
|
||||||
|
|
||||||
|
std::string content_body;
|
||||||
for (const auto& line : lines)
|
for (const auto& line : lines)
|
||||||
{
|
{
|
||||||
if (!metadata_finished)
|
if (!metadata_finished)
|
||||||
|
@ -14,28 +23,23 @@ void MarkdownContentParser::run(const Path& path)
|
||||||
if (!metadata)
|
if (!metadata)
|
||||||
{
|
{
|
||||||
metadata_finished = true;
|
metadata_finished = true;
|
||||||
mContentBody.push_back(line);
|
content_body += line + '\n';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mMetadata[metadata->first] = metadata->second;
|
output_metadata[metadata->first] = metadata->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mContentBody.push_back(line);
|
content_body += line + '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MarkdownContentParser::FileContentBody MarkdownContentParser::getContentBody() const
|
MarkdownParser md_parser;
|
||||||
{
|
auto content = md_parser.run(content_body);
|
||||||
return mContentBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkdownContentParser::FileMetadata MarkdownContentParser::getFileMetadata() const
|
return {output_metadata, std::move(content)};
|
||||||
{
|
|
||||||
return mMetadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<MarkdownContentParser::FileMetadataItem> MarkdownContentParser::checkForMetadataItem(const std::string& line) const
|
std::optional<MarkdownContentParser::FileMetadataItem> MarkdownContentParser::checkForMetadataItem(const std::string& line) const
|
||||||
|
@ -69,4 +73,4 @@ std::optional<MarkdownContentParser::FileMetadataItem> MarkdownContentParser::ch
|
||||||
{
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,22 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "File.h"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
|
class MarkdownDocument;
|
||||||
|
|
||||||
class MarkdownContentParser
|
class MarkdownContentParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using FileMetadataItem = std::pair<std::string, std::string>;
|
using FileMetadataItem = std::pair<std::string, std::string>;
|
||||||
using FileMetadata = std::unordered_map<std::string, std::string>;
|
using FileMetadata = std::unordered_map<std::string, std::string>;
|
||||||
using FileContentBody = std::vector<std::string>;
|
|
||||||
|
|
||||||
void run(const Path& path);
|
|
||||||
|
|
||||||
FileContentBody getContentBody() const;
|
|
||||||
|
|
||||||
FileMetadata getFileMetadata() const;
|
|
||||||
|
|
||||||
|
std::pair<FileMetadata, std::unique_ptr<MarkdownDocument>> run(const Path& path);
|
||||||
private:
|
private:
|
||||||
std::optional<FileMetadataItem> checkForMetadataItem(const std::string& line) const;
|
std::optional<FileMetadataItem> checkForMetadataItem(const std::string& line) const;
|
||||||
|
|
||||||
FileMetadata mMetadata;
|
|
||||||
FileContentBody mContentBody;
|
|
||||||
};
|
};
|
||||||
|
|
21
apps/website-generator/SiteGeneratorConfig.cpp
Normal file
21
apps/website-generator/SiteGeneratorConfig.cpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include "SiteGeneratorConfig.h"
|
||||||
|
|
||||||
|
Path SiteGeneratorConfig::getThemePath() const
|
||||||
|
{
|
||||||
|
return mThemesPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SiteGeneratorConfig::getActiveTheme() const
|
||||||
|
{
|
||||||
|
return mActiveTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SiteGeneratorConfig::setThemePath(const Path& path)
|
||||||
|
{
|
||||||
|
mThemesPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SiteGeneratorConfig::setActiveTheme(const std::string& theme)
|
||||||
|
{
|
||||||
|
mActiveTheme = theme;
|
||||||
|
}
|
22
apps/website-generator/SiteGeneratorConfig.h
Normal file
22
apps/website-generator/SiteGeneratorConfig.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
|
class SiteGeneratorConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Path getThemePath() const;
|
||||||
|
|
||||||
|
std::string getActiveTheme() const;
|
||||||
|
|
||||||
|
void setThemePath(const Path& path);
|
||||||
|
|
||||||
|
void setActiveTheme(const std::string& theme);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Path mThemesPath;
|
||||||
|
std::string mActiveTheme;
|
||||||
|
};
|
18
apps/website-generator/SiteTemplateFile.h
Normal file
18
apps/website-generator/SiteTemplateFile.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
|
class SiteTemplateFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SiteTemplateFile(const Path& path)
|
||||||
|
: mPath(path)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Path mPath;
|
||||||
|
};
|
|
@ -1,6 +1,27 @@
|
||||||
#include "WebsiteGenerator.h"
|
#include "WebsiteGenerator.h"
|
||||||
|
|
||||||
#include "TomlReader.h"
|
#include "TomlReader.h"
|
||||||
|
#include "Directory.h"
|
||||||
|
#include "ContentFile.h"
|
||||||
|
#include "ContentPage.h"
|
||||||
|
#include "TemplateFile.h"
|
||||||
|
#include "TemplatingEngine.h"
|
||||||
|
#include "SiteGeneratorConfig.h"
|
||||||
|
#include "PathUtils.h"
|
||||||
|
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
|
WebsiteGenerator::WebsiteGenerator()
|
||||||
|
: mConfig(std::make_unique<SiteGeneratorConfig>()),
|
||||||
|
mTemplateEngine()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
WebsiteGenerator::~WebsiteGenerator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void WebsiteGenerator::findProject(const std::string& searchPath)
|
void WebsiteGenerator::findProject(const std::string& searchPath)
|
||||||
{
|
{
|
||||||
|
@ -8,10 +29,42 @@ void WebsiteGenerator::findProject(const std::string& searchPath)
|
||||||
if (std::filesystem::exists(config_path))
|
if (std::filesystem::exists(config_path))
|
||||||
{
|
{
|
||||||
mProjectPath = searchPath;
|
mProjectPath = searchPath;
|
||||||
std::cout << "Found config.toml in " << searchPath << std::endl;
|
MLOG_INFO("Found project config in: " << mProjectPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebsiteGenerator::findContentFiles()
|
||||||
|
{
|
||||||
|
const bool is_recursive{true};
|
||||||
|
const auto pages_files = Directory::getFilesWithExtension(getPagesPath(), ".md", is_recursive);
|
||||||
|
for (const auto& path : pages_files)
|
||||||
|
{
|
||||||
|
mPages.push_back(std::make_unique<ContentPage>(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto article_files = Directory::getFilesWithExtension(getArticlesPath(), ".md", is_recursive);
|
||||||
|
for (const auto& path : article_files)
|
||||||
|
{
|
||||||
|
mArticles.push_back(std::make_unique<ContentArticle>(path));
|
||||||
|
}
|
||||||
|
MLOG_INFO("Found: " << mArticles.size() << " articles");
|
||||||
|
}
|
||||||
|
|
||||||
|
Path WebsiteGenerator::getContentPath() const
|
||||||
|
{
|
||||||
|
return mProjectPath / "content";
|
||||||
|
}
|
||||||
|
|
||||||
|
Path WebsiteGenerator::getPagesPath() const
|
||||||
|
{
|
||||||
|
return getContentPath() / "pages";
|
||||||
|
}
|
||||||
|
|
||||||
|
Path WebsiteGenerator::getArticlesPath() const
|
||||||
|
{
|
||||||
|
return getContentPath() / "articles";
|
||||||
|
}
|
||||||
|
|
||||||
Path WebsiteGenerator::getConfigPath() const
|
Path WebsiteGenerator::getConfigPath() const
|
||||||
{
|
{
|
||||||
return mProjectPath / "config.toml";
|
return mProjectPath / "config.toml";
|
||||||
|
@ -28,72 +81,54 @@ void WebsiteGenerator::readConfig()
|
||||||
auto location = items["location"];
|
auto location = items["location"];
|
||||||
auto active_theme = items["active_theme"];
|
auto active_theme = items["active_theme"];
|
||||||
|
|
||||||
mConfig.setThemePath(location);
|
mConfig->setThemePath(location);
|
||||||
mConfig.setActiveTheme(active_theme);
|
mConfig->setActiveTheme(active_theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebsiteGenerator::parseContentFiles()
|
void WebsiteGenerator::parseContentFiles()
|
||||||
{
|
{
|
||||||
findContentFiles();
|
findContentFiles();
|
||||||
|
|
||||||
for (auto& page : mPages)
|
for (auto& page : mPages)
|
||||||
{
|
{
|
||||||
page.load();
|
page->load();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& article : mArticles)
|
||||||
|
{
|
||||||
|
article->load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebsiteGenerator::parseTemplateFiles()
|
void WebsiteGenerator::parseTemplateFiles()
|
||||||
{
|
{
|
||||||
const auto template_path = mProjectPath / mConfig.getThemePath() / mConfig.getActiveTheme();
|
const auto template_path = mProjectPath / mConfig->getThemePath() / mConfig->getActiveTheme();
|
||||||
|
mTemplateEngine = std::make_unique<TemplatingEngine>(template_path);
|
||||||
const auto template_files = Directory::getFilesWithExtension(template_path, ".html");
|
mTemplateEngine->loadTemplateFiles();
|
||||||
for (const auto& path : template_files)
|
|
||||||
{
|
|
||||||
mTemplateFiles[path.stem().string()] = std::make_unique<TemplateFile>(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebsiteGenerator::doSubstitutions()
|
void WebsiteGenerator::doSubstitutions()
|
||||||
{
|
{
|
||||||
|
auto article_template = mTemplateEngine->processTemplate("article");
|
||||||
|
for (auto& article : mArticles)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebsiteGenerator::write()
|
void WebsiteGenerator::write()
|
||||||
{
|
{
|
||||||
// Setup output dir
|
// Setup output dir
|
||||||
const auto output_dir = mProjectPath / "output_custom";
|
const auto output_dir = mProjectPath / "output";
|
||||||
std::filesystem::create_directory(output_dir);
|
std::filesystem::create_directory(output_dir);
|
||||||
|
|
||||||
// Write each page
|
// Write each page
|
||||||
}
|
for (auto& article : mArticles)
|
||||||
|
|
||||||
void WebsiteGenerator::findContentFiles()
|
|
||||||
{
|
|
||||||
const auto pages_files = Directory::getFilesWithExtension(getPagesPath(), ".md");
|
|
||||||
for (const auto& path : pages_files)
|
|
||||||
{
|
{
|
||||||
mPages.push_back(ContentPage(path));
|
auto article_path = article->getFilename();
|
||||||
}
|
auto relative_path = PathUtils::getRelativePath(article_path, getArticlesPath());
|
||||||
|
auto updated_filename = PathUtils::getPathDelimited(relative_path);
|
||||||
const auto article_files = Directory::getFilesWithExtension(getArticlesPath(), ".md");
|
auto final_path = output_dir / Path(updated_filename).replace_extension(".html");
|
||||||
for (const auto& path : article_files)
|
|
||||||
{
|
|
||||||
mArticles.push_back(ContentArticle(path));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Path WebsiteGenerator::getContentPath() const
|
|
||||||
{
|
|
||||||
return mProjectPath / "content";
|
|
||||||
}
|
|
||||||
|
|
||||||
Path WebsiteGenerator::getPagesPath() const
|
|
||||||
{
|
|
||||||
return getContentPath() / "pages";
|
|
||||||
}
|
|
||||||
|
|
||||||
Path WebsiteGenerator::getArticlesPath() const
|
|
||||||
{
|
|
||||||
return getContentPath() / "articles";
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,72 +1,38 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Directory.h"
|
|
||||||
#include "ContentFile.h"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class GeneratorConfig
|
using Path = std::filesystem::path;
|
||||||
{
|
|
||||||
public:
|
|
||||||
void setThemePath(const Path& path)
|
|
||||||
{
|
|
||||||
mThemesPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setActiveTheme(const std::string& theme)
|
class SiteGeneratorConfig;
|
||||||
{
|
class ContentPage;
|
||||||
mActiveTheme = theme;
|
class ContentArticle;
|
||||||
}
|
class TemplatingEngine;
|
||||||
|
|
||||||
Path getThemePath() const
|
|
||||||
{
|
|
||||||
return mThemesPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getActiveTheme() const
|
|
||||||
{
|
|
||||||
return mActiveTheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Path mThemesPath;
|
|
||||||
std::string mActiveTheme;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TemplateFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TemplateFile(const Path& path)
|
|
||||||
: mPath(path)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Path mPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WebsiteGenerator
|
class WebsiteGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
WebsiteGenerator();
|
||||||
|
|
||||||
|
~WebsiteGenerator();
|
||||||
|
|
||||||
|
void doSubstitutions();
|
||||||
|
|
||||||
void findProject(const std::string& searchPath);
|
void findProject(const std::string& searchPath);
|
||||||
|
|
||||||
void readConfig();
|
|
||||||
|
|
||||||
void parseContentFiles();
|
void parseContentFiles();
|
||||||
|
|
||||||
void parseTemplateFiles();
|
void parseTemplateFiles();
|
||||||
|
|
||||||
void doSubstitutions();
|
void readConfig();
|
||||||
|
|
||||||
void write();
|
void write();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void findContentFiles();
|
void findContentFiles();
|
||||||
|
|
||||||
Path getContentPath() const;
|
Path getContentPath() const;
|
||||||
|
@ -78,8 +44,10 @@ private:
|
||||||
Path getConfigPath() const;
|
Path getConfigPath() const;
|
||||||
|
|
||||||
std::filesystem::path mProjectPath;
|
std::filesystem::path mProjectPath;
|
||||||
GeneratorConfig mConfig;
|
|
||||||
std::vector<ContentPage> mPages;
|
std::unique_ptr<SiteGeneratorConfig> mConfig;
|
||||||
std::vector<ContentArticle> mArticles;
|
std::unique_ptr<TemplatingEngine> mTemplateEngine;
|
||||||
std::unordered_map<std::string, std::unique_ptr<TemplateFile> > mTemplateFiles;
|
|
||||||
|
std::vector<std::unique_ptr<ContentPage> > mPages;
|
||||||
|
std::vector<std::unique_ptr<ContentArticle> > mArticles;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "WebsiteGenerator.h"
|
#include "WebsiteGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
auto args = CommandLineArgs::Create();
|
auto args = CommandLineArgs::Create();
|
||||||
|
@ -21,10 +20,10 @@ int main(int argc, char *argv[])
|
||||||
generator.parseTemplateFiles();
|
generator.parseTemplateFiles();
|
||||||
|
|
||||||
// Substitute template files
|
// Substitute template files
|
||||||
|
generator.doSubstitutions();
|
||||||
|
|
||||||
// Write output
|
// Write output
|
||||||
generator.write();
|
generator.write();
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "TemplatingEngine.h"
|
#include "TemplatingEngine.h"
|
||||||
|
|
||||||
#include "Directory.h"
|
#include "Directory.h"
|
||||||
|
#include "FileLogger.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -13,10 +14,11 @@ TemplatingEngine::TemplatingEngine(const Path& workingDirectory)
|
||||||
void TemplatingEngine::loadTemplateFiles()
|
void TemplatingEngine::loadTemplateFiles()
|
||||||
{
|
{
|
||||||
const auto files = Directory::getFilesWithExtension(mWorkingDirectory, mTemplateExtension);
|
const auto files = Directory::getFilesWithExtension(mWorkingDirectory, mTemplateExtension);
|
||||||
for (const auto& file : files)
|
for (const auto& path : files)
|
||||||
{
|
{
|
||||||
mTemplateFiles.push_back(std::make_unique<TemplateFile>(file));
|
mTemplateFiles[path.stem().string()] = std::make_unique<TemplateFile>(path);
|
||||||
}
|
}
|
||||||
|
MLOG_INFO("Found: " << mTemplateFiles.size() << " templates in " << mWorkingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TemplatingEngine::processTemplate(const std::string& name)
|
std::string TemplatingEngine::processTemplate(const std::string& name)
|
||||||
|
@ -35,15 +37,7 @@ TemplateFile* TemplatingEngine::getTemplateFile(const Path& path)
|
||||||
|
|
||||||
TemplateFile* TemplatingEngine::getTemplateFile(const std::string& name)
|
TemplateFile* TemplatingEngine::getTemplateFile(const std::string& name)
|
||||||
{
|
{
|
||||||
//std::cout << "Looking for template file with name: " << name << std::endl;
|
return mTemplateFiles[name].get();
|
||||||
for (const auto& file : mTemplateFiles)
|
|
||||||
{
|
|
||||||
if (file->getName() == name)
|
|
||||||
{
|
|
||||||
return file.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TemplatingEngine::processTemplate(TemplateFile* file, TemplateNode* parent)
|
std::string TemplatingEngine::processTemplate(TemplateFile* file, TemplateNode* parent)
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class TemplatingEngine
|
class TemplatingEngine
|
||||||
{
|
{
|
||||||
|
@ -14,7 +16,6 @@ public:
|
||||||
void loadTemplateFiles();
|
void loadTemplateFiles();
|
||||||
|
|
||||||
std::string processTemplate(const std::string& name);
|
std::string processTemplate(const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TemplateFile* getTemplateFile(const std::string& name);
|
TemplateFile* getTemplateFile(const std::string& name);
|
||||||
TemplateFile* getTemplateFile(const Path& path);
|
TemplateFile* getTemplateFile(const Path& path);
|
||||||
|
@ -22,7 +23,7 @@ private:
|
||||||
|
|
||||||
std::string processTemplate(TemplateFile* file, TemplateNode* parent = nullptr);
|
std::string processTemplate(TemplateFile* file, TemplateNode* parent = nullptr);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<TemplateFile> > mTemplateFiles;
|
std::unordered_map<std::string, std::unique_ptr<TemplateFile> > mTemplateFiles;
|
||||||
Path mWorkingDirectory;
|
Path mWorkingDirectory;
|
||||||
std::string mTemplateExtension{ ".html" };
|
std::string mTemplateExtension{ ".html" };
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
set(MODULE_NAME core)
|
||||||
|
|
||||||
list(APPEND core_HEADERS
|
list(APPEND core_HEADERS
|
||||||
AbstractApp.h
|
AbstractApp.h
|
||||||
Dictionary.h
|
Dictionary.h
|
||||||
|
@ -8,6 +10,7 @@ list(APPEND core_HEADERS
|
||||||
file_utilities/Directory.h
|
file_utilities/Directory.h
|
||||||
file_utilities/File.h
|
file_utilities/File.h
|
||||||
file_utilities/FileFormats.h
|
file_utilities/FileFormats.h
|
||||||
|
file_utilities/PathUtils.h
|
||||||
StringUtils.h
|
StringUtils.h
|
||||||
http/HttpResponse.h
|
http/HttpResponse.h
|
||||||
serializers/TomlReader.h
|
serializers/TomlReader.h
|
||||||
|
@ -25,6 +28,7 @@ list(APPEND core_LIB_INCLUDES
|
||||||
file_utilities/Directory.cpp
|
file_utilities/Directory.cpp
|
||||||
file_utilities/File.cpp
|
file_utilities/File.cpp
|
||||||
file_utilities/FileFormats.cpp
|
file_utilities/FileFormats.cpp
|
||||||
|
file_utilities/PathUtils.cpp
|
||||||
memory/SharedMemory.cpp
|
memory/SharedMemory.cpp
|
||||||
RandomUtils.cpp
|
RandomUtils.cpp
|
||||||
StringUtils.cpp
|
StringUtils.cpp
|
||||||
|
@ -38,18 +42,17 @@ list(APPEND core_LIB_INCLUDES
|
||||||
http/HttpRequest.cpp
|
http/HttpRequest.cpp
|
||||||
serializers/TomlReader.cpp)
|
serializers/TomlReader.cpp)
|
||||||
|
|
||||||
# add the executable
|
add_library(${MODULE_NAME} SHARED ${core_LIB_INCLUDES} ${core_HEADERS})
|
||||||
add_library(core SHARED ${core_LIB_INCLUDES} ${core_HEADERS})
|
|
||||||
|
|
||||||
target_include_directories(core PUBLIC
|
target_include_directories(${MODULE_NAME} PUBLIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/file_utilities"
|
${CMAKE_CURRENT_SOURCE_DIR}/file_utilities
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/loggers"
|
${CMAKE_CURRENT_SOURCE_DIR}/loggers
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/memory"
|
${CMAKE_CURRENT_SOURCE_DIR}/memory
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/streams"
|
${CMAKE_CURRENT_SOURCE_DIR}/streams
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/http"
|
${CMAKE_CURRENT_SOURCE_DIR}/http
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/data_structures"
|
${CMAKE_CURRENT_SOURCE_DIR}/data_structures
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/serializers"
|
${CMAKE_CURRENT_SOURCE_DIR}/serializers
|
||||||
)
|
)
|
||||||
set_target_properties( core PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||||
set_property(TARGET core PROPERTY FOLDER src)
|
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src)
|
|
@ -1,6 +1,6 @@
|
||||||
#include "Directory.h"
|
#include "Directory.h"
|
||||||
|
|
||||||
std::vector<Path> Directory::getFilesWithExtension(const Path& path, const std::string& extension)
|
std::vector<Path> Directory::getFilesWithExtension(const Path& path, const std::string& extension, bool recursive)
|
||||||
{
|
{
|
||||||
std::vector<Path> paths;
|
std::vector<Path> paths;
|
||||||
if (std::filesystem::is_directory(path))
|
if (std::filesystem::is_directory(path))
|
||||||
|
@ -11,6 +11,11 @@ std::vector<Path> Directory::getFilesWithExtension(const Path& path, const std::
|
||||||
{
|
{
|
||||||
paths.push_back(entry.path());
|
paths.push_back(entry.path());
|
||||||
}
|
}
|
||||||
|
else if(recursive && std::filesystem::is_directory(entry))
|
||||||
|
{
|
||||||
|
const auto child_paths = getFilesWithExtension(entry, extension, recursive);
|
||||||
|
paths.insert(paths.end(), child_paths.begin(), child_paths.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return paths;
|
return paths;
|
||||||
|
|
|
@ -9,5 +9,5 @@ class Directory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static std::vector<Path> getFilesWithExtension(const Path& path, const std::string& extension);
|
static std::vector<Path> getFilesWithExtension(const Path& path, const std::string& extension, bool recursive=false);
|
||||||
};
|
};
|
||||||
|
|
|
@ -197,11 +197,6 @@ std::string File::read()
|
||||||
return buffer.str();
|
return buffer.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string File::getBaseFilename(const Path& path)
|
|
||||||
{
|
|
||||||
return path.stem().string();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string File::readText()
|
std::string File::readText()
|
||||||
{
|
{
|
||||||
if (!pathExists())
|
if (!pathExists())
|
||||||
|
|
|
@ -20,7 +20,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
File(std::filesystem::path fullPath);
|
File(std::filesystem::path fullPath);
|
||||||
|
|
||||||
~File();
|
~File();
|
||||||
|
@ -29,8 +28,6 @@ public:
|
||||||
|
|
||||||
std::string dumpBinary();
|
std::string dumpBinary();
|
||||||
|
|
||||||
static std::string getBaseFilename(const Path& path);
|
|
||||||
|
|
||||||
std::string getExtension() const;
|
std::string getExtension() const;
|
||||||
|
|
||||||
std::ifstream* getInHandle() const;
|
std::ifstream* getInHandle() const;
|
||||||
|
|
33
src/core/file_utilities/PathUtils.cpp
Normal file
33
src/core/file_utilities/PathUtils.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "PathUtils.h"
|
||||||
|
|
||||||
|
|
||||||
|
std::string PathUtils::getBaseFilename(const Path& path)
|
||||||
|
{
|
||||||
|
return path.stem().string();
|
||||||
|
}
|
||||||
|
|
||||||
|
Path PathUtils::getRelativePath(const Path& input, const Path& relativeTo)
|
||||||
|
{
|
||||||
|
return std::filesystem::relative(input, relativeTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PathUtils::getPathDelimited(const Path& path, char delimiter)
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
unsigned count = 0;
|
||||||
|
for(const auto& element : path)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
name += element.stem().string();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name += delimiter + element.stem().string();
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
17
src/core/file_utilities/PathUtils.h
Normal file
17
src/core/file_utilities/PathUtils.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
|
class PathUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string getBaseFilename(const Path& path);
|
||||||
|
|
||||||
|
static Path getRelativePath(const Path& path, const Path& relativeTo);
|
||||||
|
|
||||||
|
static std::string getPathDelimited(const Path& path, char delimiter='-');
|
||||||
|
};
|
|
@ -15,6 +15,10 @@ list(APPEND web_LIB_INCLUDES
|
||||||
markdown/MarkdownConverter.cpp
|
markdown/MarkdownConverter.cpp
|
||||||
markdown/MarkdownDocument.h
|
markdown/MarkdownDocument.h
|
||||||
markdown/MarkdownDocument.cpp
|
markdown/MarkdownDocument.cpp
|
||||||
|
markdown/MarkdownComponents.h
|
||||||
|
markdown/MarkdownComponents.cpp
|
||||||
|
markdown/MarkdownElement.h
|
||||||
|
markdown/MarkdownElement.cpp
|
||||||
html/HtmlWriter.cpp
|
html/HtmlWriter.cpp
|
||||||
html/HtmlDocument.cpp
|
html/HtmlDocument.cpp
|
||||||
html/HtmlElement.cpp
|
html/HtmlElement.cpp
|
||||||
|
|
122
src/web/markdown/MarkdownComponents.cpp
Normal file
122
src/web/markdown/MarkdownComponents.cpp
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
#include "MarkdownComponents.h"
|
||||||
|
|
||||||
|
MarkdownTextSpan::Type MarkdownTextSpan::getType() const
|
||||||
|
{
|
||||||
|
return Type::TEXT_SPAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownParagraph::Type MarkdownParagraph::getType() const
|
||||||
|
{
|
||||||
|
return Type::PARAGRAPH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkdownParagraph::addChild(std::unique_ptr<MarkdownInlineElement> child)
|
||||||
|
{
|
||||||
|
mChildren.push_back(std::move(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t MarkdownParagraph::getNumChildren() const
|
||||||
|
{
|
||||||
|
return mChildren.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownInlineElement* MarkdownParagraph::getChild(std::size_t idx) const
|
||||||
|
{
|
||||||
|
return mChildren[idx].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownBulletItem::Type MarkdownBulletItem::getType() const
|
||||||
|
{
|
||||||
|
return Type::BULLET_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownBulletList::Type MarkdownBulletList::getType() const
|
||||||
|
{
|
||||||
|
return Type::BULLET_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkdownBulletList::addChild(std::unique_ptr<MarkdownBulletItem> child)
|
||||||
|
{
|
||||||
|
mChildren.push_back(std::move(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t MarkdownBulletList::getNumChildren() const
|
||||||
|
{
|
||||||
|
return mChildren.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownBulletItem* MarkdownBulletList::getChild(std::size_t idx) const
|
||||||
|
{
|
||||||
|
return mChildren[idx].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownHeading::MarkdownHeading(unsigned level)
|
||||||
|
: mLevel(level)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownHeading::Type MarkdownHeading::getType() const
|
||||||
|
{
|
||||||
|
return Type::HEADING;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned MarkdownHeading::getLevel() const
|
||||||
|
{
|
||||||
|
return mLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownInlineQuote::Type MarkdownInlineQuote::getType() const
|
||||||
|
{
|
||||||
|
return Type::INLINE_QUOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownLink::MarkdownLink(const std::string& target)
|
||||||
|
: mTarget(target)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& MarkdownLink::getTarget() const
|
||||||
|
{
|
||||||
|
return mTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownLink::Type MarkdownLink::getType() const
|
||||||
|
{
|
||||||
|
return Type::LINK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MarkdownImage::MarkdownImage(const std::string& source, const std::string& alt)
|
||||||
|
: mSource(source),
|
||||||
|
mAlt(alt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownImage::Type MarkdownImage::getType() const
|
||||||
|
{
|
||||||
|
return Type::IMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& MarkdownImage::getSource() const
|
||||||
|
{
|
||||||
|
return mSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& MarkdownImage::getAlt() const
|
||||||
|
{
|
||||||
|
return mAlt;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownMultilineQuote::MarkdownMultilineQuote(const std::string& tag)
|
||||||
|
: mTag(tag)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownMultilineQuote::Type MarkdownMultilineQuote::getType() const
|
||||||
|
{
|
||||||
|
return Type::MULTILINE_QUOTE;
|
||||||
|
}
|
124
src/web/markdown/MarkdownComponents.h
Normal file
124
src/web/markdown/MarkdownComponents.h
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MarkdownElement.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class MarkdownTextSpan : public MarkdownInlineElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MarkdownTextSpan() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownParagraph : public MarkdownElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MarkdownParagraph() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
void addChild(std::unique_ptr<MarkdownInlineElement> child);
|
||||||
|
|
||||||
|
std::size_t getNumChildren() const;
|
||||||
|
|
||||||
|
MarkdownInlineElement* getChild(std::size_t idx) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<MarkdownInlineElement> > mChildren;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownBulletItem : public MarkdownElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MarkdownBulletItem() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownBulletList : public MarkdownElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MarkdownBulletList() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
void addChild(std::unique_ptr<MarkdownBulletItem> child);
|
||||||
|
|
||||||
|
std::size_t getNumChildren() const;
|
||||||
|
|
||||||
|
MarkdownBulletItem* getChild(std::size_t idx) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<MarkdownBulletItem> > mChildren;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownHeading : public MarkdownElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MarkdownHeading(unsigned level);
|
||||||
|
|
||||||
|
virtual ~MarkdownHeading() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
unsigned getLevel() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned mLevel{1};
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownInlineQuote : public MarkdownInlineElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~MarkdownInlineQuote() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownLink : public MarkdownInlineElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MarkdownLink(const std::string& target);
|
||||||
|
|
||||||
|
virtual ~MarkdownLink() = default;
|
||||||
|
|
||||||
|
const std::string& getTarget() const;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
private:
|
||||||
|
std::string mTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownImage : public MarkdownInlineElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MarkdownImage(const std::string& source, const std::string& alt);
|
||||||
|
|
||||||
|
virtual ~MarkdownImage() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
|
||||||
|
const std::string& getSource() const;
|
||||||
|
|
||||||
|
const std::string& getAlt() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mSource;
|
||||||
|
std::string mAlt;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownMultilineQuote : public MarkdownElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MarkdownMultilineQuote(const std::string& tag);
|
||||||
|
|
||||||
|
virtual ~MarkdownMultilineQuote() = default;
|
||||||
|
|
||||||
|
Type getType() const override;
|
||||||
|
private:
|
||||||
|
std::string mTag;
|
||||||
|
};
|
|
@ -4,6 +4,8 @@
|
||||||
#include "HtmlElement.h"
|
#include "HtmlElement.h"
|
||||||
#include "HtmlParagraphElement.h"
|
#include "HtmlParagraphElement.h"
|
||||||
#include "HtmlTextRun.h"
|
#include "HtmlTextRun.h"
|
||||||
|
#include "MarkdownElement.h"
|
||||||
|
#include "MarkdownComponents.h"
|
||||||
|
|
||||||
#include "MarkdownDocument.h"
|
#include "MarkdownDocument.h"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include "MarkdownDocument.h"
|
||||||
|
|
||||||
|
#include "MarkdownElement.h"
|
||||||
|
|
||||||
|
void MarkdownDocument::addElement(std::unique_ptr<MarkdownElement> element)
|
||||||
|
{
|
||||||
|
mElements.push_back(std::move(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t MarkdownDocument::getNumElements() const
|
||||||
|
{
|
||||||
|
return mElements.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownElement* MarkdownDocument::getElement(std::size_t idx) const
|
||||||
|
{
|
||||||
|
return mElements[idx].get();
|
||||||
|
}
|
|
@ -3,262 +3,16 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class MarkdownElement
|
class MarkdownElement;
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
HEADING,
|
|
||||||
PARAGRAPH,
|
|
||||||
TEXT_SPAN,
|
|
||||||
INLINE_CODE,
|
|
||||||
MULTILINE_CODE,
|
|
||||||
INLINE_QUOTE,
|
|
||||||
MULTILINE_QUOTE,
|
|
||||||
INLINE_SPECIAL,
|
|
||||||
MULTILINE_SPECIAL,
|
|
||||||
LINK,
|
|
||||||
IMAGE,
|
|
||||||
BULLET_ITEM,
|
|
||||||
BULLET_LIST
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~MarkdownElement() = default;
|
|
||||||
|
|
||||||
void appendTextContent(const std::string& content)
|
|
||||||
{
|
|
||||||
mTextContent += content;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& getTextContent() const
|
|
||||||
{
|
|
||||||
return mTextContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Type getType() const = 0;
|
|
||||||
private:
|
|
||||||
std::string mTextContent;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownInlineElement : public MarkdownElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~MarkdownInlineElement() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownTextSpan : public MarkdownInlineElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~MarkdownTextSpan() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::TEXT_SPAN;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownParagraph : public MarkdownElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~MarkdownParagraph() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::PARAGRAPH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addChild(std::unique_ptr<MarkdownInlineElement> child)
|
|
||||||
{
|
|
||||||
mChildren.push_back(std::move(child));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t getNumChildren() const
|
|
||||||
{
|
|
||||||
return mChildren.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkdownInlineElement* getChild(std::size_t idx) const
|
|
||||||
{
|
|
||||||
return mChildren[idx].get();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<MarkdownInlineElement> > mChildren;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownBulletItem : public MarkdownElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~MarkdownBulletItem() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::BULLET_ITEM;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownBulletList : public MarkdownElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~MarkdownBulletList() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::BULLET_LIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addChild(std::unique_ptr<MarkdownBulletItem> child)
|
|
||||||
{
|
|
||||||
mChildren.push_back(std::move(child));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t getNumChildren() const
|
|
||||||
{
|
|
||||||
return mChildren.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkdownBulletItem* getChild(std::size_t idx) const
|
|
||||||
{
|
|
||||||
return mChildren[idx].get();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<MarkdownBulletItem> > mChildren;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownHeading : public MarkdownElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MarkdownHeading(unsigned level)
|
|
||||||
: mLevel(level)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
virtual ~MarkdownHeading() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::HEADING;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getLevel() const
|
|
||||||
{
|
|
||||||
return mLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned mLevel{1};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MarkdownInlineQuote : public MarkdownInlineElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual ~MarkdownInlineQuote() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::INLINE_QUOTE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownLink : public MarkdownInlineElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
MarkdownLink(const std::string& target)
|
|
||||||
: mTarget(target)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MarkdownLink() = default;
|
|
||||||
|
|
||||||
const std::string& getTarget() const
|
|
||||||
{
|
|
||||||
return mTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::LINK;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::string mTarget;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownImage : public MarkdownInlineElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MarkdownImage(const std::string& source, const std::string& alt)
|
|
||||||
: mSource(source),
|
|
||||||
mAlt(alt)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MarkdownImage() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::IMAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& getSource() const
|
|
||||||
{
|
|
||||||
return mSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& getAlt() const
|
|
||||||
{
|
|
||||||
return mAlt;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string mSource;
|
|
||||||
std::string mAlt;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MarkdownMultilineQuote : public MarkdownElement
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MarkdownMultilineQuote(const std::string& tag)
|
|
||||||
: mTag(tag)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MarkdownMultilineQuote() = default;
|
|
||||||
|
|
||||||
Type getType() const override
|
|
||||||
{
|
|
||||||
return Type::MULTILINE_QUOTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string mTag;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MarkdownDocument
|
class MarkdownDocument
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void addElement(std::unique_ptr<MarkdownElement> element)
|
void addElement(std::unique_ptr<MarkdownElement> element);
|
||||||
{
|
|
||||||
mElements.push_back(std::move(element));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t getNumElements() const
|
std::size_t getNumElements() const;
|
||||||
{
|
|
||||||
return mElements.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkdownElement* getElement(std::size_t idx) const
|
MarkdownElement* getElement(std::size_t idx) const;
|
||||||
{
|
|
||||||
return mElements[idx].get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<MarkdownElement> > mElements;
|
std::vector<std::unique_ptr<MarkdownElement> > mElements;
|
||||||
|
|
11
src/web/markdown/MarkdownElement.cpp
Normal file
11
src/web/markdown/MarkdownElement.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include "MarkdownElement.h"
|
||||||
|
|
||||||
|
void MarkdownElement::appendTextContent(const std::string& content)
|
||||||
|
{
|
||||||
|
mTextContent += content;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& MarkdownElement::getTextContent() const
|
||||||
|
{
|
||||||
|
return mTextContent;
|
||||||
|
}
|
40
src/web/markdown/MarkdownElement.h
Normal file
40
src/web/markdown/MarkdownElement.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class MarkdownElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
HEADING,
|
||||||
|
PARAGRAPH,
|
||||||
|
TEXT_SPAN,
|
||||||
|
INLINE_CODE,
|
||||||
|
MULTILINE_CODE,
|
||||||
|
INLINE_QUOTE,
|
||||||
|
MULTILINE_QUOTE,
|
||||||
|
INLINE_SPECIAL,
|
||||||
|
MULTILINE_SPECIAL,
|
||||||
|
LINK,
|
||||||
|
IMAGE,
|
||||||
|
BULLET_ITEM,
|
||||||
|
BULLET_LIST
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~MarkdownElement() = default;
|
||||||
|
|
||||||
|
void appendTextContent(const std::string& content);
|
||||||
|
|
||||||
|
const std::string& getTextContent() const;
|
||||||
|
|
||||||
|
virtual Type getType() const = 0;
|
||||||
|
private:
|
||||||
|
std::string mTextContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownInlineElement : public MarkdownElement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MarkdownInlineElement() = default;
|
||||||
|
};
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "MarkdownDocument.h"
|
#include "MarkdownDocument.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
#include "MarkdownComponents.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
Loading…
Reference in a new issue