diff --git a/.gitignore b/.gitignore
index 2ef7c1b..b11b982 100644
--- a/.gitignore
+++ b/.gitignore
@@ -161,10 +161,6 @@ tags
### VisualStudioCode ###
.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
.history
### Xcode ###
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5fb0515..bde4c15 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,7 @@ maddy uses [semver versioning](https://semver.org/).
*  config flags `isEmphasizedParserEnabled` and `isHTMLWrappedInParagraph`
*  config flag `enabledParsers` to en-/disable each parser separately
*  class attribute to code blocks if there is text after the three backticks like ` ```cpp`
+*  optional support for latex blocks - it's off by default
* ?
## version 1.1.2 2020-10-04
diff --git a/docs/definitions.md b/docs/definitions.md
index 862b956..9be5075 100644
--- a/docs/definitions.md
+++ b/docs/definitions.md
@@ -220,6 +220,18 @@ results in
some code
+```
+
+ ```cpp
+ int a = 42;
+ ```
+
+results in
+
+```html
+
+int a = 42;
+
```
## Inline code
@@ -364,3 +376,29 @@ becomes
```
table header and footer are optional
+
+## LaTeX(MathJax) block support
+
+To turn on the LaTeX support - which basically is only a
+[MathJax](https://www.mathjax.org/) support and makes sure, that formulas aren't
+internally checked for other parsers - it has to be enabled in config:
+
+```cpp
+std::shared_ptr config = std::make_shared();
+config->enabledParsers |= maddy::types::LATEX_BLOCK_PARSER;
+
+std::shared_ptr parser = std::make_shared(config);
+std::string htmlOutput = parser->Parse(markdownInput);
+```
+
+After this you can do the following in Markdown:
+
+```
+$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$
+```
+
+Which results in
+
+```html
+$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$\n
+```
diff --git a/include/maddy/latexblockparser.h b/include/maddy/latexblockparser.h
new file mode 100644
index 0000000..02d66cb
--- /dev/null
+++ b/include/maddy/latexblockparser.h
@@ -0,0 +1,135 @@
+/*
+ * This project is licensed under the MIT license. For more information see the
+ * LICENSE file.
+ */
+#pragma once
+
+// -----------------------------------------------------------------------------
+
+#include
+#include
+#include
+
+#include "maddy/blockparser.h"
+
+// -----------------------------------------------------------------------------
+
+namespace maddy {
+
+// -----------------------------------------------------------------------------
+
+/**
+ * LatexBlockParser
+ *
+ * Support for https://www.mathjax.org/
+ * Be aware, that if you want to make MathJax work, you need also their
+ * JavaScript library added to your HTML code.
+ * maddy does not itself add that code to be more flexible in how you write your
+ * head and full body.
+ *
+ * From Markdown: `$$` surrounded text
+ *
+ * ```
+ * $$some formula
+ * $$
+ * ```
+ *
+ * To HTML:
+ *
+ * ```
+ * $$some formula
+ * $$
+ * ```
+ *
+ * @class
+ */
+class LatexBlockParser : public BlockParser
+{
+public:
+ /**
+ * ctor
+ *
+ * @method
+ * @param {std::function} parseLineCallback
+ * @param {std::function(const std::string& line)>} getBlockParserForLineCallback
+ */
+ LatexBlockParser(
+ std::function parseLineCallback,
+ std::function(const std::string& line)> getBlockParserForLineCallback
+ )
+ : BlockParser(parseLineCallback, getBlockParserForLineCallback)
+ , isStarted(false)
+ , isFinished(false)
+ {}
+
+ /**
+ * IsStartingLine
+ *
+ * If the line starts with two dollars, then it is a latex block.
+ *
+ * ```
+ * $$
+ * ```
+ *
+ * @method
+ * @param {const std::string&} line
+ * @return {bool}
+ */
+ static bool
+ IsStartingLine(const std::string& line)
+ {
+ static std::regex re("^(?:\\$){2}(.*)$");
+ return std::regex_match(line, re);
+ }
+
+ /**
+ * IsFinished
+ *
+ * @method
+ * @return {bool}
+ */
+ bool
+ IsFinished() const override
+ {
+ return this->isFinished;
+ }
+
+protected:
+ bool
+ isInlineBlockAllowed() const override
+ {
+ return false;
+ }
+
+ bool
+ isLineParserAllowed() const override
+ {
+ return false;
+ }
+
+ void
+ parseBlock(std::string& line) override
+ {
+ if (!this->isStarted && line.substr(0, 2) == "$$")
+ {
+ this->isStarted = true;
+ this->isFinished = false;
+ }
+
+ if (this->isStarted && !this->isFinished && line.size() > 1 && line.substr(line.size() - 2, 2) == "$$")
+ {
+ this->isFinished = true;
+ this->isStarted = false;
+ }
+
+ line += "\n";
+ }
+
+private:
+ bool isStarted;
+ bool isFinished;
+}; // class LatexBlockParser
+
+// -----------------------------------------------------------------------------
+
+} // namespace maddy
diff --git a/include/maddy/parser.h b/include/maddy/parser.h
index ffca7aa..1ae8377 100644
--- a/include/maddy/parser.h
+++ b/include/maddy/parser.h
@@ -18,6 +18,7 @@
#include "maddy/headlineparser.h"
#include "maddy/horizontallineparser.h"
#include "maddy/htmlparser.h"
+#include "maddy/latexblockparser.h"
#include "maddy/orderedlistparser.h"
#include "maddy/paragraphparser.h"
#include "maddy/quoteparser.h"
@@ -259,6 +260,17 @@ private:
nullptr
);
}
+ else if (
+ this->config &&
+ (this->config->enabledParsers & maddy::types::LATEX_BLOCK_PARSER) != 0 &&
+ maddy::LatexBlockParser::IsStartingLine(line)
+ )
+ {
+ parser = std::make_shared(
+ nullptr,
+ nullptr
+ );
+ }
else if (
(
!this->config ||
diff --git a/include/maddy/parserconfig.h b/include/maddy/parserconfig.h
index 2395a2c..ddf129c 100644
--- a/include/maddy/parserconfig.h
+++ b/include/maddy/parserconfig.h
@@ -41,9 +41,10 @@ enum PARSER_TYPE : uint32_t
STRONG_PARSER = 0b1000000000000000,
TABLE_PARSER = 0b10000000000000000,
UNORDERED_LIST_PARSER = 0b100000000000000000,
+ LATEX_BLOCK_PARSER = 0b1000000000000000000,
- DEFAULT = 0b111111111110111111,
- ALL = 0b111111111111111111,
+ DEFAULT = 0b0111111111110111111,
+ ALL = 0b1111111111111111111,
};
} // namespace types
diff --git a/tests/maddy/test_maddy_latexblockparser.cpp b/tests/maddy/test_maddy_latexblockparser.cpp
new file mode 100644
index 0000000..701b1a3
--- /dev/null
+++ b/tests/maddy/test_maddy_latexblockparser.cpp
@@ -0,0 +1,102 @@
+/*
+ * This project is licensed under the MIT license. For more information see the
+ * LICENSE file.
+ */
+#include
+
+#include "gmock/gmock.h"
+
+#include "maddy/latexblockparser.h"
+
+// -----------------------------------------------------------------------------
+
+class MADDY_LATEXBLOCKPARSER : public ::testing::Test
+{
+protected:
+ std::shared_ptr lbParser;
+
+ void
+ SetUp() override
+ {
+ this->lbParser = std::make_shared(
+ nullptr,
+ nullptr
+ );
+ }
+};
+
+// -----------------------------------------------------------------------------
+
+TEST_F(MADDY_LATEXBLOCKPARSER, IsStartingLineReturnsTrueWhenFacedWithTwoDollars)
+{
+ ASSERT_TRUE(maddy::LatexBlockParser::IsStartingLine("$$"));
+}
+
+TEST_F(MADDY_LATEXBLOCKPARSER, IsFinishedReturnsFalseInTheBeginning)
+{
+ ASSERT_FALSE(lbParser->IsFinished());
+}
+
+TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesOneLineMarkdownWithALatexBlock)
+{
+ std::vector markdown = {
+ "$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$"
+ };
+
+ std::string expected = "$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$\n";
+
+ for (std::string md : markdown)
+ {
+ lbParser->AddLine(md);
+ }
+ ASSERT_TRUE(lbParser->IsFinished());
+
+ std::stringstream& output(lbParser->GetResult());
+ const std::string& outputString = output.str();
+
+ ASSERT_EQ(expected, outputString);
+}
+
+TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesABlockMarkdownWithALatexBlock)
+{
+ std::vector markdown = {
+ "$$",
+ "x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.",
+ "$$"
+ };
+
+ std::string expected = "$$\nx = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.\n$$\n";
+
+ for (std::string md : markdown)
+ {
+ lbParser->AddLine(md);
+ }
+ ASSERT_TRUE(lbParser->IsFinished());
+
+ std::stringstream& output(lbParser->GetResult());
+ const std::string& outputString = output.str();
+
+ ASSERT_EQ(expected, outputString);
+}
+
+TEST_F(MADDY_LATEXBLOCKPARSER, ItReplacesAMultilineBlockMarkdownWithALatexBlock)
+{
+ std::vector markdown = {
+ "$$",
+ "x = {-b \\pm \\sqrt{b^2-4ac}",
+ "\\over 2a}.$$"
+ };
+
+ std::string expected = "$$\nx = {-b \\pm \\sqrt{b^2-4ac}\n\\over 2a}.$$\n";
+
+ for (std::string md : markdown)
+ {
+ lbParser->AddLine(md);
+ }
+ ASSERT_TRUE(lbParser->IsFinished());
+
+ std::stringstream& output(lbParser->GetResult());
+ const std::string& outputString = output.str();
+
+ ASSERT_EQ(expected, outputString);
+}