Parcourir la source

LibMarkdown: Refactor Document's parser into ContainerBlock

This will better allow us too do things like have Lists and blockquotes
support multiple blocks.
Peter Elliott il y a 3 ans
Parent
commit
cd560d3ae3

+ 1 - 0
Userland/Libraries/LibMarkdown/CMakeLists.txt

@@ -1,5 +1,6 @@
 set(SOURCES
     CodeBlock.cpp
+    ContainerBlock.cpp
     Document.cpp
     Heading.cpp
     HorizontalRule.cpp

+ 98 - 0
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));
+}
+
+}

+ 34 - 0
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;
+};
+
+}

+ 3 - 69
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));
 }
 
 }

+ 7 - 2
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;
 };
 
 }