mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2024-11-14 04:57:21 +01:00
Added maddy and switched to markdown from bbcode in ListPage.
This commit is contained in:
parent
e20f1c98a2
commit
6c56380d90
@ -1,10 +1,28 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <maddy/parser.h>
|
||||
|
||||
void Utils::newline_to_br(std::string *str) {
|
||||
str_replace(str, "\r\n", "<br>");
|
||||
str_replace(str, "\n", "<br>");
|
||||
}
|
||||
|
||||
void Utils::markdown_to_html(std::string *str) {
|
||||
std::shared_ptr<maddy::ParserConfig> config = std::make_shared<maddy::ParserConfig>();
|
||||
config->isEmphasizedParserEnabled = true;
|
||||
config->isHTMLWrappedInParagraph = true;
|
||||
|
||||
std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>(config);
|
||||
|
||||
std::stringstream ss((*str));
|
||||
|
||||
std::string htmlOutput = parser->Parse(ss);
|
||||
|
||||
(*str) = htmlOutput;
|
||||
}
|
||||
|
||||
void Utils::bbcode_evaluate_simple(std::string *str) {
|
||||
bbcpp::BBDocumentPtr doc = bbcode((*str));
|
||||
|
||||
|
@ -5,11 +5,14 @@
|
||||
|
||||
#include <bbcpp/BBDocument.h>
|
||||
|
||||
|
||||
class Utils {
|
||||
public:
|
||||
static void newline_to_br(std::string *str);
|
||||
//htmlspecialchars
|
||||
|
||||
static void markdown_to_html(std::string *str);
|
||||
|
||||
static void bbcode_evaluate_simple(std::string *str);
|
||||
static bbcpp::BBDocumentPtr bbcode(const std::string &str);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
RapidJSON 0ccdbf364c577803e2a751f5aededce935314313
|
||||
brynet b0d13e7419628d0f7051a2bb310daaf8a506e08b
|
||||
rapidxml 1.13
|
||||
bbcpp a035c4942ed9e5277833fe80e444406f959c3d88
|
||||
bbcpp a035c4942ed9e5277833fe80e444406f959c3d88
|
||||
maddy adb1a910d4aadea09cb7b200f2ec204f61214596
|
18
libs/maddy/LICENSE
Normal file
18
libs/maddy/LICENSE
Normal file
@ -0,0 +1,18 @@
|
||||
Copyright 2017, 2018, 2019, 2020 M. Petra Baranski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
82
libs/maddy/README.md
Normal file
82
libs/maddy/README.md
Normal file
@ -0,0 +1,82 @@
|
||||
# maddy
|
||||
|
||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
||||
[![Version: 1.1.2](https://img.shields.io/badge/Version-1.1.2-brightgreen.svg)](https://semver.org/)
|
||||
[![Travis Build Status](https://travis-ci.org/progsource/maddy.svg?branch=master)](https://travis-ci.org/progsource/maddy)
|
||||
[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/04m0lg27kigv1pg8/branch/master?svg=true)](https://ci.appveyor.com/project/progsource/maddy/branch/master)
|
||||
|
||||
maddy is a C++ Markdown to HTML **header-only** parser library.
|
||||
|
||||
## Supported OS
|
||||
|
||||
It actually should work on any OS, that supports the C++14 standard library.
|
||||
|
||||
It is tested to work on:
|
||||
|
||||
* Linux (gcc)
|
||||
* OSX (clang)
|
||||
* Windows (Visual Studio 2017)
|
||||
|
||||
## Dependencies
|
||||
|
||||
* C++14
|
||||
|
||||
## Why maddy?
|
||||
|
||||
When I was needing a Markdown parser in C++ I couldn't find any, that was
|
||||
fitting my needs. So I simply wrote my own one.
|
||||
|
||||
## Markdown syntax
|
||||
|
||||
The supported syntax can be found in the [definitions docs](docs/definitions.md).
|
||||
|
||||
## How to use
|
||||
|
||||
To use maddy in your project, simply add the include path of maddy to yours
|
||||
and in the code, you can then do the following:
|
||||
|
||||
```c++
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/parser.h"
|
||||
|
||||
std::stringstream markdownInput("");
|
||||
|
||||
// config is optional
|
||||
std::shared_ptr<maddy::ParserConfig> config = std::make_shared<maddy::ParserConfig>();
|
||||
config->isEmphasizedParserEnabled = true; // default
|
||||
config->isHTMLWrappedInParagraph = true; // default
|
||||
|
||||
std::shared_ptr<maddy::Parser> parser = std::make_shared<maddy::Parser>(config);
|
||||
std::string htmlOutput = parser->Parse(markdownInput);
|
||||
```
|
||||
|
||||
## How to run the tests
|
||||
|
||||
*(tested on Linux with
|
||||
[git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and
|
||||
[cmake](https://cmake.org/install/) installed)*
|
||||
|
||||
Open your preferred terminal and type:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/progsource/maddy.git
|
||||
cd maddy
|
||||
git submodule update --init --recursive
|
||||
mkdir tmp
|
||||
cd tmp
|
||||
cmake ..
|
||||
make
|
||||
make test # or run the executable in ../build/MaddyTests
|
||||
```
|
||||
|
||||
## How to contribute
|
||||
|
||||
There are different possibilities:
|
||||
|
||||
* [Create a GitHub issue](https://github.com/progsource/maddy/issues/new)
|
||||
* Create a pull request with an own branch (don't forget to put yourself in the
|
||||
AUTHORS file)
|
||||
|
||||
Please also read [CONTRIBUTING.md](CONTRIBUTING.md).
|
203
libs/maddy/blockparser.h
Normal file
203
libs/maddy/blockparser.h
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
// windows compatibility includes
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* BlockParser
|
||||
*
|
||||
* The code expects every child to have the following static function to be
|
||||
* implemented:
|
||||
* `static bool IsStartingLine(const std::string& line)`
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
BlockParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: result("", std::ios_base::ate | std::ios_base::in | std::ios_base::out)
|
||||
, childParser(nullptr)
|
||||
, parseLineCallback(parseLineCallback)
|
||||
, getBlockParserForLineCallback(getBlockParserForLineCallback)
|
||||
{}
|
||||
|
||||
/**
|
||||
* dtor
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
virtual ~BlockParser() {}
|
||||
|
||||
/**
|
||||
* AddLine
|
||||
*
|
||||
* Adding a line which has to be parsed.
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line
|
||||
* @return {void}
|
||||
*/
|
||||
virtual void
|
||||
AddLine(std::string& line)
|
||||
{
|
||||
this->parseBlock(line);
|
||||
|
||||
if (this->isInlineBlockAllowed() && !this->childParser)
|
||||
{
|
||||
this->childParser = this->getBlockParserForLine(line);
|
||||
}
|
||||
|
||||
if (this->childParser)
|
||||
{
|
||||
this->childParser->AddLine(line);
|
||||
|
||||
if (this->childParser->IsFinished())
|
||||
{
|
||||
this->result << this->childParser->GetResult().str();
|
||||
this->childParser = nullptr;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->isLineParserAllowed())
|
||||
{
|
||||
this->parseLine(line);
|
||||
}
|
||||
|
||||
this->result << line;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* Check if the BlockParser is done
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
virtual bool IsFinished() const = 0;
|
||||
|
||||
/**
|
||||
* GetResult
|
||||
*
|
||||
* Get the parsed HTML output.
|
||||
*
|
||||
* @method
|
||||
* @return {std::stringstream}
|
||||
*/
|
||||
std::stringstream&
|
||||
GetResult()
|
||||
{
|
||||
return this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear
|
||||
*
|
||||
* Clear the result to reuse the parser object.
|
||||
*
|
||||
* It is only used by one test for now.
|
||||
*
|
||||
* @method
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Clear()
|
||||
{
|
||||
this->result.str("");
|
||||
}
|
||||
|
||||
protected:
|
||||
std::stringstream result;
|
||||
std::shared_ptr<BlockParser> childParser;
|
||||
|
||||
virtual bool isInlineBlockAllowed() const = 0;
|
||||
virtual bool isLineParserAllowed() const = 0;
|
||||
virtual void parseBlock(std::string& line) = 0;
|
||||
|
||||
void
|
||||
parseLine(std::string& line)
|
||||
{
|
||||
if (parseLineCallback)
|
||||
{
|
||||
parseLineCallback(line);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
getIndentationWidth(const std::string& line) const
|
||||
{
|
||||
bool hasMetNonSpace = false;
|
||||
|
||||
uint32_t indentation = static_cast<uint32_t>(
|
||||
std::count_if(
|
||||
line.begin(),
|
||||
line.end(),
|
||||
[&hasMetNonSpace](unsigned char c)
|
||||
{
|
||||
if (hasMetNonSpace)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::isspace(c))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
hasMetNonSpace = true;
|
||||
return false;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return indentation;
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockParser>
|
||||
getBlockParserForLine(const std::string& line)
|
||||
{
|
||||
if (getBlockParserForLineCallback)
|
||||
{
|
||||
return getBlockParserForLineCallback(line);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(std::string&)> parseLineCallback;
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback;
|
||||
}; // class BlockParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
51
libs/maddy/breaklineparser.h
Normal file
51
libs/maddy/breaklineparser.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* BreakLineParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class BreakLineParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `text\r\n text`
|
||||
*
|
||||
* To HTML: `text<br> text`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
static std::regex re(R"((\r\n|\r))");
|
||||
static std::string replacement = "<br>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class BreakLineParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
140
libs/maddy/checklistparser.h
Normal file
140
libs/maddy/checklistparser.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ChecklistParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class ChecklistParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
ChecklistParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* An unordered list starts with `* `.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::regex re("^- \\[[x| ]\\] .*");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return this->isFinished;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string& line) override
|
||||
{
|
||||
bool isStartOfNewListItem = IsStartingLine(line);
|
||||
uint32_t indentation = getIndentationWidth(line);
|
||||
|
||||
static std::regex lineRegex("^(- )");
|
||||
line = std::regex_replace(line, lineRegex, "");
|
||||
|
||||
static std::regex emptyBoxRegex("^\\[ \\]");
|
||||
static std::string emptyBoxReplacement = "<input type=\"checkbox\"/>";
|
||||
line = std::regex_replace(line, emptyBoxRegex, emptyBoxReplacement);
|
||||
|
||||
static std::regex boxRegex("^\\[x\\]");
|
||||
static std::string boxReplacement = "<input type=\"checkbox\" checked=\"checked\"/>";
|
||||
line = std::regex_replace(line, boxRegex, boxReplacement);
|
||||
|
||||
if (!this->isStarted)
|
||||
{
|
||||
line = "<ul class=\"checklist\"><li><label>" + line;
|
||||
this->isStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (indentation >= 2)
|
||||
{
|
||||
line = line.substr(2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
line.empty() ||
|
||||
line.find("</label></li><li><label>") != std::string::npos ||
|
||||
line.find("</label></li></ul>") != std::string::npos
|
||||
)
|
||||
{
|
||||
line = "</label></li></ul>" + line;
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isStartOfNewListItem)
|
||||
{
|
||||
line = "</label></li><li><label>" + line;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
}; // class ChecklistParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
137
libs/maddy/codeblockparser.h
Normal file
137
libs/maddy/codeblockparser.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CodeBlockParser
|
||||
*
|
||||
* From Markdown: 3 times surrounded code (without space in the beginning)
|
||||
*
|
||||
* ```
|
||||
* ```
|
||||
* some code
|
||||
* ```
|
||||
* ```
|
||||
*
|
||||
* To HTML:
|
||||
*
|
||||
* ```
|
||||
* <pre><code>
|
||||
* some code
|
||||
* </code></pre>
|
||||
* ```
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class CodeBlockParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
CodeBlockParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* If the line starts with three code signs, then it is a code block.
|
||||
*
|
||||
* ```
|
||||
* ```
|
||||
* ```
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::regex re("^(?:`){3}$");
|
||||
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 (line == "```")
|
||||
{
|
||||
if (!this->isStarted)
|
||||
{
|
||||
line = "<pre><code>\n";
|
||||
this->isStarted = true;
|
||||
this->isFinished = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = "</code></pre>";
|
||||
this->isFinished = true;
|
||||
this->isStarted = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
line += "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
}; // class CodeBlockParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
53
libs/maddy/emphasizedparser.h
Normal file
53
libs/maddy/emphasizedparser.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* EmphasizedParser
|
||||
*
|
||||
* Has to be used after the `StrongParser`.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class EmphasizedParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `text _text_`
|
||||
*
|
||||
* To HTML: `text <em>text</em>`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
static std::regex re("(?!.*`.*|.*<code>.*)_(?!.*`.*|.*<\\/code>.*)([^_]*)_(?!.*`.*|.*<\\/code>.*)");
|
||||
static std::string replacement = "<em>$1</em>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class EmphasizedParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
138
libs/maddy/headlineparser.h
Normal file
138
libs/maddy/headlineparser.h
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* HeadlineParser
|
||||
*
|
||||
* From Markdown:
|
||||
*
|
||||
* ```
|
||||
* # Headline 1
|
||||
* ## Headline 2
|
||||
* ### Headline 3
|
||||
* #### Headline 4
|
||||
* ##### Headline 5
|
||||
* ###### Headline 6
|
||||
* ```
|
||||
*
|
||||
* To HTML:
|
||||
*
|
||||
* ```
|
||||
* <h1>Headline 1</h1>
|
||||
* <h2>Headline 2</h2>
|
||||
* <h3>Headline 3</h3>
|
||||
* <h4>Headline 4</h4>
|
||||
* <h5>Headline 5</h5>
|
||||
* <h6>Headline 6</h6>
|
||||
* ```
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class HeadlineParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
HeadlineParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* If the line starts with 1 - 6 `#`, then it is a headline.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::regex re("^(?:#){1,6} (.*)");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* The headline is always only one line long, so this method always returns
|
||||
* true.
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string& line) override
|
||||
{
|
||||
static std::vector<std::regex> hlRegex = {
|
||||
std::regex("^# (.*)")
|
||||
, std::regex("^(?:#){2} (.*)")
|
||||
, std::regex("^(?:#){3} (.*)")
|
||||
, std::regex("^(?:#){4} (.*)")
|
||||
, std::regex("^(?:#){5} (.*)")
|
||||
, std::regex("^(?:#){6} (.*)")
|
||||
};
|
||||
static std::vector<std::string> hlReplacement = {
|
||||
"<h1>$1</h1>"
|
||||
, "<h2>$1</h2>"
|
||||
, "<h3>$1</h3>"
|
||||
, "<h4>$1</h4>"
|
||||
, "<h5>$1</h5>"
|
||||
, "<h6>$1</h6>"
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < 6; ++i)
|
||||
{
|
||||
line = std::regex_replace(line, hlRegex[i], hlReplacement[i]);
|
||||
}
|
||||
}
|
||||
}; // class HeadlineParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
106
libs/maddy/horizontallineparser.h
Normal file
106
libs/maddy/horizontallineparser.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* HorizontalLineParser
|
||||
*
|
||||
* From Markdown: `---`
|
||||
*
|
||||
* To HTML: `<hr/>`
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class HorizontalLineParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
HorizontalLineParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, lineRegex("^---$")
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* If the line has exact three dashes `---`, then it is a horizontal line.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::regex re("^---$");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* The horizontal line is always only one line long, so this method always
|
||||
* returns true.
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string& line) override
|
||||
{
|
||||
static std::string replacement = "<hr/>";
|
||||
|
||||
line = std::regex_replace(line, lineRegex, replacement);
|
||||
}
|
||||
|
||||
private:
|
||||
std::regex lineRegex;
|
||||
}; // class HorizontalLineParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
127
libs/maddy/htmlparser.h
Normal file
127
libs/maddy/htmlparser.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* HtmlParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class HtmlParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
HtmlParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
, isGreaterThanFound(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* If the line is starting with `<`, HTML is expected to follow.
|
||||
* Nothing after that will be parsed, it only is copied.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
return line[0] == '<';
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* `>` followed by an empty line will end the HTML block.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
this->isStarted = true;
|
||||
}
|
||||
|
||||
if (!line.empty() && line[line.size() - 1] == '>')
|
||||
{
|
||||
this->isGreaterThanFound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.empty() && this->isGreaterThanFound)
|
||||
{
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!line.empty() && this->isGreaterThanFound)
|
||||
{
|
||||
this->isGreaterThanFound = false;
|
||||
}
|
||||
|
||||
if (!line.empty())
|
||||
{
|
||||
line += " ";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
bool isGreaterThanFound;
|
||||
}; // class HtmlParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
53
libs/maddy/imageparser.h
Normal file
53
libs/maddy/imageparser.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ImageParser
|
||||
*
|
||||
* Has to be used before the `LinkParser`.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class ImageParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `![text](http://example.com/a.png)`
|
||||
*
|
||||
* To HTML: `<img src="http://example.com/a.png" alt="text"/>`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
static std::regex re("\\!\\[([^\\]]*)\\]\\(([^\\]]*)\\)");
|
||||
static std::string replacement = "<img src=\"$2\" alt=\"$1\"/>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class ImageParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
51
libs/maddy/inlinecodeparser.h
Normal file
51
libs/maddy/inlinecodeparser.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* InlineCodeParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class InlineCodeParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `text `some code``
|
||||
*
|
||||
* To HTML: `text <code>some code</code>`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
static std::regex re("`([^`]*)`");
|
||||
static std::string replacement = "<code>$1</code>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class InlineCodeParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
50
libs/maddy/italicparser.h
Normal file
50
libs/maddy/italicparser.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ItalicParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class ItalicParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `text *text*`
|
||||
*
|
||||
* To HTML: `text <i>text</i>`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
std::regex re("(?!.*`.*|.*<code>.*)\\*(?!.*`.*|.*<\\/code>.*)([^\\*]*)\\*(?!.*`.*|.*<\\/code>.*)");
|
||||
static std::string replacement = "<i>$1</i>";
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class ItalicParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
46
libs/maddy/lineparser.h
Normal file
46
libs/maddy/lineparser.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* LineParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* dtor
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
virtual ~LineParser() {}
|
||||
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown to HTML
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
virtual void Parse(std::string& line) = 0;
|
||||
}; // class LineParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
53
libs/maddy/linkparser.h
Normal file
53
libs/maddy/linkparser.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* LinkParser
|
||||
*
|
||||
* Has to be used after the `ImageParser`.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class LinkParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `[text](http://example.com)`
|
||||
*
|
||||
* To HTML: `<a href="http://example.com">text</a>`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
static std::regex re("\\[([^\\]]*)\\]\\(([^\\]]*)\\)");
|
||||
static std::string replacement = "<a href=\"$2\">$1</a>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class LinkParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
142
libs/maddy/orderedlistparser.h
Normal file
142
libs/maddy/orderedlistparser.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* OrderedListParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class OrderedListParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
OrderedListParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* An ordered list starts with `1. `.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::regex re("^1\\. .*");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return this->isFinished;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string& line) override
|
||||
{
|
||||
bool isStartOfNewListItem = this->isStartOfNewListItem(line);
|
||||
uint32_t indentation = getIndentationWidth(line);
|
||||
|
||||
static std::regex orderedlineRegex("^[1-9]+[0-9]*\\. ");
|
||||
line = std::regex_replace(line, orderedlineRegex, "");
|
||||
static std::regex unorderedlineRegex("^\\* ");
|
||||
line = std::regex_replace(line, unorderedlineRegex, "");
|
||||
|
||||
if (!this->isStarted)
|
||||
{
|
||||
line = "<ol><li>" + line;
|
||||
this->isStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (indentation >= 2)
|
||||
{
|
||||
line = line.substr(2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
line.empty() ||
|
||||
line.find("</li><li>") != std::string::npos ||
|
||||
line.find("</li></ol>") != std::string::npos ||
|
||||
line.find("</li></ul>") != std::string::npos
|
||||
)
|
||||
{
|
||||
line = "</li></ol>" + line;
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isStartOfNewListItem)
|
||||
{
|
||||
line = "</li><li>" + line;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
|
||||
bool
|
||||
isStartOfNewListItem(const std::string& line) const
|
||||
{
|
||||
static std::regex re("^(?:[1-9]+[0-9]*\\. |\\* ).*");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
}; // class OrderedListParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
115
libs/maddy/paragraphparser.h
Normal file
115
libs/maddy/paragraphparser.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ParagraphParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class ParagraphParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
ParagraphParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* If the line is not empty, it will be a paragraph.
|
||||
*
|
||||
* This block parser has to always run as the last one!
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
return !line.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* An empty line will end the paragraph.
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return this->isFinished;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string& line) override
|
||||
{
|
||||
if (!this->isStarted)
|
||||
{
|
||||
line = "<p>" + line + " ";
|
||||
this->isStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (line.empty())
|
||||
{
|
||||
line += "</p>";
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
line += " ";
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
}; // class ParagraphParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
294
libs/maddy/parser.h
Normal file
294
libs/maddy/parser.h
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/parserconfig.h"
|
||||
|
||||
// BlockParser
|
||||
#include "maddy/checklistparser.h"
|
||||
#include "maddy/codeblockparser.h"
|
||||
#include "maddy/headlineparser.h"
|
||||
#include "maddy/horizontallineparser.h"
|
||||
#include "maddy/htmlparser.h"
|
||||
#include "maddy/orderedlistparser.h"
|
||||
#include "maddy/paragraphparser.h"
|
||||
#include "maddy/quoteparser.h"
|
||||
#include "maddy/tableparser.h"
|
||||
#include "maddy/unorderedlistparser.h"
|
||||
|
||||
// LineParser
|
||||
#include "maddy/breaklineparser.h"
|
||||
#include "maddy/emphasizedparser.h"
|
||||
#include "maddy/imageparser.h"
|
||||
#include "maddy/inlinecodeparser.h"
|
||||
#include "maddy/italicparser.h"
|
||||
#include "maddy/linkparser.h"
|
||||
#include "maddy/strikethroughparser.h"
|
||||
#include "maddy/strongparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parser
|
||||
*
|
||||
* Transforms Markdown to HTML
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* Initializes all `LineParser`
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
Parser(std::shared_ptr<ParserConfig> config = nullptr)
|
||||
: config(config)
|
||||
, breakLineParser(std::make_shared<BreakLineParser>())
|
||||
, emphasizedParser(std::make_shared<EmphasizedParser>())
|
||||
, imageParser(std::make_shared<ImageParser>())
|
||||
, inlineCodeParser(std::make_shared<InlineCodeParser>())
|
||||
, italicParser(std::make_shared<ItalicParser>())
|
||||
, linkParser(std::make_shared<LinkParser>())
|
||||
, strikeThroughParser(std::make_shared<StrikeThroughParser>())
|
||||
, strongParser(std::make_shared<StrongParser>())
|
||||
{}
|
||||
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* @method
|
||||
* @param {const std::istream&} markdown
|
||||
* @return {std::string} HTML
|
||||
*/
|
||||
std::string
|
||||
Parse(std::istream& markdown) const
|
||||
{
|
||||
std::string result = "";
|
||||
std::shared_ptr<BlockParser> currentBlockParser = nullptr;
|
||||
|
||||
for (std::string line; std::getline(markdown, line);)
|
||||
{
|
||||
if (!currentBlockParser)
|
||||
{
|
||||
currentBlockParser = getBlockParserForLine(line);
|
||||
}
|
||||
|
||||
if (currentBlockParser)
|
||||
{
|
||||
currentBlockParser->AddLine(line);
|
||||
|
||||
if (currentBlockParser->IsFinished())
|
||||
{
|
||||
result += currentBlockParser->GetResult().str();
|
||||
currentBlockParser = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure, that all parsers are finished
|
||||
if (currentBlockParser)
|
||||
{
|
||||
std::string emptyLine = "";
|
||||
currentBlockParser->AddLine(emptyLine);
|
||||
if (currentBlockParser->IsFinished())
|
||||
{
|
||||
result += currentBlockParser->GetResult().str();
|
||||
currentBlockParser = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<ParserConfig> config;
|
||||
std::shared_ptr<BreakLineParser> breakLineParser;
|
||||
std::shared_ptr<EmphasizedParser> emphasizedParser;
|
||||
std::shared_ptr<ImageParser> imageParser;
|
||||
std::shared_ptr<InlineCodeParser> inlineCodeParser;
|
||||
std::shared_ptr<ItalicParser> italicParser;
|
||||
std::shared_ptr<LinkParser> linkParser;
|
||||
std::shared_ptr<StrikeThroughParser> strikeThroughParser;
|
||||
std::shared_ptr<StrongParser> strongParser;
|
||||
|
||||
// block parser have to run before
|
||||
void
|
||||
runLineParser(std::string& line) const
|
||||
{
|
||||
// Attention! ImageParser has to be before LinkParser
|
||||
this->imageParser->Parse(line);
|
||||
this->linkParser->Parse(line);
|
||||
|
||||
// Attention! StrongParser has to be before EmphasizedParser
|
||||
this->strongParser->Parse(line);
|
||||
|
||||
if (!this->config || this->config->isEmphasizedParserEnabled)
|
||||
{
|
||||
this->emphasizedParser->Parse(line);
|
||||
}
|
||||
|
||||
this->strikeThroughParser->Parse(line);
|
||||
|
||||
this->inlineCodeParser->Parse(line);
|
||||
|
||||
this->italicParser->Parse(line);
|
||||
|
||||
this->breakLineParser->Parse(line);
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockParser>
|
||||
getBlockParserForLine(const std::string& line) const
|
||||
{
|
||||
std::shared_ptr<BlockParser> parser;
|
||||
|
||||
if (maddy::CodeBlockParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::CodeBlockParser>(
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
else if (maddy::HeadlineParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::HeadlineParser>(
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
else if (maddy::HorizontalLineParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::HorizontalLineParser>(
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
else if (maddy::QuoteParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::QuoteParser>(
|
||||
[this](std::string& line){ this->runLineParser(line); },
|
||||
[this](const std::string& line){ return this->getBlockParserForLine(line); }
|
||||
);
|
||||
}
|
||||
else if (maddy::TableParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::TableParser>(
|
||||
[this](std::string& line){ this->runLineParser(line); },
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
else if (maddy::ChecklistParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createChecklistParser();
|
||||
}
|
||||
else if (maddy::OrderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createOrderedListParser();
|
||||
}
|
||||
else if (maddy::UnorderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createUnorderedListParser();
|
||||
}
|
||||
else if (
|
||||
this->config &&
|
||||
!this->config->isHTMLWrappedInParagraph &&
|
||||
maddy::HtmlParser::IsStartingLine(line)
|
||||
)
|
||||
{
|
||||
parser = std::make_shared<maddy::HtmlParser>(nullptr, nullptr);
|
||||
}
|
||||
else if (maddy::ParagraphParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::ParagraphParser>(
|
||||
[this](std::string& line){ this->runLineParser(line); },
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockParser>
|
||||
createChecklistParser() const
|
||||
{
|
||||
return std::make_shared<maddy::ChecklistParser>(
|
||||
[this](std::string& line){ this->runLineParser(line); },
|
||||
[this](const std::string& line)
|
||||
{
|
||||
std::shared_ptr<BlockParser> parser;
|
||||
|
||||
if (maddy::ChecklistParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createChecklistParser();
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockParser>
|
||||
createOrderedListParser() const
|
||||
{
|
||||
return std::make_shared<maddy::OrderedListParser>(
|
||||
[this](std::string& line){ this->runLineParser(line); },
|
||||
[this](const std::string& line)
|
||||
{
|
||||
std::shared_ptr<BlockParser> parser;
|
||||
|
||||
if (maddy::OrderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createOrderedListParser();
|
||||
}
|
||||
else if (maddy::UnorderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createUnorderedListParser();
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockParser>
|
||||
createUnorderedListParser() const
|
||||
{
|
||||
return std::make_shared<maddy::UnorderedListParser>(
|
||||
[this](std::string& line){ this->runLineParser(line); },
|
||||
[this](const std::string& line)
|
||||
{
|
||||
std::shared_ptr<BlockParser> parser;
|
||||
|
||||
if (maddy::OrderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createOrderedListParser();
|
||||
}
|
||||
else if (maddy::UnorderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createUnorderedListParser();
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
);
|
||||
}
|
||||
}; // class Parser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
31
libs/maddy/parserconfig.h
Normal file
31
libs/maddy/parserconfig.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ParserConfig
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
struct ParserConfig
|
||||
{
|
||||
bool isEmphasizedParserEnabled;
|
||||
bool isHTMLWrappedInParagraph;
|
||||
|
||||
ParserConfig()
|
||||
: isEmphasizedParserEnabled(true)
|
||||
, isHTMLWrappedInParagraph(true)
|
||||
{}
|
||||
}; // class ParserConfig
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
165
libs/maddy/quoteparser.h
Normal file
165
libs/maddy/quoteparser.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* QuoteParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class QuoteParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
QuoteParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* A quote starts with `> `.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::regex re("^\\>.*");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
|
||||
/**
|
||||
* AddLine
|
||||
*
|
||||
* Adding a line which has to be parsed.
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
AddLine(std::string& line) override
|
||||
{
|
||||
if (!this->isStarted)
|
||||
{
|
||||
this->result << "<blockquote>";
|
||||
this->isStarted = true;
|
||||
}
|
||||
|
||||
bool finish = false;
|
||||
if (line.empty())
|
||||
{
|
||||
finish = true;
|
||||
}
|
||||
|
||||
this->parseBlock(line);
|
||||
|
||||
if (this->isInlineBlockAllowed() && !this->childParser)
|
||||
{
|
||||
this->childParser = this->getBlockParserForLine(line);
|
||||
}
|
||||
|
||||
if (this->childParser)
|
||||
{
|
||||
this->childParser->AddLine(line);
|
||||
|
||||
if (this->childParser->IsFinished())
|
||||
{
|
||||
this->result << this->childParser->GetResult().str();
|
||||
this->childParser = nullptr;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->isLineParserAllowed())
|
||||
{
|
||||
this->parseLine(line);
|
||||
}
|
||||
|
||||
if (finish)
|
||||
{
|
||||
this->result << "</blockquote>";
|
||||
this->isFinished = true;
|
||||
}
|
||||
|
||||
this->result << line;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return this->isFinished;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string& line) override
|
||||
{
|
||||
static std::regex lineRegexWithSpace("^\\> ");
|
||||
line = std::regex_replace(line, lineRegexWithSpace, "");
|
||||
static std::regex lineRegexWithoutSpace("^\\>");
|
||||
line = std::regex_replace(line, lineRegexWithoutSpace, "");
|
||||
|
||||
if (!line.empty())
|
||||
{
|
||||
line += " ";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
}; // class QuoteParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
51
libs/maddy/strikethroughparser.h
Normal file
51
libs/maddy/strikethroughparser.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* StrikeThroughParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class StrikeThroughParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `text ~~text~~`
|
||||
*
|
||||
* To HTML: `text <s>text</s>`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
static std::regex re("(?!.*`.*|.*<code>.*)\\~\\~(?!.*`.*|.*<\\/code>.*)([^\\~]*)\\~\\~(?!.*`.*|.*<\\/code>.*)");
|
||||
static std::string replacement = "<s>$1</s>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class StrikeThroughParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
59
libs/maddy/strongparser.h
Normal file
59
libs/maddy/strongparser.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* StrongParser
|
||||
*
|
||||
* Has to be used before the `EmphasizedParser`.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class StrongParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: `text **text** __text__`
|
||||
*
|
||||
* To HTML: `text <strong>text</strong> <strong>text</strong>`
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line The line to interpret
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
Parse(std::string& line) override
|
||||
{
|
||||
static std::vector<std::regex> res
|
||||
{
|
||||
std::regex{"(?!.*`.*|.*<code>.*)\\*\\*(?!.*`.*|.*<\\/code>.*)([^\\*\\*]*)\\*\\*(?!.*`.*|.*<\\/code>.*)"},
|
||||
std::regex{"(?!.*`.*|.*<code>.*)__(?!.*`.*|.*<\\/code>.*)([^__]*)__(?!.*`.*|.*<\\/code>.*)"}
|
||||
};
|
||||
static std::string replacement = "<strong>$1</strong>";
|
||||
for (const auto& re : res)
|
||||
{
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}
|
||||
}; // class StrongParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
246
libs/maddy/tableparser.h
Normal file
246
libs/maddy/tableparser.h
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* TableParser
|
||||
*
|
||||
* For more information, see the docs folder.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class TableParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
TableParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
, currentBlock(0)
|
||||
, currentRow(0)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* If the line has exact `|table>`, then it is starting the table.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::string matchString("|table>");
|
||||
return line == matchString;
|
||||
}
|
||||
|
||||
/**
|
||||
* AddLine
|
||||
*
|
||||
* Adding a line which has to be parsed.
|
||||
*
|
||||
* @method
|
||||
* @param {std::string&} line
|
||||
* @return {void}
|
||||
*/
|
||||
void
|
||||
AddLine(std::string& line) override
|
||||
{
|
||||
if (!this->isStarted && line == "|table>")
|
||||
{
|
||||
this->isStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->isStarted)
|
||||
{
|
||||
if (line == "- | - | -")
|
||||
{
|
||||
++this->currentBlock;
|
||||
this->currentRow = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (line == "|<table")
|
||||
{
|
||||
static std::string emptyLine = "";
|
||||
this->parseBlock(emptyLine);
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->table.size() < this->currentBlock + 1)
|
||||
{
|
||||
this->table.push_back(std::vector<std::vector<std::string>>());
|
||||
}
|
||||
this->table[this->currentBlock].push_back(std::vector<std::string>());
|
||||
|
||||
std::string segment;
|
||||
std::stringstream streamToSplit(line);
|
||||
|
||||
while (std::getline(streamToSplit, segment, '|'))
|
||||
{
|
||||
this->parseLine(segment);
|
||||
this->table[this->currentBlock][this->currentRow].push_back(segment);
|
||||
}
|
||||
|
||||
++this->currentRow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* A table ends with `|<table`.
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return this->isFinished;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string&) override
|
||||
{
|
||||
result << "<table>";
|
||||
|
||||
bool hasHeader = false;
|
||||
bool hasFooter = false;
|
||||
bool isFirstBlock = true;
|
||||
uint32_t currentBlockNumber = 0;
|
||||
|
||||
if (this->table.size() > 1)
|
||||
{
|
||||
hasHeader = true;
|
||||
}
|
||||
|
||||
if (this->table.size() >= 3)
|
||||
{
|
||||
hasFooter = true;
|
||||
}
|
||||
|
||||
for (const std::vector<std::vector<std::string>>& block : this->table)
|
||||
{
|
||||
bool isInHeader = false;
|
||||
bool isInFooter = false;
|
||||
++currentBlockNumber;
|
||||
|
||||
if (hasHeader && isFirstBlock)
|
||||
{
|
||||
result << "<thead>";
|
||||
isInHeader = true;
|
||||
}
|
||||
else if (hasFooter && currentBlockNumber == this->table.size())
|
||||
{
|
||||
result << "<tfoot>";
|
||||
isInFooter = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result << "<tbody>";
|
||||
}
|
||||
|
||||
for (const std::vector<std::string>& row : block)
|
||||
{
|
||||
result << "<tr>";
|
||||
|
||||
for (const std::string& column : row)
|
||||
{
|
||||
if (isInHeader)
|
||||
{
|
||||
result << "<th>";
|
||||
}
|
||||
else
|
||||
{
|
||||
result << "<td>";
|
||||
}
|
||||
|
||||
result << column;
|
||||
|
||||
if (isInHeader)
|
||||
{
|
||||
result << "</th>";
|
||||
}
|
||||
else
|
||||
{
|
||||
result << "</td>";
|
||||
}
|
||||
}
|
||||
|
||||
result << "</tr>";
|
||||
}
|
||||
|
||||
if (isInHeader)
|
||||
{
|
||||
result << "</thead>";
|
||||
}
|
||||
else if (isInFooter)
|
||||
{
|
||||
result << "</tfoot>";
|
||||
}
|
||||
else
|
||||
{
|
||||
result << "</tbody>";
|
||||
}
|
||||
|
||||
isFirstBlock = false;
|
||||
}
|
||||
|
||||
result << "</table>";
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
uint32_t currentBlock;
|
||||
uint32_t currentRow;
|
||||
std::vector<std::vector<std::vector<std::string>>> table;
|
||||
}; // class TableParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
133
libs/maddy/unorderedlistparser.h
Normal file
133
libs/maddy/unorderedlistparser.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/blockparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* UnorderedListParser
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class UnorderedListParser : public BlockParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* @method
|
||||
* @param {std::function<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string& line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
UnorderedListParser(
|
||||
std::function<void(std::string&)> parseLineCallback,
|
||||
std::function<std::shared_ptr<BlockParser>(const std::string& line)> getBlockParserForLineCallback
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* IsStartingLine
|
||||
*
|
||||
* An unordered list starts with `* `.
|
||||
*
|
||||
* @method
|
||||
* @param {const std::string&} line
|
||||
* @return {bool}
|
||||
*/
|
||||
static bool
|
||||
IsStartingLine(const std::string& line)
|
||||
{
|
||||
static std::regex re("^[+*-] .*");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
|
||||
/**
|
||||
* IsFinished
|
||||
*
|
||||
* @method
|
||||
* @return {bool}
|
||||
*/
|
||||
bool
|
||||
IsFinished() const override
|
||||
{
|
||||
return this->isFinished;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool
|
||||
isInlineBlockAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
isLineParserAllowed() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
parseBlock(std::string& line) override
|
||||
{
|
||||
bool isStartOfNewListItem = IsStartingLine(line);
|
||||
uint32_t indentation = getIndentationWidth(line);
|
||||
|
||||
static std::regex lineRegex("^([+*-] )");
|
||||
line = std::regex_replace(line, lineRegex, "");
|
||||
|
||||
if (!this->isStarted)
|
||||
{
|
||||
line = "<ul><li>" + line;
|
||||
this->isStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (indentation >= 2)
|
||||
{
|
||||
line = line.substr(2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
line.empty() ||
|
||||
line.find("</li><li>") != std::string::npos ||
|
||||
line.find("</li></ol>") != std::string::npos ||
|
||||
line.find("</li></ul>") != std::string::npos
|
||||
)
|
||||
{
|
||||
line = "</li></ul>" + line;
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isStartOfNewListItem)
|
||||
{
|
||||
line = "</li><li>" + line;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
}; // class UnorderedListParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
@ -73,7 +73,7 @@ void ListPage::load() {
|
||||
fclose(f);
|
||||
|
||||
Utils::newline_to_br(&fd);
|
||||
Utils::bbcode_evaluate_simple(&fd);
|
||||
Utils::markdown_to_html(&fd);
|
||||
|
||||
list_entries.push_back(fd);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user