From 2fe7a71bf328c706e11a8a05724eacf667bf013d Mon Sep 17 00:00:00 2001 From: Petra Baranski Date: Fri, 27 Dec 2019 19:48:29 +0100 Subject: [PATCH] No paragraphs for html (#27) * htmlparser added * Added ParserConfig * added option to disable the emphasized parser * added option to not wrap HTML in markdown within a paragraph in output * Updated docs * Version update 1.1.1 --- README.md | 10 +- docs/definitions.md | 6 ++ include/maddy/htmlparser.h | 127 ++++++++++++++++++++++++++ include/maddy/paragraphparser.h | 5 +- include/maddy/parser.h | 23 ++++- include/maddy/parserconfig.h | 31 +++++++ tests/maddy/test_maddy_htmlparser.cpp | 82 +++++++++++++++++ tests/maddy/test_maddy_parser.cpp | 15 +++ tests/maddy/test_maddy_parser.h | 5 +- 9 files changed, 296 insertions(+), 8 deletions(-) create mode 100644 include/maddy/htmlparser.h create mode 100644 include/maddy/parserconfig.h create mode 100644 tests/maddy/test_maddy_htmlparser.cpp diff --git a/README.md b/README.md index 2a4a15a..8b51180 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # maddy [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Version: 1.1.0](https://img.shields.io/badge/Version-1.1.0-brightgreen.svg)](https://semver.org/) +[![Version: 1.1.1](https://img.shields.io/badge/Version-1.1.1-brightgreen.svg)](https://semver.org/) [![Travis Build Status](https://travis-ci.org/progsource/maddy.svg?branch=master)](https://travis-ci.org/progsource/maddy) [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/04m0lg27kigv1pg8/branch/master?svg=true)](https://ci.appveyor.com/project/progsource/maddy/branch/master) @@ -42,7 +42,13 @@ and in the code, you can then do the following: #include "maddy/parser.h" std::stringstream markdownInput(""); -std::shared_ptr parser = std::make_shared(); + +// config is optional +std::shared_ptr config = std::make_shared(); +config->isEmphasizedParserEnabled = true; // default +config->isHTMLWrappedInParagraph = true; // default + +std::shared_ptr parser = std::make_shared(config); std::string htmlOutput = parser->Parse(markdownInput); ``` diff --git a/docs/definitions.md b/docs/definitions.md index 4bbb593..6595d8b 100644 --- a/docs/definitions.md +++ b/docs/definitions.md @@ -7,6 +7,10 @@ destroy the output, if there was HTML in your markdown. The Parser expects you to use spaces and not tabs for indentation in the markdown. +If a line starts with `<` and `config->isHTMLWrappedInParagraph` is false, it +expects that the upcoming line is HTML and therefor will not be surrounded by a +paragraph. + ## Headlines ``` @@ -241,6 +245,8 @@ results in ## emphasized +This can be disabled by setting `config->isEmphasizedParserEnabled = false`. + ``` _emphasized text_ ``` diff --git a/include/maddy/htmlparser.h b/include/maddy/htmlparser.h new file mode 100644 index 0000000..b6845a7 --- /dev/null +++ b/include/maddy/htmlparser.h @@ -0,0 +1,127 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include + +#include "maddy/blockparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * HtmlParser + * + * @class + */ +class HtmlParser : public BlockParser +{ +public: + /** + * ctor + * + * @method + * @param {std::function} parseLineCallback + * @param {std::function(const std::string& line)>} getBlockParserForLineCallback + */ + HtmlParser( + std::function parseLineCallback, + std::function(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 diff --git a/include/maddy/paragraphparser.h b/include/maddy/paragraphparser.h index 984f7b4..303e3b0 100644 --- a/include/maddy/paragraphparser.h +++ b/include/maddy/paragraphparser.h @@ -44,8 +44,9 @@ public: /** * IsStartingLine * - * If the line is not empty, it will be a paragraph. So this block parser has - * to always run as the last one! + * 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 diff --git a/include/maddy/parser.h b/include/maddy/parser.h index 5ff5ec1..e5f4f72 100644 --- a/include/maddy/parser.h +++ b/include/maddy/parser.h @@ -10,11 +10,14 @@ #include #include +#include "maddy/parserconfig.h" + // BlockParser #include "maddy/checklistparser.h" #include "maddy/codeblockparser.h" #include "maddy/headlineparser.h" #include "maddy/horizontallineparser.h" +#include "maddy/htmlparser.h" #include "maddy/orderedlistparser.h" #include "maddy/paragraphparser.h" #include "maddy/quoteparser.h" @@ -54,8 +57,9 @@ public: * * @method */ - Parser() - : breakLineParser(std::make_shared()) + Parser(std::shared_ptr config = nullptr) + : config(config) + , breakLineParser(std::make_shared()) , emphasizedParser(std::make_shared()) , imageParser(std::make_shared()) , inlineCodeParser(std::make_shared()) @@ -113,6 +117,7 @@ public: } private: + std::shared_ptr config; std::shared_ptr breakLineParser; std::shared_ptr emphasizedParser; std::shared_ptr imageParser; @@ -132,7 +137,11 @@ private: // Attention! StrongParser has to be before EmphasizedParser this->strongParser->Parse(line); - this->emphasizedParser->Parse(line); + + if (!this->config || this->config->isEmphasizedParserEnabled) + { + this->emphasizedParser->Parse(line); + } this->strikeThroughParser->Parse(line); @@ -195,6 +204,14 @@ private: { parser = this->createUnorderedListParser(); } + else if ( + this->config && + !this->config->isHTMLWrappedInParagraph && + maddy::HtmlParser::IsStartingLine(line) + ) + { + parser = std::make_shared(nullptr, nullptr); + } else if (maddy::ParagraphParser::IsStartingLine(line)) { parser = std::make_shared( diff --git a/include/maddy/parserconfig.h b/include/maddy/parserconfig.h new file mode 100644 index 0000000..e1b10ae --- /dev/null +++ b/include/maddy/parserconfig.h @@ -0,0 +1,31 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * ParserConfig + * + * @class + */ +struct ParserConfig +{ + bool isEmphasizedParserEnabled; + bool isHTMLWrappedInParagraph; + + ParserConfig() + : isEmphasizedParserEnabled(true) + , isHTMLWrappedInParagraph(true) + {} +}; // class ParserConfig + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/tests/maddy/test_maddy_htmlparser.cpp b/tests/maddy/test_maddy_htmlparser.cpp new file mode 100644 index 0000000..465ce62 --- /dev/null +++ b/tests/maddy/test_maddy_htmlparser.cpp @@ -0,0 +1,82 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/htmlparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_HTMLPARSER : public ::testing::Test +{ +protected: + std::shared_ptr pParser; + + void + SetUp() override + { + this->pParser = std::make_shared( + nullptr, + nullptr + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_HTMLPARSER, IsFinishedReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(pParser->IsFinished()); +} + +TEST_F(MADDY_HTMLPARSER, IsStartingLineReturnsFalseWhenFacedWithNoSmallerThan) +{ + const std::vector markdown = { + "> quote" + , "some text" + , "* list" + , "1. numbered list" + , "|table>" + }; + + for (size_t i = 0; i < markdown.size(); ++i) + { + ASSERT_FALSE(maddy::HtmlParser::IsStartingLine(markdown[i])); + } +} + +TEST_F(MADDY_HTMLPARSER, IsStartingLineReturnsTrueWhenFacedWithSmallerThan) +{ + const std::string markdown = "
test element
"; + + ASSERT_TRUE(maddy::HtmlParser::IsStartingLine(markdown)); +} + +TEST_F(MADDY_HTMLPARSER, ItReplacesNoHtml) +{ + const std::vector markdown { + "some text in a paragraph" + , "" + , "
some HTML
" + , "" + , "
more" + , "HTML" + , "
" + , "" + }; + const std::string expected = "some text in a paragraph
some HTML
more HTML
"; + + for (std::string md : markdown) + { + pParser->AddLine(md); + } + ASSERT_TRUE(pParser->IsFinished()); + + std::stringstream& output(pParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_parser.cpp b/tests/maddy/test_maddy_parser.cpp index 91e03e0..6e0c76d 100644 --- a/tests/maddy/test_maddy_parser.cpp +++ b/tests/maddy/test_maddy_parser.cpp @@ -19,3 +19,18 @@ TEST(MADDY_PARSER, ItShouldParse) ASSERT_EQ(testHtml, output); } + +TEST(MADDY_PARSER, ItShouldParseWithConfig) +{ + auto config = std::make_shared(); + config->isEmphasizedParserEnabled = false; + config->isHTMLWrappedInParagraph = false; + + auto parser = std::make_shared(config); + + std::stringstream markdown(testMarkdown); + + const std::string output = parser->Parse(markdown); + + ASSERT_EQ(testHtml2, output); +} diff --git a/tests/maddy/test_maddy_parser.h b/tests/maddy/test_maddy_parser.h index 36091e1..e939fd8 100644 --- a/tests/maddy/test_maddy_parser.h +++ b/tests/maddy/test_maddy_parser.h @@ -42,6 +42,8 @@ And well - let's see how an image would be shown:\n\ \n\ ---\n\ \n\ +\n\ +\n\ ### and more headlines\n\ \n\ - [ ] how\n\ @@ -67,4 +69,5 @@ foot a|foot b|foot c\n\ \n\ "; -const std::string testHtml = "

This is a test

This should result in a praragraph it's that simple.

  • an unordered list
    • with some hierarchy
      1. and an ordered
      2. list
      3. directly
    • inside
\nvar c = 'blub';\n

A Quote

With some text blocks inside

  • even a list
  • should be
  • possible

And well inline code should also work.

Another Headline

And not to forget link to progsource should work. And well - let's see how an image would be shown:

\"an


and more headlines

even a table

Left headermiddle headerlast header
cell 1cell 2cell 3
cell 4cell 5cell 6
foot afoot bfoot c
h5
h6
"; +const std::string testHtml = "

This is a test

This should result in a praragraph it's that simple.

  • an unordered list
    • with some hierarchy
      1. and an ordered
      2. list
      3. directly
    • inside
\nvar c = 'blub';\n

A Quote

With some text blocks inside

  • even a list
  • should be
  • possible

And well inline code should also work.

Another Headline

And not to forget link to progsource should work. And well - let's see how an image would be shown:

\"an


and more headlines

even a table

Left headermiddle headerlast header
cell 1cell 2cell 3
cell 4cell 5cell 6
foot afoot bfoot c
h5
h6
"; +const std::string testHtml2 = "

This is a test

This should result in a praragraph it's that simple.

  • an unordered list
    • with some hierarchy
      1. and an _ordered_
      2. list
      3. directly
    • inside
\nvar c = 'blub';\n

A Quote

With some text blocks inside

  • even a list
  • should be
  • possible

And well inline code should also work.

Another Headline

And not to forget link to progsource should work. And well - let's see how an image would be shown:

\"an


and more headlines

even a table

Left headermiddle headerlast header
cell 1cell 2cell 3
cell 4cell 5cell 6
foot afoot bfoot c
h5
h6
";