Allow custom tag processing in md

This commit is contained in:
James Grogan 2022-12-07 11:34:29 +00:00
parent 22157169c0
commit 101bfb4207
12 changed files with 214 additions and 43 deletions

View file

@ -3,6 +3,7 @@
#include "MarkdownParser.h"
#include "MarkdownDocument.h"
#include "MarkdownElement.h"
#include "MarkdownCustomElement.h"
#include "File.h"
@ -37,9 +38,20 @@ std::pair<MarkdownContentParser::FileMetadata, std::unique_ptr<MarkdownDocument>
}
MarkdownParser md_parser;
auto content = md_parser.run(content_body);
return {output_metadata, std::move(content)};
auto document = std::make_unique<MarkdownDocument>();
auto custom_math_inline = std::make_unique<MarkdownCustomInlineElementContext>("$");
custom_math_inline->setReplacementDelimiters("\\(", "\\)");
auto custom_math_multiline = std::make_unique<MarkdownCustomMultilineElementContext>("$$");
document->registerCustomInlineElement(std::move(custom_math_inline));
document->registerCustomMultilineElement(std::move(custom_math_multiline));
md_parser.run(content_body, document.get());
return {output_metadata, std::move(document)};
}
std::optional<MarkdownContentParser::FileMetadataItem> MarkdownContentParser::checkForMetadataItem(const std::string& line) const

View file

@ -1,5 +1,6 @@
#include "MarkdownComponents.h"
#include "MarkdownCustomElement.h"
#include "StringUtils.h"
MarkdownTextSpan::Type MarkdownTextSpan::getType() const
@ -98,8 +99,8 @@ MarkdownInlineQuote::Type MarkdownInlineQuote::getType() const
return Type::INLINE_QUOTE;
}
MarkdownCustomInline::MarkdownCustomInline(const std::string& delimiter)
: mDelimiter(delimiter)
MarkdownCustomInline::MarkdownCustomInline(MarkdownCustomElementContext* customElement)
: mCustomElement(customElement)
{
}
@ -108,6 +109,11 @@ MarkdownCustomInline::Type MarkdownCustomInline::getType() const
return Type::CUSTOM_INLINE;
};
std::string MarkdownCustomInline::getTextContent() const
{
return mCustomElement->getOutputLeftDelimiter() + MarkdownElement::getTextContent() + mCustomElement->getOutputRightDelimiter();
}
MarkdownLink::MarkdownLink(const std::string& target)
: mTarget(target)
{
@ -158,13 +164,19 @@ MarkdownMultilineQuote::Type MarkdownMultilineQuote::getType() const
}
MarkdownCustomMultiLine::MarkdownCustomMultiLine(const std::string& tag, const std::string& delimiter)
MarkdownCustomMultiLine::MarkdownCustomMultiLine(const std::string& tag, MarkdownCustomElementContext* customElement)
: mTag(tag),
mDelimiter(delimiter)
mCustomElement(customElement)
{
}
MarkdownCustomMultiLine::Type MarkdownCustomMultiLine::getType() const
{
return Type::CUSTOM_MULTILINE;
}
std::string MarkdownCustomMultiLine::getTextContent() const
{
return mCustomElement->getOutputLeftDelimiter() + "\n" + MarkdownElement::getTextContent() + mCustomElement->getOutputRightDelimiter();
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "MarkdownElement.h"
#include "MarkdownCustomElement.h"
#include <vector>
#include <memory>
@ -120,12 +121,14 @@ public:
class MarkdownCustomInline : public MarkdownInlineElement
{
public:
MarkdownCustomInline(const std::string& delimiter);
MarkdownCustomInline(MarkdownCustomElementContext* customElement);
virtual ~MarkdownCustomInline() = default;
Type getType() const override;
std::string getTextContent() const override;
private:
std::string mDelimiter;
MarkdownCustomElementContext* mCustomElement{nullptr};
};
class MarkdownImage : public MarkdownInlineElement
@ -161,12 +164,14 @@ private:
class MarkdownCustomMultiLine : public MarkdownMultilineElement
{
public:
MarkdownCustomMultiLine(const std::string& tag, const std::string& delimiter);
MarkdownCustomMultiLine(const std::string& tag, MarkdownCustomElementContext* customElement);
virtual ~MarkdownCustomMultiLine() = default;
Type getType() const override;
std::string getTextContent() const override;
private:
std::string mTag;
std::string mDelimiter;
MarkdownCustomElementContext* mCustomElement{nullptr};
};

View file

@ -21,6 +21,12 @@ void MarkdownConverter::onBlockElement(MarkdownElementWithChildren* mdElement, H
html_quote->setText(child->getTextContent());
htmlElement->addChild(std::move(html_quote));
}
else if (child->getType() == MarkdownElement::Type::CUSTOM_INLINE)
{
auto html_text = std::make_unique<HtmlTextRun>();
html_text->setText(child->getTextContent());
htmlElement->addChild(std::move(html_text));
}
else if(child->getType() == MarkdownElement::Type::TEXT_SPAN)
{
auto html_text = std::make_unique<HtmlTextRun>();
@ -87,6 +93,12 @@ void MarkdownConverter::convert(MarkdownDocument* markdownDoc, HtmlElement* pare
html_quote->setText(md_element->getTextContent());
parentElement->addChild(std::move(html_quote));
}
else if(md_element->getType() == MarkdownElement::Type::CUSTOM_MULTILINE)
{
auto html_text = std::make_unique<HtmlTextRun>();
html_text->setText("\n" + md_element->getTextContent() + "\n");
parentElement->addChild(std::move(html_text));
}
}
}

View file

@ -0,0 +1,79 @@
#pragma once
#include <string>
class MarkdownCustomElementContext
{
public:
MarkdownCustomElementContext(const std::string& delimiter)
: mDelimiter(delimiter)
{
}
virtual ~MarkdownCustomElementContext() = default;
void setReplacementDelimiters(const std::string& leftReplacement, const std::string& rightReplacement)
{
mReplacementLeftDelimiter = leftReplacement;
mReplacementRightDelimiter = rightReplacement;
if (mReplacementRightDelimiter.empty())
{
mReplacementRightDelimiter = mReplacementLeftDelimiter;
}
}
const std::string& getDelimiter() const
{
return mDelimiter;
}
const std::string& getOutputLeftDelimiter() const
{
if (!mReplacementLeftDelimiter.empty())
{
return mReplacementLeftDelimiter;
}
else
{
return mDelimiter;
}
}
const std::string& getOutputRightDelimiter() const
{
if (!mReplacementRightDelimiter.empty())
{
return mReplacementRightDelimiter;
}
else
{
return mDelimiter;
}
}
private:
std::string mReplacementLeftDelimiter;
std::string mReplacementRightDelimiter;
std::string mDelimiter;
};
class MarkdownCustomInlineElementContext : public MarkdownCustomElementContext
{
public:
MarkdownCustomInlineElementContext(const std::string& delimiter)
: MarkdownCustomElementContext(delimiter)
{
}
};
class MarkdownCustomMultilineElementContext : public MarkdownCustomElementContext
{
public:
MarkdownCustomMultilineElementContext(const std::string& delimiter)
: MarkdownCustomElementContext(delimiter)
{
}
};

View file

@ -3,6 +3,10 @@
#include "MarkdownElement.h"
#include "MarkdownComponents.h"
MarkdownDocument::~MarkdownDocument()
{
}
void MarkdownDocument::addElement(std::unique_ptr<MarkdownElement> element)
{
@ -19,14 +23,6 @@ MarkdownElement* MarkdownDocument::getElement(std::size_t idx) const
return mElements[idx].get();
}
void MarkdownDocument::doLinkTargetSubstitution(const std::string& targetString, const std::string& replacementString)
{
for(auto& element : mElements)
{
element->doFieldSubstitution(MarkdownElement::Type::LINK, targetString, replacementString);
}
}
std::vector<MarkdownLink*> MarkdownDocument::getAllLinks() const
{
std::vector<MarkdownLink*> links;
@ -49,3 +45,33 @@ std::vector<MarkdownLink*> MarkdownDocument::getAllLinks() const
}
return links;
}
std::size_t MarkdownDocument::getNumMultilineContexts() const
{
return mCustomMultilineContexts.size();
}
std::size_t MarkdownDocument::getNumInlineContexts() const
{
return mCustomInlineContexts.size();
}
MarkdownCustomMultilineElementContext* MarkdownDocument::getMultilineContext(std::size_t idx) const
{
return mCustomMultilineContexts[idx].get();
}
MarkdownCustomInlineElementContext* MarkdownDocument::getInlineContext(std::size_t idx) const
{
return mCustomInlineContexts[idx].get();
}
void MarkdownDocument::registerCustomInlineElement(std::unique_ptr<MarkdownCustomInlineElementContext> context)
{
mCustomInlineContexts.push_back(std::move(context));
}
void MarkdownDocument::registerCustomMultilineElement(std::unique_ptr<MarkdownCustomMultilineElementContext> context)
{
mCustomMultilineContexts.push_back(std::move(context));
}

View file

@ -5,22 +5,38 @@
class MarkdownElement;
class MarkdownLink;
class MarkdownCustomMultilineElementContext;
class MarkdownCustomInlineElementContext;
class MarkdownDocument
{
public:
~MarkdownDocument();
void addElement(std::unique_ptr<MarkdownElement> element);
std::size_t getNumElements() const;
MarkdownElement* getElement(std::size_t idx) const;
void doLinkTargetSubstitution(const std::string& targetString, const std::string& replacementString);
std::vector<MarkdownLink*> getAllLinks() const;
std::size_t getNumMultilineContexts() const;
std::size_t getNumInlineContexts() const;
MarkdownCustomMultilineElementContext* getMultilineContext(std::size_t idx) const;
MarkdownCustomInlineElementContext* getInlineContext(std::size_t idx) const;
void registerCustomInlineElement(std::unique_ptr<MarkdownCustomInlineElementContext> context);
void registerCustomMultilineElement(std::unique_ptr<MarkdownCustomMultilineElementContext> context);
private:
std::vector<std::unique_ptr<MarkdownElement> > mElements;
std::vector<std::unique_ptr<MarkdownCustomMultilineElementContext> > mCustomMultilineContexts;
std::vector<std::unique_ptr<MarkdownCustomInlineElementContext> > mCustomInlineContexts;
};

View file

@ -5,7 +5,7 @@ void MarkdownElement::appendTextContent(const std::string& content)
mTextContent += content;
}
const std::string& MarkdownElement::getTextContent() const
std::string MarkdownElement::getTextContent() const
{
return mTextContent;
}

View file

@ -26,7 +26,7 @@ public:
void addLine(const std::string& line);
const std::string& getTextContent() const;
virtual std::string getTextContent() const;
virtual Type getType() const = 0;

View file

@ -2,6 +2,7 @@
#include "MarkdownDocument.h"
#include "MarkdownComponents.h"
#include "MarkdownCustomElement.h"
#include "Lexer.h"
#include "StringUtils.h"
@ -13,8 +14,7 @@ static constexpr char HEADING_DELIMITER{'#'};
MarkdownParser::MarkdownParser()
{
mCustomMultilineDelimiters = {{"$$"}};
mCustomInlineDelimiters = {{"$"}};
}
MarkdownParser::~MarkdownParser()
@ -121,9 +121,9 @@ unsigned MarkdownParser::checkForCustomInline(const std::string& lineSection)
std::vector<std::string> hits;
unsigned hit_size{0};
for(unsigned idx=0; idx<mCustomInlineDelimiters.size(); idx++)
for(unsigned idx=0; idx<mWorkingDocument->getNumInlineContexts(); idx++)
{
const auto delimiter = mCustomInlineDelimiters[idx];
const auto delimiter = mWorkingDocument->getInlineContext(idx)->getDelimiter();
if (Lexer::matchPattern(delimiter + "@" + delimiter, lineSection, '@', hits))
{
if (hits.size() == 1)
@ -132,7 +132,7 @@ unsigned MarkdownParser::checkForCustomInline(const std::string& lineSection)
onTextSpanFinished();
auto element = std::make_unique<MarkdownCustomInline>(delimiter);
auto element = std::make_unique<MarkdownCustomInline>(mWorkingDocument->getInlineContext(idx));
element->appendTextContent(content);
addChildToWorkingElement(std::move(element));
@ -182,7 +182,7 @@ void MarkdownParser::processLine(const std::string& line)
{
auto paragraph = std::make_unique<MarkdownParagraph>();
mWorkingElement = paragraph.get();
mMarkdownDocument->addElement(std::move(paragraph));
mWorkingDocument->addElement(std::move(paragraph));
}
if (mWorkingElement && mWorkingElement->getType() == MarkdownElement::Type::PARAGRAPH)
@ -239,9 +239,9 @@ bool MarkdownParser::startsWithMultiLineQuote(const std::string& line) const
int MarkdownParser::startsWithCustomMultilineBlock(const std::string& line) const
{
for(unsigned idx=0; idx<mCustomMultilineDelimiters.size(); idx++)
for(unsigned idx=0; idx<mWorkingDocument->getNumMultilineContexts(); idx++)
{
if (StringUtils::startsWith(line, mCustomMultilineDelimiters[idx], true))
if (StringUtils::startsWith(line, mWorkingDocument->getMultilineContext(idx)->getDelimiter(), true))
{
return idx;
}
@ -274,7 +274,7 @@ void MarkdownParser::onFoundMultiLineQuote(const std::string& line)
const auto tag = StringUtils::removeUpTo(line, MULTILINE_QUOTE_DELIMITER);
auto quote = std::make_unique<MarkdownMultilineQuote>(tag);
mWorkingElement = quote.get();
mMarkdownDocument->addElement(std::move(quote));
mWorkingDocument->addElement(std::move(quote));
}
}
@ -290,11 +290,11 @@ void MarkdownParser::onFoundCustomMultiLineBlock(const std::string& line, unsign
}
else
{
const auto delimiter = mCustomMultilineDelimiters[blockSlot];
const auto delimiter = mWorkingDocument->getMultilineContext(blockSlot)->getDelimiter();
const auto tag = StringUtils::removeUpTo(line, delimiter);
auto quote = std::make_unique<MarkdownCustomMultiLine>(tag, delimiter);
auto quote = std::make_unique<MarkdownCustomMultiLine>(tag, mWorkingDocument->getMultilineContext(blockSlot));
mWorkingElement = quote.get();
mMarkdownDocument->addElement(std::move(quote));
mWorkingDocument->addElement(std::move(quote));
}
}
@ -317,7 +317,7 @@ void MarkdownParser::onFoundHeading(const std::string& line)
prefix += HEADING_DELIMITER;
}
heading->appendTextContent(StringUtils::stripSurroundingWhitepsace(StringUtils::removeUpTo(line, prefix)));
mMarkdownDocument->addElement(std::move(heading));
mWorkingDocument->addElement(std::move(heading));
}
}
@ -340,7 +340,7 @@ void MarkdownParser::onFoundBulletItem(const std::string& line)
auto bullet_list = std::make_unique<MarkdownBulletList>();
mWorkingBulletList = bullet_list.get();
mMarkdownDocument->addElement(std::move(bullet_list));
mWorkingDocument->addElement(std::move(bullet_list));
auto bullet_item = std::make_unique<MarkdownBulletItem>();
mWorkingElement = bullet_item.get();
@ -357,9 +357,9 @@ void MarkdownParser::onSectionFinished()
mWorkingTextSpan = nullptr;
}
std::unique_ptr<MarkdownDocument> MarkdownParser::run(const std::string& content)
void MarkdownParser::run(const std::string& content, MarkdownDocument* document)
{
mMarkdownDocument = std::make_unique<MarkdownDocument>();
mWorkingDocument = document;
std::stringstream ss(content);
std::string line;
@ -392,6 +392,13 @@ std::unique_ptr<MarkdownDocument> MarkdownParser::run(const std::string& content
processLine(line);
}
}
return std::move(mMarkdownDocument);
}
std::unique_ptr<MarkdownDocument> MarkdownParser::run(const std::string& content)
{
auto doc = std::make_unique<MarkdownDocument>();
run(content, doc.get());
return std::move(doc);
}

View file

@ -8,6 +8,8 @@ class MarkdownDocument;
class MarkdownElement;
class MarkdownInlineElement;
class MarkdownBulletList;
class MarkdownCustomInlineElementContext;
class MarkdownCustomMultilineElementContext;
class MarkdownParser
{
@ -18,6 +20,8 @@ public:
std::unique_ptr<MarkdownDocument> run(const std::string& content);
void run(const std::string& content, MarkdownDocument* document);
private:
void addChildToWorkingElement(std::unique_ptr<MarkdownInlineElement> child);
@ -45,8 +49,6 @@ private:
bool startsWithBulletItem(const std::string& line) const;
unsigned mCustomDelimiterIndex{0};
std::vector<std::string> mCustomMultilineDelimiters;
std::vector<std::string> mCustomInlineDelimiters;
MarkdownElement* mWorkingElement{nullptr};
MarkdownBulletList* mWorkingBulletList{nullptr};
@ -54,5 +56,5 @@ private:
MarkdownInlineElement* mWorkingTextSpan{nullptr};
std::string mWorkingLine;
std::unique_ptr<MarkdownDocument> mMarkdownDocument;
MarkdownDocument* mWorkingDocument{nullptr};
};