Toward template rendering.
This commit is contained in:
parent
eb3b394bdf
commit
350c20efa6
9 changed files with 542 additions and 385 deletions
|
@ -1,399 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "File.h"
|
||||
#include "Directory.h"
|
||||
#include "StringUtils.h"
|
||||
#include "TemplateFile.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
class TemplateNode
|
||||
{
|
||||
public:
|
||||
|
||||
TemplateNode(TemplateNode* parent)
|
||||
: mParent(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TemplateNode* getParent() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
virtual void addChild(std::unique_ptr<TemplateNode> child)
|
||||
{
|
||||
mChildren.push_back(std::move(child));
|
||||
}
|
||||
|
||||
std::size_t getNumChildren() const
|
||||
{
|
||||
return mChildren.size();
|
||||
}
|
||||
|
||||
TemplateNode* getChild(std::size_t index) const
|
||||
{
|
||||
return mChildren[index].get();
|
||||
}
|
||||
|
||||
virtual std::string getRawContent() const
|
||||
{
|
||||
std::string content;
|
||||
for (const auto& child : mChildren)
|
||||
{
|
||||
content += child->getRawContent() + "\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<TemplateNode> > mChildren;
|
||||
TemplateNode* mParent{ nullptr };
|
||||
};
|
||||
|
||||
using TemplateNodePtr = std::unique_ptr<TemplateNode>;
|
||||
|
||||
class TemplateExtends : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExtends(TemplateNode* parent, const std::string& path)
|
||||
: TemplateNode(parent),
|
||||
mPath(path)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
std::string getRawContent() const override
|
||||
{
|
||||
return "TemplateExtends: " + mPath;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mPath;
|
||||
};
|
||||
|
||||
class TemplateBlock : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateBlock(TemplateNode* parent, const std::string& name)
|
||||
: TemplateNode(parent),
|
||||
mName(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void addLine(const std::string& line)
|
||||
{
|
||||
mBody.push_back(line);
|
||||
}
|
||||
|
||||
std::string getRawContent() const override
|
||||
{
|
||||
std::string content = "TemplateBlock: " + mName + "\n";
|
||||
content += TemplateNode::getRawContent();
|
||||
return content;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::vector<std::string> mBody;
|
||||
};
|
||||
|
||||
class TemplateExpression : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateExpression(TemplateNode* parent, const std::string& content)
|
||||
: TemplateNode(parent),
|
||||
mContent(content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string getRawContent() const override
|
||||
{
|
||||
return "TemplateExpression: " + mContent;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mContent;
|
||||
};
|
||||
|
||||
class TemplateTextBody : public TemplateNode
|
||||
{
|
||||
public:
|
||||
TemplateTextBody(TemplateNode* parent)
|
||||
: TemplateNode(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void addLine(const std::string& content)
|
||||
{
|
||||
mContent.push_back(content);
|
||||
}
|
||||
|
||||
bool hasContent() const
|
||||
{
|
||||
return !mContent.empty();
|
||||
}
|
||||
|
||||
std::string getRawContent() const override
|
||||
{
|
||||
std::string content;
|
||||
for (const auto& line : mContent)
|
||||
{
|
||||
content += "TemplateBody: " + line + "\n";
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> mContent;
|
||||
};
|
||||
|
||||
class TemplateFile
|
||||
{
|
||||
public:
|
||||
TemplateFile(const Path& path)
|
||||
: mPath(path),
|
||||
mRootNode(std::make_unique<TemplateNode>(nullptr))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::string> getProcessedContent() const
|
||||
{
|
||||
return mProcessedContent;
|
||||
}
|
||||
|
||||
std::string getName() const
|
||||
{
|
||||
return mPath.stem().string();
|
||||
}
|
||||
|
||||
void loadContent()
|
||||
{
|
||||
std::cout << "Trying to load file at: " << mPath << std::endl;
|
||||
mRawContent = File(mPath).readLines();
|
||||
mWorkingLine = 0;
|
||||
mWorkingNode = mRootNode.get();
|
||||
mWorkingTextBody = std::make_unique<TemplateTextBody>(mWorkingNode);
|
||||
for (const auto& line : mRawContent)
|
||||
{
|
||||
processLine(line);
|
||||
mWorkingLine++;
|
||||
}
|
||||
onTextBodyFinished();
|
||||
}
|
||||
|
||||
void onTextBodyFinished(std::string working_string = {})
|
||||
{
|
||||
if (!working_string.empty())
|
||||
{
|
||||
mWorkingTextBody->addLine(working_string);
|
||||
}
|
||||
|
||||
if (mWorkingTextBody->hasContent())
|
||||
{
|
||||
mWorkingNode->addChild(std::move(mWorkingTextBody));
|
||||
mWorkingTextBody = std::make_unique<TemplateTextBody>(mWorkingNode);
|
||||
}
|
||||
}
|
||||
|
||||
void processLine(const std::string& line)
|
||||
{
|
||||
bool last_was_ldelimiter{ false };
|
||||
bool last_was_statement_rdelimiter{ false };
|
||||
bool last_was_expression_rdelimiter{ false };
|
||||
bool in_statement{ false };
|
||||
bool in_expression{ false };
|
||||
std::string working_string;
|
||||
std::string last_working_string;
|
||||
for (auto c : line)
|
||||
{
|
||||
if (c == '{')
|
||||
{
|
||||
if (last_was_ldelimiter)
|
||||
{
|
||||
in_expression = true;
|
||||
last_was_ldelimiter = false;
|
||||
working_string = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
last_was_ldelimiter = true;
|
||||
}
|
||||
}
|
||||
else if (c == '%' && last_was_ldelimiter)
|
||||
{
|
||||
last_was_ldelimiter = false;
|
||||
in_statement = true;
|
||||
last_working_string = working_string;
|
||||
working_string = "";
|
||||
}
|
||||
else if (c == '%' && in_statement)
|
||||
{
|
||||
last_was_statement_rdelimiter = true;
|
||||
}
|
||||
else if (c == '}' && (last_was_statement_rdelimiter || in_expression || last_was_expression_rdelimiter))
|
||||
{
|
||||
if (last_was_statement_rdelimiter)
|
||||
{
|
||||
onTextBodyFinished(last_working_string);
|
||||
onFoundStatement(working_string);
|
||||
last_was_statement_rdelimiter = false;
|
||||
working_string = "";
|
||||
}
|
||||
else if (in_expression)
|
||||
{
|
||||
last_was_expression_rdelimiter = true;
|
||||
in_expression = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
onTextBodyFinished();
|
||||
onFoundExpression(working_string);
|
||||
last_was_expression_rdelimiter = false;
|
||||
working_string = "";
|
||||
}
|
||||
}
|
||||
else if (last_was_ldelimiter && (!in_statement && !in_expression))
|
||||
{
|
||||
last_was_ldelimiter = false;
|
||||
working_string += '{';
|
||||
working_string += c;
|
||||
}
|
||||
else
|
||||
{
|
||||
working_string += c;
|
||||
}
|
||||
}
|
||||
|
||||
if (!working_string.empty())
|
||||
{
|
||||
mWorkingTextBody->addLine(working_string);
|
||||
}
|
||||
}
|
||||
|
||||
void onFoundStatement(const std::string& statement_string)
|
||||
{
|
||||
const auto statement_elements = StringUtils::split(statement_string);
|
||||
|
||||
if (statement_elements.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto statement_type = statement_elements[0];
|
||||
if (statement_type == "block" && statement_elements.size() == 2)
|
||||
{
|
||||
onFoundBlock(statement_elements);
|
||||
}
|
||||
else if (statement_type == "endblock")
|
||||
{
|
||||
onFoundEndBlock(statement_elements);
|
||||
}
|
||||
else if (statement_type == "extends")
|
||||
{
|
||||
onFoundExtends(statement_elements);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void onFoundBlock(const std::vector<std::string> args)
|
||||
{
|
||||
if (args.size() != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto block = std::make_unique<TemplateBlock>(mWorkingNode, args[1]);
|
||||
auto temp = block.get();
|
||||
mWorkingNode->addChild(std::move(block));
|
||||
mWorkingNode = temp;
|
||||
}
|
||||
|
||||
void onFoundEndBlock(const std::vector<std::string> args)
|
||||
{
|
||||
mWorkingNode = mWorkingNode->getParent();
|
||||
}
|
||||
|
||||
void onFoundExtends(const std::vector<std::string> args)
|
||||
{
|
||||
if (args.size() != 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto extends = std::make_unique<TemplateExtends>(mWorkingNode, args[1]);
|
||||
mWorkingNode->addChild(std::move(extends));
|
||||
}
|
||||
|
||||
void onFoundExpression(const std::string& expression_string)
|
||||
{
|
||||
auto expression = std::make_unique<TemplateExpression>(mWorkingNode, expression_string);
|
||||
mWorkingNode->addChild(std::move(expression));
|
||||
}
|
||||
|
||||
void dumpContent()
|
||||
{
|
||||
auto content = mRootNode->getRawContent();
|
||||
std::cout << content << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
Path mPath;
|
||||
unsigned mWorkingLine{ 0 };
|
||||
std::string mParentName;
|
||||
std::vector<std::string> mRawContent;
|
||||
std::vector<std::string> mProcessedContent;
|
||||
std::unique_ptr<TemplateNode> mRootNode;
|
||||
TemplateNode* mWorkingNode{ nullptr };
|
||||
std::unique_ptr<TemplateTextBody> mWorkingTextBody;
|
||||
};
|
||||
|
||||
class TemplatingEngine
|
||||
{
|
||||
public:
|
||||
TemplatingEngine(const Path& workingDirectory)
|
||||
: mWorkingDirectory(workingDirectory)
|
||||
{
|
||||
TemplatingEngine(const Path& workingDirectory);
|
||||
|
||||
}
|
||||
|
||||
void loadTemplateFiles()
|
||||
{
|
||||
const auto files = Directory::getFilesWithExtension(mWorkingDirectory, mTemplateExtension);
|
||||
for (const auto& file : files)
|
||||
{
|
||||
mTemplateFiles.push_back(TemplateFile(file));
|
||||
}
|
||||
}
|
||||
|
||||
void processTemplate(const std::string& name)
|
||||
{
|
||||
for (auto& file : mTemplateFiles)
|
||||
{
|
||||
const auto filename = file.getName();
|
||||
if (filename == name)
|
||||
{
|
||||
processTemplate(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processTemplate(TemplateFile& file)
|
||||
{
|
||||
file.loadContent();
|
||||
file.dumpContent();
|
||||
}
|
||||
|
||||
|
||||
void loadTemplateFiles();
|
||||
|
||||
std::string processTemplate(const std::string& name);
|
||||
|
||||
private:
|
||||
std::vector<TemplateFile> mTemplateFiles;
|
||||
TemplateFile* getTemplateFile(const std::string& name);
|
||||
TemplateFile* getTemplateFile(const Path& path);
|
||||
std::string render(TemplateNode* content);
|
||||
|
||||
std::string processTemplate(TemplateFile* file, TemplateNode* parent = nullptr);
|
||||
|
||||
std::vector<std::unique_ptr<TemplateFile> > mTemplateFiles;
|
||||
Path mWorkingDirectory;
|
||||
std::string mTemplateExtension{ ".html" };
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue