summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibMarkdown
diff options
context:
space:
mode:
authorPeter Elliott <pelliott@ualberta.ca>2021-09-19 11:04:24 -0600
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-10-05 13:27:25 +0330
commitcd560d3ae3c5dd618f54f802f1efffe633ba75a5 (patch)
treef6a0cbb1e22f736a1dd98ec1f112a6508f2b99c7 /Userland/Libraries/LibMarkdown
parent4fa57480932965874146b771e5078460ee071655 (diff)
downloadserenity-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.txt1
-rw-r--r--Userland/Libraries/LibMarkdown/ContainerBlock.cpp98
-rw-r--r--Userland/Libraries/LibMarkdown/ContainerBlock.h34
-rw-r--r--Userland/Libraries/LibMarkdown/Document.cpp72
-rw-r--r--Userland/Libraries/LibMarkdown/Document.h9
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;
};
}