Compare commits
5 Commits
v2.1.0
...
v3.0.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
| c4d74bb22b | |||
| f99ab4741b | |||
| b014daad7e | |||
|
|
73363bf12c | ||
|
|
ff4ebbc82f |
0
Info.plist
Executable file → Normal file
0
Info.plist
Executable file → Normal file
@@ -5,8 +5,13 @@ Wrote with Qt 6 Open Source : [Download](https://www.qt.io/download-open-source)
|
||||
This is a very simple note editor. The editor has a Markdown text area and a rendering view
|
||||
|
||||
## Prepare to use on linux
|
||||
You need to install Qt 6 dependencies
|
||||
You need to install Qt 6.2.4 dependencies
|
||||
|
||||
```sh
|
||||
sudo apt install libqt6widgets6 libqt6gui6 libqt6core5compat6 libqt6core5compat6 libqt6core6 libqt6dbus6
|
||||
sudo apt install libxcb1 libxcb-xinerama0 libqt6widgets6 libqt6gui6 libqt6core5compat6 libqt6core5compat6 libqt6core6 libqt6dbus6 qt6-qpa-plugins
|
||||
```
|
||||
### To run on Wayland
|
||||
|
||||
```sh
|
||||
sudo apt install qt6-wayland
|
||||
```
|
||||
|
||||
13
WorkPad.pro
Executable file → Normal file
13
WorkPad.pro
Executable file → Normal file
@@ -1,13 +1,13 @@
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += widgets
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += widgets webenginewidgets
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
win32:VERSION = 2.1.0.0 # major.minor.patch.build
|
||||
else:VERSION = 2.1.0 # major.minor.patch
|
||||
win32:VERSION = 3.0.0.0 # major.minor.patch.build
|
||||
else:VERSION = 3.0.0 # major.minor.patch
|
||||
|
||||
DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\"
|
||||
DEFINES += APP_VERSION=\"\\\"$${VERSION}-rc2\\\"\"
|
||||
DEFINES += APP_NAME=\"\\\"WorkPad\\\"\"
|
||||
|
||||
# remove possible other optimization flags
|
||||
@@ -83,6 +83,8 @@ SOURCES += \
|
||||
src/services/savemanager.cpp
|
||||
|
||||
HEADERS += \
|
||||
maddy/parserconfig.h \
|
||||
maddy/parser.h \
|
||||
src/frames/configdialog.h \
|
||||
src/services/configmanager.h \
|
||||
src/frames/exportdialog.h \
|
||||
@@ -109,4 +111,5 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
RESOURCES += \
|
||||
icons.qrc
|
||||
icons.qrc \
|
||||
static.qrc
|
||||
|
||||
0
icon.ico
Executable file → Normal file
0
icon.ico
Executable file → Normal file
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
192
maddy/blockparser.h
Normal file
192
maddy/blockparser.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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 <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
50
maddy/breaklineparser.h
Normal file
50
maddy/breaklineparser.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 <regex>
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
127
maddy/checklistparser.h
Normal file
127
maddy/checklistparser.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 <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(R"(^- \[[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(R"(^\[ \])");
|
||||
static std::string emptyBoxReplacement = "<input type=\"checkbox\"/>";
|
||||
line = std::regex_replace(line, emptyBoxRegex, emptyBoxReplacement);
|
||||
|
||||
static std::regex boxRegex(R"(^\[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
|
||||
132
maddy/codeblockparser.h
Normal file
132
maddy/codeblockparser.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
else if (!this->isStarted && line.substr(0, 3) == "```")
|
||||
{
|
||||
line = "<pre class=\"" + line.substr(3) + "\"><code>\n";
|
||||
this->isStarted = true;
|
||||
this->isFinished = false;
|
||||
return;
|
||||
}
|
||||
|
||||
line += "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
}; // class CodeBlockParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
54
maddy/emphasizedparser.h
Normal file
54
maddy/emphasizedparser.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#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(
|
||||
R"((?!.*`.*|.*<code>.*)_(?!.*`.*|.*<\/code>.*)([^_]*)_(?!.*`.*|.*<\/code>.*))"
|
||||
);
|
||||
static std::string replacement = "<em>$1</em>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class EmphasizedParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
134
maddy/headlineparser.h
Normal file
134
maddy/headlineparser.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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,
|
||||
bool isInlineParserAllowed = true
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isInlineParserAllowed(isInlineParserAllowed)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 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 this->isInlineParserAllowed;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isInlineParserAllowed;
|
||||
}; // class HeadlineParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
94
maddy/horizontallineparser.h
Normal file
94
maddy/horizontallineparser.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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
|
||||
112
maddy/htmlparser.h
Normal file
112
maddy/htmlparser.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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
|
||||
52
maddy/imageparser.h
Normal file
52
maddy/imageparser.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "maddy/lineparser.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ImageParser
|
||||
*
|
||||
* Has to be used before the `LinkParser`.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
class ImageParser : public LineParser
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Parse
|
||||
*
|
||||
* From Markdown: ``
|
||||
*
|
||||
* 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(R"(\!\[([^\]]*)\]\(([^\]]*)\))");
|
||||
static std::string replacement = "<img src=\"$2\" alt=\"$1\"/>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class ImageParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
50
maddy/inlinecodeparser.h
Normal file
50
maddy/inlinecodeparser.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 <regex>
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
51
maddy/italicparser.h
Normal file
51
maddy/italicparser.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 <regex>
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
{
|
||||
static std::regex re(
|
||||
R"((?!.*`.*|.*<code>.*)\*(?!.*`.*|.*<\/code>.*)([^\*]*)\*(?!.*`.*|.*<\/code>.*))"
|
||||
);
|
||||
static std::string replacement = "<i>$1</i>";
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class ItalicParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
124
maddy/latexblockparser.h
Normal file
124
maddy/latexblockparser.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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<void(std::string&)>} parseLineCallback
|
||||
* @param {std::function<std::shared_ptr<BlockParser>(const std::string&
|
||||
* line)>} getBlockParserForLineCallback
|
||||
*/
|
||||
LatexBlockParser(
|
||||
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 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(R"(^(?:\$){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
|
||||
46
maddy/lineparser.h
Normal file
46
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
|
||||
52
maddy/linkparser.h
Normal file
52
maddy/linkparser.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#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(R"(\[([^\]]*)\]\(([^\]]*)\))");
|
||||
static std::string replacement = "<a href=\"$2\">$1</a>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class LinkParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
126
maddy/orderedlistparser.h
Normal file
126
maddy/orderedlistparser.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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(R"(^[1-9]+[0-9]*\. )");
|
||||
line = std::regex_replace(line, orderedlineRegex, "");
|
||||
static std::regex unorderedlineRegex(R"(^\* )");
|
||||
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(R"(^(?:[1-9]+[0-9]*\. |\* ).*)");
|
||||
return std::regex_match(line, re);
|
||||
}
|
||||
}; // class OrderedListParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
115
maddy/paragraphparser.h
Normal file
115
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,
|
||||
bool isEnabled
|
||||
)
|
||||
: BlockParser(parseLineCallback, getBlockParserForLineCallback)
|
||||
, isStarted(false)
|
||||
, isFinished(false)
|
||||
, isEnabled(isEnabled)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 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->isEnabled && !this->isStarted)
|
||||
{
|
||||
line = "<p>" + line + " ";
|
||||
this->isStarted = true;
|
||||
return;
|
||||
}
|
||||
else if (!this->isEnabled && !this->isStarted)
|
||||
{
|
||||
line += " ";
|
||||
this->isStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->isEnabled && line.empty())
|
||||
{
|
||||
line += "</p>";
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
else if (!this->isEnabled && line.empty())
|
||||
{
|
||||
line += "<br/>";
|
||||
this->isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
line += " ";
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
bool isEnabled;
|
||||
}; // class ParagraphParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
412
maddy/parser.h
Normal file
412
maddy/parser.h
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#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/latexblockparser.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:
|
||||
/**
|
||||
* Version info
|
||||
*
|
||||
* Check https://github.com/progsource/maddy/blob/master/CHANGELOG.md
|
||||
* for the changelog.
|
||||
*/
|
||||
static const std::string& version()
|
||||
{
|
||||
static const std::string v = "1.3.0";
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* ctor
|
||||
*
|
||||
* Initializes all `LineParser`
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
Parser(std::shared_ptr<ParserConfig> config = nullptr) : config(config)
|
||||
{
|
||||
// deprecated backward compatibility
|
||||
// will be removed in 1.4.0 latest including the booleans
|
||||
if (this->config && !this->config->isEmphasizedParserEnabled)
|
||||
{
|
||||
this->config->enabledParsers &= ~maddy::types::EMPHASIZED_PARSER;
|
||||
}
|
||||
if (this->config && !this->config->isHTMLWrappedInParagraph)
|
||||
{
|
||||
this->config->enabledParsers |= maddy::types::HTML_PARSER;
|
||||
}
|
||||
|
||||
if (!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::BREAKLINE_PARSER) != 0)
|
||||
{
|
||||
this->breakLineParser = std::make_shared<BreakLineParser>();
|
||||
}
|
||||
|
||||
if (!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::EMPHASIZED_PARSER) != 0)
|
||||
{
|
||||
this->emphasizedParser = std::make_shared<EmphasizedParser>();
|
||||
}
|
||||
|
||||
if (!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::IMAGE_PARSER) != 0)
|
||||
{
|
||||
this->imageParser = std::make_shared<ImageParser>();
|
||||
}
|
||||
|
||||
if (!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::INLINE_CODE_PARSER) != 0)
|
||||
{
|
||||
this->inlineCodeParser = std::make_shared<InlineCodeParser>();
|
||||
}
|
||||
|
||||
if (!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::ITALIC_PARSER) != 0)
|
||||
{
|
||||
this->italicParser = std::make_shared<ItalicParser>();
|
||||
}
|
||||
|
||||
if (!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::LINK_PARSER) != 0)
|
||||
{
|
||||
this->linkParser = std::make_shared<LinkParser>();
|
||||
}
|
||||
|
||||
if (!this->config || (this->config->enabledParsers &
|
||||
maddy::types::STRIKETHROUGH_PARSER) != 0)
|
||||
{
|
||||
this->strikeThroughParser = std::make_shared<StrikeThroughParser>();
|
||||
}
|
||||
|
||||
if (!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::STRONG_PARSER) != 0)
|
||||
{
|
||||
this->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
|
||||
if (this->imageParser)
|
||||
{
|
||||
this->imageParser->Parse(line);
|
||||
}
|
||||
|
||||
if (this->linkParser)
|
||||
{
|
||||
this->linkParser->Parse(line);
|
||||
}
|
||||
|
||||
// Attention! StrongParser has to be before EmphasizedParser
|
||||
if (this->strongParser)
|
||||
{
|
||||
this->strongParser->Parse(line);
|
||||
}
|
||||
|
||||
if (this->emphasizedParser)
|
||||
{
|
||||
this->emphasizedParser->Parse(line);
|
||||
}
|
||||
|
||||
if (this->strikeThroughParser)
|
||||
{
|
||||
this->strikeThroughParser->Parse(line);
|
||||
}
|
||||
|
||||
if (this->inlineCodeParser)
|
||||
{
|
||||
this->inlineCodeParser->Parse(line);
|
||||
}
|
||||
|
||||
if (this->italicParser)
|
||||
{
|
||||
this->italicParser->Parse(line);
|
||||
}
|
||||
|
||||
if (this->breakLineParser)
|
||||
{
|
||||
this->breakLineParser->Parse(line);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockParser> getBlockParserForLine(const std::string& line
|
||||
) const
|
||||
{
|
||||
std::shared_ptr<BlockParser> parser;
|
||||
|
||||
if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::CODE_BLOCK_PARSER) != 0) &&
|
||||
maddy::CodeBlockParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::CodeBlockParser>(nullptr, nullptr);
|
||||
}
|
||||
else if (this->config &&
|
||||
(this->config->enabledParsers & maddy::types::LATEX_BLOCK_PARSER
|
||||
) != 0 &&
|
||||
maddy::LatexBlockParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<LatexBlockParser>(nullptr, nullptr);
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::HEADLINE_PARSER) != 0) &&
|
||||
maddy::HeadlineParser::IsStartingLine(line))
|
||||
{
|
||||
if (!this->config || this->config->isHeadlineInlineParsingEnabled)
|
||||
{
|
||||
parser = std::make_shared<maddy::HeadlineParser>(
|
||||
[this](std::string& line) { this->runLineParser(line); },
|
||||
nullptr,
|
||||
true
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser =
|
||||
std::make_shared<maddy::HeadlineParser>(nullptr, nullptr, false);
|
||||
}
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::HORIZONTAL_LINE_PARSER) != 0) &&
|
||||
maddy::HorizontalLineParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::HorizontalLineParser>(nullptr, nullptr);
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::QUOTE_PARSER) != 0) &&
|
||||
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 ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::TABLE_PARSER) != 0) &&
|
||||
maddy::TableParser::IsStartingLine(line))
|
||||
{
|
||||
parser = std::make_shared<maddy::TableParser>(
|
||||
[this](std::string& line) { this->runLineParser(line); }, nullptr
|
||||
);
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::CHECKLIST_PARSER) != 0) &&
|
||||
maddy::ChecklistParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createChecklistParser();
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::ORDERED_LIST_PARSER) != 0) &&
|
||||
maddy::OrderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createOrderedListParser();
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::UNORDERED_LIST_PARSER) != 0) &&
|
||||
maddy::UnorderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createUnorderedListParser();
|
||||
}
|
||||
else if (this->config &&
|
||||
(this->config->enabledParsers & maddy::types::HTML_PARSER) != 0 &&
|
||||
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,
|
||||
(!this->config ||
|
||||
(this->config->enabledParsers & maddy::types::PARAGRAPH_PARSER) != 0)
|
||||
);
|
||||
}
|
||||
|
||||
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 ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::CHECKLIST_PARSER) != 0) &&
|
||||
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 ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::ORDERED_LIST_PARSER) != 0) &&
|
||||
maddy::OrderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createOrderedListParser();
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::UNORDERED_LIST_PARSER) != 0
|
||||
) &&
|
||||
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 ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::ORDERED_LIST_PARSER) != 0) &&
|
||||
maddy::OrderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createOrderedListParser();
|
||||
}
|
||||
else if ((!this->config || (this->config->enabledParsers &
|
||||
maddy::types::UNORDERED_LIST_PARSER) != 0
|
||||
) &&
|
||||
maddy::UnorderedListParser::IsStartingLine(line))
|
||||
{
|
||||
parser = this->createUnorderedListParser();
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
);
|
||||
}
|
||||
}; // class Parser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
97
maddy/parserconfig.h
Normal file
97
maddy/parserconfig.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace maddy {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace types {
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* PARSER_TYPE
|
||||
*
|
||||
* Bitwise flags to turn on/off each parser
|
||||
*/
|
||||
enum PARSER_TYPE : uint32_t
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
BREAKLINE_PARSER = 0b1,
|
||||
CHECKLIST_PARSER = 0b10,
|
||||
CODE_BLOCK_PARSER = 0b100,
|
||||
EMPHASIZED_PARSER = 0b1000,
|
||||
HEADLINE_PARSER = 0b10000,
|
||||
HORIZONTAL_LINE_PARSER = 0b100000,
|
||||
HTML_PARSER = 0b1000000,
|
||||
IMAGE_PARSER = 0b10000000,
|
||||
INLINE_CODE_PARSER = 0b100000000,
|
||||
ITALIC_PARSER = 0b1000000000,
|
||||
LINK_PARSER = 0b10000000000,
|
||||
ORDERED_LIST_PARSER = 0b100000000000,
|
||||
PARAGRAPH_PARSER = 0b1000000000000,
|
||||
QUOTE_PARSER = 0b10000000000000,
|
||||
STRIKETHROUGH_PARSER = 0b100000000000000,
|
||||
STRONG_PARSER = 0b1000000000000000,
|
||||
TABLE_PARSER = 0b10000000000000000,
|
||||
UNORDERED_LIST_PARSER = 0b100000000000000000,
|
||||
LATEX_BLOCK_PARSER = 0b1000000000000000000,
|
||||
|
||||
DEFAULT = 0b0111111111110111111,
|
||||
ALL = 0b1111111111111111111,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
} // namespace types
|
||||
|
||||
/**
|
||||
* ParserConfig
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
struct ParserConfig
|
||||
{
|
||||
/**
|
||||
* @deprecated will be removed in 1.4.0 latest
|
||||
*
|
||||
* this flag = false == `enabledParsers &= ~maddy::types::EMPHASIZED_PARSER`
|
||||
*/
|
||||
bool isEmphasizedParserEnabled;
|
||||
|
||||
/**
|
||||
* @deprecated will be removed in 1.4.0 latest
|
||||
*
|
||||
* this flag = false == `enabledParsers |= maddy::types::HTML_PARSER`
|
||||
*/
|
||||
bool isHTMLWrappedInParagraph;
|
||||
|
||||
/**
|
||||
* en-/disable headline inline-parsing
|
||||
*
|
||||
* default: enabled
|
||||
*/
|
||||
bool isHeadlineInlineParsingEnabled;
|
||||
|
||||
/**
|
||||
* enabled parsers bitfield
|
||||
*/
|
||||
uint32_t enabledParsers;
|
||||
|
||||
ParserConfig()
|
||||
: isEmphasizedParserEnabled(true)
|
||||
, isHTMLWrappedInParagraph(true)
|
||||
, isHeadlineInlineParsingEnabled(true)
|
||||
, enabledParsers(maddy::types::DEFAULT)
|
||||
{}
|
||||
}; // class ParserConfig
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
152
maddy/quoteparser.h
Normal file
152
maddy/quoteparser.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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(R"(^\>.*)");
|
||||
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(R"(^\> )");
|
||||
line = std::regex_replace(line, lineRegexWithSpace, "");
|
||||
static std::regex lineRegexWithoutSpace(R"(^\>)");
|
||||
line = std::regex_replace(line, lineRegexWithoutSpace, "");
|
||||
|
||||
if (!line.empty())
|
||||
{
|
||||
line += " ";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStarted;
|
||||
bool isFinished;
|
||||
}; // class QuoteParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
52
maddy/strikethroughparser.h
Normal file
52
maddy/strikethroughparser.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#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(
|
||||
R"((?!.*`.*|.*<code>.*)\~\~(?!.*`.*|.*<\/code>.*)([^\~]*)\~\~(?!.*`.*|.*<\/code>.*))"
|
||||
);
|
||||
static std::string replacement = "<s>$1</s>";
|
||||
|
||||
line = std::regex_replace(line, re, replacement);
|
||||
}
|
||||
}; // class StrikeThroughParser
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
} // namespace maddy
|
||||
61
maddy/strongparser.h
Normal file
61
maddy/strongparser.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This project is licensed under the MIT license. For more information see the
|
||||
* LICENSE file.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#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{
|
||||
R"((?!.*`.*|.*<code>.*)\*\*(?!.*`.*|.*<\/code>.*)([^\*\*]*)\*\*(?!.*`.*|.*<\/code>.*))"
|
||||
},
|
||||
std::regex{
|
||||
R"((?!.*`.*|.*<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
|
||||
233
maddy/tableparser.h
Normal file
233
maddy/tableparser.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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 {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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
|
||||
118
maddy/unorderedlistparser.h
Normal file
118
maddy/unorderedlistparser.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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
|
||||
0
resources/logo.png
Executable file → Normal file
0
resources/logo.png
Executable file → Normal file
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
1105
resources/style.css
Normal file
1105
resources/style.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -95,7 +95,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_6">
|
||||
@@ -121,7 +121,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QSpinBox" name="autoSaveDelaySpinbox">
|
||||
@@ -161,7 +161,7 @@
|
||||
<string>Author: Aurélie Delhaie (github.com/mojitaurelie)</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="versionLabel">
|
||||
@@ -177,7 +177,7 @@
|
||||
<string>Version 1.2.0.0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="appNameLabel">
|
||||
@@ -198,7 +198,7 @@
|
||||
<string>WorkPad</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label">
|
||||
@@ -217,7 +217,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_5">
|
||||
@@ -233,7 +233,7 @@
|
||||
<string><html><head/><body><p>Under MIT license</p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||
@@ -249,7 +249,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="plainText">
|
||||
<string>Copyright 2022 Aurélie Delhaie
|
||||
<string>Copyright 2025 Aurélie Delhaie
|
||||
|
||||
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:
|
||||
|
||||
@@ -270,7 +270,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRES
|
||||
</rect>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
|
||||
@@ -19,5 +19,9 @@ int ExportDialog::getResult()
|
||||
{
|
||||
return MARKDOWN;
|
||||
}
|
||||
else if (ui->pdfRadio->isChecked())
|
||||
{
|
||||
return PDF;
|
||||
}
|
||||
return PLAIN;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#define MARKDOWN 1
|
||||
#define PLAIN 2
|
||||
#define PDF 3
|
||||
|
||||
namespace Ui {
|
||||
class ExportDialog;
|
||||
|
||||
@@ -35,10 +35,10 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QRadioButton" name="markdownButton">
|
||||
@@ -61,7 +61,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>60</y>
|
||||
<y>40</y>
|
||||
<width>92</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
@@ -70,6 +70,19 @@
|
||||
<string>Text file</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QRadioButton" name="pdfRadio">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>60</y>
|
||||
<width>92</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PDF file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
||||
90
src/frames/mainwindow.cpp
Executable file → Normal file
90
src/frames/mainwindow.cpp
Executable file → Normal file
@@ -7,12 +7,22 @@
|
||||
#include "renamedialog.h"
|
||||
#include "exportdialog.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
timer = new QTimer(this);
|
||||
parser = std::make_shared<maddy::Parser>();
|
||||
|
||||
// open stylesheet resource
|
||||
QFile f(":/css/resources/style.css");
|
||||
f.open(QFile::OpenModeFlag::ReadOnly);
|
||||
style = f.readAll();
|
||||
f.close();
|
||||
|
||||
connect(ui->actionAdd_folder, &QAction::triggered, this, &MainWindow::createFolder);
|
||||
connect(ui->actionAdd, &QAction::triggered, this, &MainWindow::createNote);
|
||||
connect(ui->actionSave, &QAction::triggered, this, &MainWindow::save);
|
||||
@@ -21,6 +31,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
connect(ui->plainTextEdit, &QPlainTextEdit::textChanged, this, &MainWindow::plainContentChanged);
|
||||
connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged, this, &MainWindow::selectionChanged);
|
||||
connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, &MainWindow::prepareMenu);
|
||||
connect(this, &MainWindow::updateViewers, this, &MainWindow::viewReady);
|
||||
const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont);
|
||||
ui->contentEdit->setFont(fixedFont);
|
||||
ui->plainTextEdit->setFont(fixedFont);
|
||||
@@ -29,10 +40,39 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
this->cfgmng = new ConfigManager();
|
||||
updateListView();
|
||||
connect(timer, &QTimer::timeout, this, &MainWindow::save);
|
||||
|
||||
// start render thread
|
||||
threaddone = new bool(false);
|
||||
queue = new QVector<QString>;
|
||||
queueMutex = new QMutex();
|
||||
updateViewThread = new std::thread([this](){
|
||||
while (!*threaddone) {
|
||||
queueMutex->lock();
|
||||
if (queue->count() == 0) {
|
||||
queueMutex->unlock();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
continue;
|
||||
}
|
||||
QString content = (*queue)[0];
|
||||
queue->pop_front();
|
||||
queueMutex->unlock();
|
||||
std::stringstream markdownInput(content.toStdString());
|
||||
QString htmlOutput = "<html><body class='markdown-body'>";
|
||||
htmlOutput += QString::fromStdString(parser->Parse(markdownInput));
|
||||
htmlOutput += "</body><style>" + style + "</style></html>";
|
||||
emit updateViewers(htmlOutput);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
*threaddone = true;
|
||||
updateViewThread->join();
|
||||
delete queue;
|
||||
delete queueMutex;
|
||||
delete threaddone;
|
||||
delete updateViewThread;
|
||||
delete timer;
|
||||
delete savemng;
|
||||
delete ui;
|
||||
@@ -100,8 +140,7 @@ void MainWindow::selectionChanged()
|
||||
ui->contentEdit->setDisabled(false);
|
||||
ui->plainTextEdit->setPlainText(n->getContent());
|
||||
ui->contentEdit->setPlainText(n->getContent());
|
||||
ui->markdownViewer->setMarkdown(ui->contentEdit->toPlainText());
|
||||
ui->markdownViewer2->setMarkdown(n->getContent());
|
||||
updateHTMLView();
|
||||
|
||||
ui->plainTextEdit->blockSignals(false);
|
||||
ui->contentEdit->blockSignals(false);
|
||||
@@ -307,6 +346,10 @@ void MainWindow::exportNote()
|
||||
{
|
||||
filter = "Markdown file (*.md)";
|
||||
}
|
||||
else if (fileType == PDF)
|
||||
{
|
||||
filter = "PDF file (*.pdf)";
|
||||
}
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Export note"), "", filter);
|
||||
if (!fileName.isEmpty())
|
||||
{
|
||||
@@ -318,17 +361,37 @@ void MainWindow::exportNote()
|
||||
{
|
||||
fileName += ".txt";
|
||||
}
|
||||
else if (fileType == PDF && !fileName.endsWith(".pdf", Qt::CaseInsensitive))
|
||||
{
|
||||
fileName += ".pdf";
|
||||
}
|
||||
|
||||
if (fileType == PDF)
|
||||
{
|
||||
ui->webEngineViewer->printToPdf(fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
QFile *f = new QFile(fileName);
|
||||
if (f->open(QIODevice::WriteOnly))
|
||||
{
|
||||
|
||||
f->write(n->getContent().toUtf8());
|
||||
f->close();
|
||||
}
|
||||
delete f;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::viewReady(QString html)
|
||||
{
|
||||
ui->webEngineViewer->setHtml(html);
|
||||
ui->webEngineEditor->setHtml(html);
|
||||
}
|
||||
|
||||
void MainWindow::markdownContentChanged()
|
||||
@@ -341,17 +404,11 @@ void MainWindow::markdownContentChanged()
|
||||
QString uuid = ui->treeWidget->selectedItems()[0]->text(COLUMN_UUID);
|
||||
Note *n = savemng->getNoteByUUID(uuid);
|
||||
if (n != nullptr) {
|
||||
QScrollBar *scrollbar = ui->markdownViewer->verticalScrollBar();
|
||||
|
||||
QString content = ui->contentEdit->toPlainText();
|
||||
|
||||
int pos = scrollbar->sliderPosition();
|
||||
ui->markdownViewer->setMarkdown(content);
|
||||
scrollbar->setSliderPosition(pos);
|
||||
|
||||
ui->markdownViewer2->setMarkdown(content);
|
||||
ui->plainTextEdit->setPlainText(content);
|
||||
n->setContent(content);
|
||||
updateHTMLView();
|
||||
}
|
||||
}
|
||||
ui->plainTextEdit->blockSignals(false);
|
||||
@@ -374,10 +431,9 @@ void MainWindow::plainContentChanged()
|
||||
Note *n = savemng->getNoteByUUID(uuid);
|
||||
if (n != nullptr) {
|
||||
QString content = ui->plainTextEdit->toPlainText();
|
||||
ui->markdownViewer->setMarkdown(content);
|
||||
ui->markdownViewer2->setMarkdown(content);
|
||||
ui->contentEdit->setPlainText(content);
|
||||
n->setContent(content);
|
||||
updateHTMLView();
|
||||
}
|
||||
}
|
||||
ui->plainTextEdit->blockSignals(false);
|
||||
@@ -410,6 +466,16 @@ void MainWindow::updateListView()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateHTMLView()
|
||||
{
|
||||
queueMutex->lock();
|
||||
if (queue->count() > 4) {
|
||||
queue->pop_front();
|
||||
}
|
||||
queue->append(ui->plainTextEdit->toPlainText());
|
||||
queueMutex->unlock();
|
||||
}
|
||||
|
||||
void MainWindow::clearAndDisableFields()
|
||||
{
|
||||
ui->contentEdit->blockSignals(true);
|
||||
@@ -420,8 +486,6 @@ void MainWindow::clearAndDisableFields()
|
||||
ui->plainTextEdit->setDisabled(true);
|
||||
ui->plainTextEdit->clear();
|
||||
ui->contentEdit->clear();
|
||||
ui->markdownViewer->clear();
|
||||
ui->markdownViewer2->clear();
|
||||
ui->titleLabel->setText("");
|
||||
this->setWindowTitle("WorkPad");
|
||||
|
||||
|
||||
19
src/frames/mainwindow.h
Executable file → Normal file
19
src/frames/mainwindow.h
Executable file → Normal file
@@ -10,10 +10,15 @@
|
||||
#include <QPoint>
|
||||
#include <QFileDialog>
|
||||
#include <QScrollBar>
|
||||
#include <QMutex>
|
||||
#include <thread>
|
||||
|
||||
#include "../services/savemanager.h"
|
||||
#include "../services/configmanager.h"
|
||||
|
||||
#include "../../maddy/parserconfig.h"
|
||||
#include "../../maddy/parser.h"
|
||||
|
||||
#define COLUMN_NAME 0
|
||||
#define COLUMN_UUID 1
|
||||
#define COLUMN_TYPE 2
|
||||
@@ -33,6 +38,9 @@ public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
signals:
|
||||
void updateViewers(QString html);
|
||||
|
||||
private slots:
|
||||
void createNote();
|
||||
void createFolder();
|
||||
@@ -46,15 +54,26 @@ private slots:
|
||||
void moveNote();
|
||||
void editName();
|
||||
void exportNote();
|
||||
void viewReady(QString html);
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
SaveManager *savemng;
|
||||
ConfigManager *cfgmng;
|
||||
QTimer *timer;
|
||||
std::shared_ptr<maddy::Parser> parser;
|
||||
|
||||
QString style;
|
||||
|
||||
//shared between threads
|
||||
QVector<QString>* queue;
|
||||
QMutex* queueMutex;
|
||||
bool* threaddone;
|
||||
std::thread *updateViewThread;
|
||||
|
||||
void updateListView();
|
||||
void clearAndDisableFields();
|
||||
void selectTreeItem(QString uuid);
|
||||
void updateHTMLView();
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
55
src/frames/mainwindow.ui
Executable file → Normal file
55
src/frames/mainwindow.ui
Executable file → Normal file
@@ -35,7 +35,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="animated">
|
||||
<bool>true</bool>
|
||||
@@ -50,7 +50,7 @@
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -71,10 +71,10 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::South</enum>
|
||||
<enum>QTabWidget::TabPosition::South</enum>
|
||||
</property>
|
||||
<property name="tabShape">
|
||||
<enum>QTabWidget::Rounded</enum>
|
||||
<enum>QTabWidget::TabShape::Rounded</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
@@ -99,7 +99,7 @@
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="contentEdit">
|
||||
<property name="enabled">
|
||||
@@ -117,36 +117,18 @@
|
||||
</font>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
<enum>QPlainTextEdit::LineWrapMode::NoWrap</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="markdownViewer">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWebEngineView" name="webEngineEditor" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<width>400</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoFormatting">
|
||||
<set>QTextEdit::AutoAll</set>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -159,14 +141,7 @@
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTextEdit" name="markdownViewer2">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWebEngineView" name="webEngineViewer" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -189,7 +164,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::PreventContextMenu</enum>
|
||||
<enum>Qt::ContextMenuPolicy::PreventContextMenu</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
@@ -198,7 +173,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextUnderIcon</enum>
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonTextUnderIcon</enum>
|
||||
</property>
|
||||
<property name="floatable">
|
||||
<bool>false</bool>
|
||||
@@ -277,6 +252,14 @@
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebEngineView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qwebengineview.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../icons.qrc"/>
|
||||
</resources>
|
||||
|
||||
0
src/main.cpp
Executable file → Normal file
0
src/main.cpp
Executable file → Normal file
0
src/models/note.cpp
Executable file → Normal file
0
src/models/note.cpp
Executable file → Normal file
0
src/models/note.h
Executable file → Normal file
0
src/models/note.h
Executable file → Normal file
0
src/services/savemanager.cpp
Executable file → Normal file
0
src/services/savemanager.cpp
Executable file → Normal file
0
src/services/savemanager.h
Executable file → Normal file
0
src/services/savemanager.h
Executable file → Normal file
5
static.qrc
Normal file
5
static.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/css">
|
||||
<file>resources/style.css</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Reference in New Issue
Block a user