diff options
author | Peter Elliott <pelliott@ualberta.ca> | 2021-09-19 11:04:24 -0600 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2021-10-05 13:27:25 +0330 |
commit | cd560d3ae3c5dd618f54f802f1efffe633ba75a5 (patch) | |
tree | f6a0cbb1e22f736a1dd98ec1f112a6508f2b99c7 /Userland/Libraries/LibMarkdown | |
parent | 4fa57480932965874146b771e5078460ee071655 (diff) | |
download | serenity-cd560d3ae3c5dd618f54f802f1efffe633ba75a5.zip |
LibMarkdown: Refactor Document's parser into ContainerBlock
This will better allow us too do things like have Lists and blockquotes
support multiple blocks.
Diffstat (limited to 'Userland/Libraries/LibMarkdown')
-rw-r--r-- | Userland/Libraries/LibMarkdown/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibMarkdown/ContainerBlock.cpp | 98 | ||||
-rw-r--r-- | Userland/Libraries/LibMarkdown/ContainerBlock.h | 34 | ||||
-rw-r--r-- | Userland/Libraries/LibMarkdown/Document.cpp | 72 | ||||
-rw-r--r-- | Userland/Libraries/LibMarkdown/Document.h | 9 |
5 files changed, 143 insertions, 71 deletions
diff --git a/Userland/Libraries/LibMarkdown/CMakeLists.txt b/Userland/Libraries/LibMarkdown/CMakeLists.txt index 034e9c6da8..6674966251 100644 --- a/Userland/Libraries/LibMarkdown/CMakeLists.txt +++ b/Userland/Libraries/LibMarkdown/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES CodeBlock.cpp + ContainerBlock.cpp Document.cpp Heading.cpp HorizontalRule.cpp diff --git a/Userland/Libraries/LibMarkdown/ContainerBlock.cpp b/Userland/Libraries/LibMarkdown/ContainerBlock.cpp new file mode 100644 index 0000000000..6acc5f3226 --- /dev/null +++ b/Userland/Libraries/LibMarkdown/ContainerBlock.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021, Peter Elliott <pelliott@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibMarkdown/CodeBlock.h> +#include <LibMarkdown/ContainerBlock.h> +#include <LibMarkdown/Heading.h> +#include <LibMarkdown/HorizontalRule.h> +#include <LibMarkdown/List.h> +#include <LibMarkdown/Paragraph.h> +#include <LibMarkdown/Table.h> + +namespace Markdown { + +String ContainerBlock::render_to_html() const +{ + StringBuilder builder; + + for (auto& block : m_blocks) { + auto s = block.render_to_html(); + builder.append(s); + } + + return builder.build(); +} + +String ContainerBlock::render_for_terminal(size_t view_width) const +{ + StringBuilder builder; + + for (auto& block : m_blocks) { + auto s = block.render_for_terminal(view_width); + builder.append(s); + } + + return builder.build(); +} + +template<typename BlockType> +static bool try_parse_block(Vector<StringView>::ConstIterator& lines, NonnullOwnPtrVector<Block>& blocks) +{ + OwnPtr<BlockType> block = BlockType::parse(lines); + if (!block) + return false; + blocks.append(block.release_nonnull()); + return true; +} + +OwnPtr<ContainerBlock> ContainerBlock::parse(Vector<StringView>::ConstIterator& lines) +{ + NonnullOwnPtrVector<Block> blocks; + + StringBuilder paragraph_text; + + auto flush_paragraph = [&] { + if (paragraph_text.is_empty()) + return; + auto paragraph = make<Paragraph>(Text::parse(paragraph_text.build())); + blocks.append(move(paragraph)); + paragraph_text.clear(); + }; + + while (true) { + if (lines.is_end()) + break; + + if ((*lines).is_empty()) { + ++lines; + + flush_paragraph(); + continue; + } + + bool any = try_parse_block<Table>(lines, blocks) || try_parse_block<List>(lines, blocks) || try_parse_block<CodeBlock>(lines, blocks) + || try_parse_block<Heading>(lines, blocks) || try_parse_block<HorizontalRule>(lines, blocks); + + if (any) { + if (!paragraph_text.is_empty()) { + auto last_block = blocks.take_last(); + flush_paragraph(); + blocks.append(move(last_block)); + } + continue; + } + + if (!paragraph_text.is_empty()) + paragraph_text.append("\n"); + paragraph_text.append(*lines++); + } + + flush_paragraph(); + + return make<ContainerBlock>(move(blocks)); +} + +} diff --git a/Userland/Libraries/LibMarkdown/ContainerBlock.h b/Userland/Libraries/LibMarkdown/ContainerBlock.h new file mode 100644 index 0000000000..bc7abf5058 --- /dev/null +++ b/Userland/Libraries/LibMarkdown/ContainerBlock.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021, Peter Elliott <pelliott@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/NonnullOwnPtrVector.h> +#include <AK/OwnPtr.h> +#include <AK/String.h> +#include <LibMarkdown/Block.h> + +namespace Markdown { + +class ContainerBlock final : public Block { +public: + ContainerBlock(NonnullOwnPtrVector<Block> blocks) + : m_blocks(move(blocks)) + { + } + + virtual ~ContainerBlock() override { } + + virtual String render_to_html() const override; + virtual String render_for_terminal(size_t view_width = 0) const override; + + static OwnPtr<ContainerBlock> parse(Vector<StringView>::ConstIterator& lines); + +private: + NonnullOwnPtrVector<Block> m_blocks; +}; + +} diff --git a/Userland/Libraries/LibMarkdown/Document.cpp b/Userland/Libraries/LibMarkdown/Document.cpp index 059bbc97c9..733e896f51 100644 --- a/Userland/Libraries/LibMarkdown/Document.cpp +++ b/Userland/Libraries/LibMarkdown/Document.cpp @@ -38,85 +38,19 @@ String Document::render_to_html() const String Document::render_to_inline_html() const { - StringBuilder builder; - - for (auto& block : m_blocks) { - auto s = block.render_to_html(); - builder.append(s); - } - - return builder.build(); + return m_container->render_to_html(); } String Document::render_for_terminal(size_t view_width) const { - StringBuilder builder; - - for (auto& block : m_blocks) { - auto s = block.render_for_terminal(view_width); - builder.append(s); - } - - return builder.build(); -} - -template<typename BlockType> -static bool helper(Vector<StringView>::ConstIterator& lines, NonnullOwnPtrVector<Block>& blocks) -{ - OwnPtr<BlockType> block = BlockType::parse(lines); - if (!block) - return false; - blocks.append(block.release_nonnull()); - return true; + return m_container->render_for_terminal(view_width); } OwnPtr<Document> Document::parse(const StringView& str) { const Vector<StringView> lines_vec = str.lines(); auto lines = lines_vec.begin(); - auto document = make<Document>(); - auto& blocks = document->m_blocks; - StringBuilder paragraph_text; - - auto flush_paragraph = [&] { - if (paragraph_text.is_empty()) - return; - auto paragraph = make<Paragraph>(Text::parse(paragraph_text.build())); - document->m_blocks.append(move(paragraph)); - paragraph_text.clear(); - }; - - while (true) { - if (lines.is_end()) - break; - - if ((*lines).is_empty()) { - ++lines; - - flush_paragraph(); - continue; - } - - bool any = helper<Table>(lines, blocks) || helper<List>(lines, blocks) || helper<CodeBlock>(lines, blocks) - || helper<Heading>(lines, blocks) || helper<HorizontalRule>(lines, blocks); - - if (any) { - if (!paragraph_text.is_empty()) { - auto last_block = document->m_blocks.take_last(); - flush_paragraph(); - document->m_blocks.append(move(last_block)); - } - continue; - } - - if (!paragraph_text.is_empty()) - paragraph_text.append("\n"); - paragraph_text.append(*lines++); - } - - flush_paragraph(); - - return document; + return make<Document>(ContainerBlock::parse(lines)); } } diff --git a/Userland/Libraries/LibMarkdown/Document.h b/Userland/Libraries/LibMarkdown/Document.h index 2337fa4969..796fdbda10 100644 --- a/Userland/Libraries/LibMarkdown/Document.h +++ b/Userland/Libraries/LibMarkdown/Document.h @@ -6,14 +6,19 @@ #pragma once -#include <AK/NonnullOwnPtrVector.h> +#include <AK/OwnPtr.h> #include <AK/String.h> #include <LibMarkdown/Block.h> +#include <LibMarkdown/ContainerBlock.h> namespace Markdown { class Document final { public: + Document(OwnPtr<ContainerBlock> container) + : m_container(move(container)) + { + } String render_to_html() const; String render_to_inline_html() const; String render_for_terminal(size_t view_width = 0) const; @@ -21,7 +26,7 @@ public: static OwnPtr<Document> parse(const StringView&); private: - NonnullOwnPtrVector<Block> m_blocks; + OwnPtr<ContainerBlock> m_container; }; } |