From 9bef80fbef9c1461dc64285dea2bad798f29e4fe Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 13 Jun 2014 19:12:56 +0200 Subject: [PATCH] Simple Markdown parser. Parse just a tiny subset of Markdown, to basically collapse multiple whitespace and do paragraphs only after two newlines. Also one-level, unordered lists are supported. The output can be eg. directly forwarded to canvas::Text. --- simgear/misc/CMakeLists.txt | 7 ++ simgear/misc/SimpleMarkdown.cxx | 104 +++++++++++++++++++++++++++ simgear/misc/SimpleMarkdown.hxx | 39 ++++++++++ simgear/misc/SimpleMarkdown_test.cxx | 34 +++++++++ 4 files changed, 184 insertions(+) create mode 100644 simgear/misc/SimpleMarkdown.cxx create mode 100644 simgear/misc/SimpleMarkdown.hxx create mode 100644 simgear/misc/SimpleMarkdown_test.cxx diff --git a/simgear/misc/CMakeLists.txt b/simgear/misc/CMakeLists.txt index deb72963..404fe5f0 100644 --- a/simgear/misc/CMakeLists.txt +++ b/simgear/misc/CMakeLists.txt @@ -5,6 +5,7 @@ set(HEADERS CSSBorder.hxx ListDiff.hxx ResourceManager.hxx + SimpleMarkdown.hxx SVGpreserveAspectRatio.hxx interpolator.hxx make_new.hxx @@ -23,6 +24,7 @@ set(HEADERS set(SOURCES CSSBorder.cxx ResourceManager.cxx + SimpleMarkdown.cxx SVGpreserveAspectRatio.cxx interpolator.cxx sg_dir.cxx @@ -65,6 +67,11 @@ target_link_libraries(test_path ${TEST_LIBS}) endif(ENABLE_TESTS) +add_boost_test(SimpleMarkdown + SOURCES SimpleMarkdown_test.cxx + LIBRARIES ${TEST_LIBS} +) + add_boost_test(SVGpreserveAspectRatio SOURCES SVGpreserveAspectRatio_test.cxx LIBRARIES ${TEST_LIBS} diff --git a/simgear/misc/SimpleMarkdown.cxx b/simgear/misc/SimpleMarkdown.cxx new file mode 100644 index 00000000..fee6f7a7 --- /dev/null +++ b/simgear/misc/SimpleMarkdown.cxx @@ -0,0 +1,104 @@ +// Really simple markdown parser +// +// Copyright (C) 2014 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "SimpleMarkdown.hxx" + +namespace simgear +{ + + // White space + static bool isSpace(const char c) + { + return c == ' ' || c == '\t'; + } + + // Unordered list item + static bool isULItem(const char c) + { + return c == '*' || c == '+' || c == '-'; + } + + //---------------------------------------------------------------------------- + std::string SimpleMarkdown::parse(const std::string& src) + { + std::string out; + + int num_space = 0, + num_newline = 0; + bool line_empty = true; + + for( std::string::const_iterator it = src.begin(); + it != src.end(); + ++it ) + { + if( isSpace(*it) ) + { + ++num_space; + } + else if( *it == '\n' ) + { + // Two or more whitespace at end of line -> line break + if( !line_empty && num_space >= 2 ) + { + out.push_back('\n'); + line_empty = true; + } + + ++num_newline; + num_space = 0; + } + else + { + // Remove all new lines before first printable character + if( out.empty() ) + num_newline = 0; + + // Two or more new lines (aka. at least one empty line) -> new paragraph + if( num_newline >= 2 ) + { + out.append("\n\n"); + + line_empty = true; + num_newline = 0; + } + + // Replace unordered list item markup at begin of line with bullet + // (TODO multilevel lists, indent multiple lines, etc.) + if( (line_empty || num_newline) && isULItem(*it) ) + { + if( num_newline < 2 ) + out.push_back('\n'); + out.append("\xE2\x80\xA2"); + } + else + { + // Collapse multiple whitespace + if( !line_empty && (num_space || num_newline) ) + out.push_back(' '); + out.push_back(*it); + } + + line_empty = false; + num_space = 0; + num_newline = 0; + } + } + return out; + } + +} // namespace simgear diff --git a/simgear/misc/SimpleMarkdown.hxx b/simgear/misc/SimpleMarkdown.hxx new file mode 100644 index 00000000..ea98184a --- /dev/null +++ b/simgear/misc/SimpleMarkdown.hxx @@ -0,0 +1,39 @@ +///@file Really simple markdown parser +// +// Copyright (C) 2014 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SIMPLE_MARKDOWN_HXX_ +#define SIMPLE_MARKDOWN_HXX_ + +#include + +namespace simgear +{ + /** + * Really simple mardown parser. Currently just paragraphs, new lines and + * one level of unordered lists are supported. + * + * @see http://en.wikipedia.org/wiki/Markdown + */ + class SimpleMarkdown + { + public: + static std::string parse(const std::string& src); + }; +} // namespace simgear + +#endif /* SIMPLE_MARKDOWN_HXX_ */ diff --git a/simgear/misc/SimpleMarkdown_test.cxx b/simgear/misc/SimpleMarkdown_test.cxx new file mode 100644 index 00000000..e32ea3bf --- /dev/null +++ b/simgear/misc/SimpleMarkdown_test.cxx @@ -0,0 +1,34 @@ +/// Unit tests for simple markdown parser +#define BOOST_TEST_MODULE misc +#include + +#include "SimpleMarkdown.hxx" + +BOOST_AUTO_TEST_CASE( basic_markdown ) +{ + std::string const src( + " \n" + "\n" + "blub\n" + "* \tlist item\n" + "* another\t item\n" + "\n" + "test blubt\n" + " aha \n" + "asd\n" + " * 2nd list, another item\n" + " * 2nd list, one more..." + ); + std::string const out( + "blub\n" + "\xE2\x80\xA2 list item\n" + "\xE2\x80\xA2 another item\n" + "\n" + "test blubt aha\n" + "asd\n" + "\xE2\x80\xA2 2nd list, another item\n" + "\xE2\x80\xA2 2nd list, one more..." + ); + + BOOST_CHECK_EQUAL(simgear::SimpleMarkdown::parse(src), out); +}