From 101bfb4207e95cc13077e8f9238e97d1fef88097 Mon Sep 17 00:00:00 2001 From: James Grogan Date: Wed, 7 Dec 2022 11:34:29 +0000 Subject: [PATCH] Allow custom tag processing in md --- .../MarkdownContentParser.cpp | 16 +++- src/web/markdown/MarkdownComponents.cpp | 20 ++++- src/web/markdown/MarkdownComponents.h | 13 ++- src/web/markdown/MarkdownConverter.cpp | 12 +++ src/web/markdown/MarkdownCustomElement.cpp | 0 src/web/markdown/MarkdownCustomElement.h | 79 +++++++++++++++++++ src/web/markdown/MarkdownDocument.cpp | 42 ++++++++-- src/web/markdown/MarkdownDocument.h | 20 ++++- src/web/markdown/MarkdownElement.cpp | 2 +- src/web/markdown/MarkdownElement.h | 2 +- src/web/markdown/MarkdownParser.cpp | 43 +++++----- src/web/markdown/MarkdownParser.h | 8 +- 12 files changed, 214 insertions(+), 43 deletions(-) create mode 100644 src/web/markdown/MarkdownCustomElement.cpp create mode 100644 src/web/markdown/MarkdownCustomElement.h diff --git a/apps/website-generator/MarkdownContentParser.cpp b/apps/website-generator/MarkdownContentParser.cpp index 09908cb..382134b 100644 --- a/apps/website-generator/MarkdownContentParser.cpp +++ b/apps/website-generator/MarkdownContentParser.cpp @@ -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 } MarkdownParser md_parser; - auto content = md_parser.run(content_body); - return {output_metadata, std::move(content)}; + auto document = std::make_unique(); + + auto custom_math_inline = std::make_unique("$"); + custom_math_inline->setReplacementDelimiters("\\(", "\\)"); + + auto custom_math_multiline = std::make_unique("$$"); + + 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::checkForMetadataItem(const std::string& line) const diff --git a/src/web/markdown/MarkdownComponents.cpp b/src/web/markdown/MarkdownComponents.cpp index 646be2d..145c932 100644 --- a/src/web/markdown/MarkdownComponents.cpp +++ b/src/web/markdown/MarkdownComponents.cpp @@ -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(); +} diff --git a/src/web/markdown/MarkdownComponents.h b/src/web/markdown/MarkdownComponents.h index 9ce191f..ac4d488 100644 --- a/src/web/markdown/MarkdownComponents.h +++ b/src/web/markdown/MarkdownComponents.h @@ -1,6 +1,7 @@ #pragma once #include "MarkdownElement.h" +#include "MarkdownCustomElement.h" #include #include @@ -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}; }; diff --git a/src/web/markdown/MarkdownConverter.cpp b/src/web/markdown/MarkdownConverter.cpp index db3cc33..89ac251 100644 --- a/src/web/markdown/MarkdownConverter.cpp +++ b/src/web/markdown/MarkdownConverter.cpp @@ -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(); + 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(); @@ -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(); + html_text->setText("\n" + md_element->getTextContent() + "\n"); + parentElement->addChild(std::move(html_text)); + } } } diff --git a/src/web/markdown/MarkdownCustomElement.cpp b/src/web/markdown/MarkdownCustomElement.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/web/markdown/MarkdownCustomElement.h b/src/web/markdown/MarkdownCustomElement.h new file mode 100644 index 0000000..424d914 --- /dev/null +++ b/src/web/markdown/MarkdownCustomElement.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +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) + { + + } +}; diff --git a/src/web/markdown/MarkdownDocument.cpp b/src/web/markdown/MarkdownDocument.cpp index 33e3865..7076cfa 100644 --- a/src/web/markdown/MarkdownDocument.cpp +++ b/src/web/markdown/MarkdownDocument.cpp @@ -3,6 +3,10 @@ #include "MarkdownElement.h" #include "MarkdownComponents.h" +MarkdownDocument::~MarkdownDocument() +{ + +} void MarkdownDocument::addElement(std::unique_ptr 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 MarkdownDocument::getAllLinks() const { std::vector links; @@ -49,3 +45,33 @@ std::vector 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 context) +{ + mCustomInlineContexts.push_back(std::move(context)); +} + +void MarkdownDocument::registerCustomMultilineElement(std::unique_ptr context) +{ + mCustomMultilineContexts.push_back(std::move(context)); +} diff --git a/src/web/markdown/MarkdownDocument.h b/src/web/markdown/MarkdownDocument.h index 7e3ba8c..dfeb946 100644 --- a/src/web/markdown/MarkdownDocument.h +++ b/src/web/markdown/MarkdownDocument.h @@ -5,22 +5,38 @@ class MarkdownElement; class MarkdownLink; +class MarkdownCustomMultilineElementContext; +class MarkdownCustomInlineElementContext; class MarkdownDocument { public: + ~MarkdownDocument(); + void addElement(std::unique_ptr 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 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 context); + + void registerCustomMultilineElement(std::unique_ptr context); + private: std::vector > mElements; + std::vector > mCustomMultilineContexts; + std::vector > mCustomInlineContexts; }; diff --git a/src/web/markdown/MarkdownElement.cpp b/src/web/markdown/MarkdownElement.cpp index ff2da7a..8169122 100644 --- a/src/web/markdown/MarkdownElement.cpp +++ b/src/web/markdown/MarkdownElement.cpp @@ -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; } diff --git a/src/web/markdown/MarkdownElement.h b/src/web/markdown/MarkdownElement.h index 762e57c..2b9bde5 100644 --- a/src/web/markdown/MarkdownElement.h +++ b/src/web/markdown/MarkdownElement.h @@ -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; diff --git a/src/web/markdown/MarkdownParser.cpp b/src/web/markdown/MarkdownParser.cpp index aedc6e1..685de96 100644 --- a/src/web/markdown/MarkdownParser.cpp +++ b/src/web/markdown/MarkdownParser.cpp @@ -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 hits; unsigned hit_size{0}; - for(unsigned idx=0; idxgetNumInlineContexts(); 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(delimiter); + auto element = std::make_unique(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(); 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; idxgetNumMultilineContexts(); 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(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(tag, delimiter); + auto quote = std::make_unique(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(); mWorkingBulletList = bullet_list.get(); - mMarkdownDocument->addElement(std::move(bullet_list)); + mWorkingDocument->addElement(std::move(bullet_list)); auto bullet_item = std::make_unique(); mWorkingElement = bullet_item.get(); @@ -357,9 +357,9 @@ void MarkdownParser::onSectionFinished() mWorkingTextSpan = nullptr; } -std::unique_ptr MarkdownParser::run(const std::string& content) +void MarkdownParser::run(const std::string& content, MarkdownDocument* document) { - mMarkdownDocument = std::make_unique(); + mWorkingDocument = document; std::stringstream ss(content); std::string line; @@ -392,6 +392,13 @@ std::unique_ptr MarkdownParser::run(const std::string& content processLine(line); } } - - return std::move(mMarkdownDocument); +} + +std::unique_ptr MarkdownParser::run(const std::string& content) +{ + auto doc = std::make_unique(); + + run(content, doc.get()); + + return std::move(doc); } diff --git a/src/web/markdown/MarkdownParser.h b/src/web/markdown/MarkdownParser.h index 45ea61b..0ed6e61 100644 --- a/src/web/markdown/MarkdownParser.h +++ b/src/web/markdown/MarkdownParser.h @@ -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 run(const std::string& content); + void run(const std::string& content, MarkdownDocument* document); + private: void addChildToWorkingElement(std::unique_ptr child); @@ -45,8 +49,6 @@ private: bool startsWithBulletItem(const std::string& line) const; unsigned mCustomDelimiterIndex{0}; - std::vector mCustomMultilineDelimiters; - std::vector mCustomInlineDelimiters; MarkdownElement* mWorkingElement{nullptr}; MarkdownBulletList* mWorkingBulletList{nullptr}; @@ -54,5 +56,5 @@ private: MarkdownInlineElement* mWorkingTextSpan{nullptr}; std::string mWorkingLine; - std::unique_ptr mMarkdownDocument; + MarkdownDocument* mWorkingDocument{nullptr}; };