diff options
author | FalseHonesty <thefalsehonesty@gmail.com> | 2020-05-18 16:58:00 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-05-30 00:32:12 +0200 |
commit | 20faa93cb0371c033a2e8ba8271aec5ef4dd6dfe (patch) | |
tree | e9976e07d67d8f893790c79725dbd06f9b95842d | |
parent | 7ca562b200e9a15bc02bdd23f5c9faedf53e6a26 (diff) | |
download | serenity-20faa93cb0371c033a2e8ba8271aec5ef4dd6dfe.zip |
LibMarkdown: Change internal MD API to return OwnPtrs
Previously, all Markdown blocks had a virtual parse method which has
been swapped out for a static parse method returning an OwnPtr of
that block's type.
The Text class also now has a static parse method that will return an
Optional<Text>.
-rw-r--r-- | Applications/Help/main.cpp | 9 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Block.h | 1 | ||||
-rw-r--r-- | Libraries/LibMarkdown/CodeBlock.cpp | 14 | ||||
-rw-r--r-- | Libraries/LibMarkdown/CodeBlock.h | 10 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Document.cpp | 11 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Document.h | 4 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Heading.cpp | 24 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Heading.h | 12 | ||||
-rw-r--r-- | Libraries/LibMarkdown/List.cpp | 35 | ||||
-rw-r--r-- | Libraries/LibMarkdown/List.h | 9 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Paragraph.cpp | 14 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Paragraph.h | 4 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Text.cpp | 15 | ||||
-rw-r--r-- | Libraries/LibMarkdown/Text.h | 11 | ||||
-rw-r--r-- | Userland/md.cpp | 1 |
15 files changed, 110 insertions, 64 deletions
diff --git a/Applications/Help/main.cpp b/Applications/Help/main.cpp index ffe41c3e69..903f23e5b5 100644 --- a/Applications/Help/main.cpp +++ b/Applications/Help/main.cpp @@ -128,10 +128,13 @@ int main(int argc, char* argv[]) auto buffer = file->read_all(); StringView source { (const char*)buffer.data(), buffer.size() }; - auto md_document = Markdown::Document::parse(source); - ASSERT(md_document); + String html; + { + auto md_document = Markdown::Document::parse(source); + ASSERT(md_document); + html = md_document->render_to_html(); + } - String html = md_document->render_to_html(); auto html_document = Web::parse_html_document(html); page_view.set_document(html_document); diff --git a/Libraries/LibMarkdown/Block.h b/Libraries/LibMarkdown/Block.h index 1b6e3cc3af..4a8416ad43 100644 --- a/Libraries/LibMarkdown/Block.h +++ b/Libraries/LibMarkdown/Block.h @@ -37,7 +37,6 @@ public: virtual String render_to_html() const = 0; virtual String render_for_terminal() const = 0; - virtual bool parse(Vector<StringView>::ConstIterator& lines) = 0; }; } diff --git a/Libraries/LibMarkdown/CodeBlock.cpp b/Libraries/LibMarkdown/CodeBlock.cpp index f35a29cf67..16703853fa 100644 --- a/Libraries/LibMarkdown/CodeBlock.cpp +++ b/Libraries/LibMarkdown/CodeBlock.cpp @@ -105,16 +105,16 @@ String CodeBlock::render_for_terminal() const return builder.build(); } -bool CodeBlock::parse(Vector<StringView>::ConstIterator& lines) +OwnPtr<CodeBlock> CodeBlock::parse(Vector<StringView>::ConstIterator& lines) { if (lines.is_end()) - return false; + return nullptr; constexpr auto tick_tick_tick = "```"; StringView line = *lines; if (!line.starts_with(tick_tick_tick)) - return false; + return nullptr; // Our Markdown extension: we allow // specifying a style and a language @@ -128,8 +128,9 @@ bool CodeBlock::parse(Vector<StringView>::ConstIterator& lines) // and if possible syntax-highlighted // as appropriate for a shell script. StringView style_spec = line.substring_view(3, line.length() - 3); - bool success = m_style_spec.parse(style_spec); - ASSERT(success); + auto spec = Text::parse(style_spec); + if (!spec.has_value()) + return nullptr; ++lines; @@ -149,8 +150,7 @@ bool CodeBlock::parse(Vector<StringView>::ConstIterator& lines) first = false; } - m_code = builder.build(); - return true; + return make<CodeBlock>(move(spec.value()), builder.build()); } } diff --git a/Libraries/LibMarkdown/CodeBlock.h b/Libraries/LibMarkdown/CodeBlock.h index 2410e9b0e4..5b5159de6d 100644 --- a/Libraries/LibMarkdown/CodeBlock.h +++ b/Libraries/LibMarkdown/CodeBlock.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/OwnPtr.h> #include <LibMarkdown/Block.h> #include <LibMarkdown/Text.h> @@ -33,11 +34,16 @@ namespace Markdown { class CodeBlock final : public Block { public: - virtual ~CodeBlock() override {} + CodeBlock(Text&& style_spec, const String& code) + : m_code(move(code)) + , m_style_spec(move(style_spec)) + { + } + virtual ~CodeBlock() override { } virtual String render_to_html() const override; virtual String render_for_terminal() const override; - virtual bool parse(Vector<StringView>::ConstIterator& lines) override; + static OwnPtr<CodeBlock> parse(Vector<StringView>::ConstIterator& lines); private: String style_language() const; diff --git a/Libraries/LibMarkdown/Document.cpp b/Libraries/LibMarkdown/Document.cpp index 841b5a5ef6..6958ce8229 100644 --- a/Libraries/LibMarkdown/Document.cpp +++ b/Libraries/LibMarkdown/Document.cpp @@ -67,19 +67,18 @@ String Document::render_for_terminal() const template<typename BlockType> static bool helper(Vector<StringView>::ConstIterator& lines, NonnullOwnPtrVector<Block>& blocks) { - NonnullOwnPtr<BlockType> block = make<BlockType>(); - bool success = block->parse(lines); - if (!success) + OwnPtr<BlockType> block = BlockType::parse(lines); + if (!block) return false; - blocks.append(move(block)); + blocks.append(block.release_nonnull()); return true; } -RefPtr<Document> Document::parse(const StringView& str) +OwnPtr<Document> Document::parse(const StringView& str) { const Vector<StringView> lines_vec = str.lines(); auto lines = lines_vec.begin(); - auto document = adopt(*new Document); + auto document = make<Document>(); auto& blocks = document->m_blocks; while (true) { diff --git a/Libraries/LibMarkdown/Document.h b/Libraries/LibMarkdown/Document.h index 58733db452..259aa09046 100644 --- a/Libraries/LibMarkdown/Document.h +++ b/Libraries/LibMarkdown/Document.h @@ -32,12 +32,12 @@ namespace Markdown { -class Document final : public RefCounted<Document> { +class Document final { public: String render_to_html() const; String render_for_terminal() const; - static RefPtr<Document> parse(const StringView&); + static OwnPtr<Document> parse(const StringView&); private: NonnullOwnPtrVector<Block> m_blocks; diff --git a/Libraries/LibMarkdown/Heading.cpp b/Libraries/LibMarkdown/Heading.cpp index 7997a0e0fd..c489f1e603 100644 --- a/Libraries/LibMarkdown/Heading.cpp +++ b/Libraries/LibMarkdown/Heading.cpp @@ -59,26 +59,30 @@ String Heading::render_for_terminal() const return builder.build(); } -bool Heading::parse(Vector<StringView>::ConstIterator& lines) +OwnPtr<Heading> Heading::parse(Vector<StringView>::ConstIterator& lines) { if (lines.is_end()) - return false; + return nullptr; const StringView& line = *lines; + size_t level; - for (m_level = 0; m_level < (int)line.length(); m_level++) - if (line[(size_t)m_level] != '#') + for (level = 0; level < line.length(); level++) + if (line[level] != '#') break; - if (m_level >= (int)line.length() || line[(size_t)m_level] != ' ') - return false; + if (level >= line.length() || line[level] != ' ') + return nullptr; - StringView title_view = line.substring_view((size_t)m_level + 1, line.length() - (size_t)m_level - 1); - bool success = m_text.parse(title_view); - ASSERT(success); + StringView title_view = line.substring_view(level + 1, line.length() - level - 1); + auto text = Text::parse(title_view); + if (!text.has_value()) + return nullptr; + + auto heading = make<Heading>(move(text.value()), level); ++lines; - return true; + return heading; } } diff --git a/Libraries/LibMarkdown/Heading.h b/Libraries/LibMarkdown/Heading.h index 92f5ce71ef..8988bc0f88 100644 --- a/Libraries/LibMarkdown/Heading.h +++ b/Libraries/LibMarkdown/Heading.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/OwnPtr.h> #include <AK/StringView.h> #include <AK/Vector.h> #include <LibMarkdown/Block.h> @@ -35,15 +36,20 @@ namespace Markdown { class Heading final : public Block { public: - virtual ~Heading() override {} + Heading(Text&& text, size_t level) + : m_text(move(text)) + , m_level(level) + { + } + virtual ~Heading() override { } virtual String render_to_html() const override; virtual String render_for_terminal() const override; - virtual bool parse(Vector<StringView>::ConstIterator& lines) override; + static OwnPtr<Heading> parse(Vector<StringView>::ConstIterator& lines); private: Text m_text; - int m_level { -1 }; + size_t m_level { 0 }; }; } diff --git a/Libraries/LibMarkdown/List.cpp b/Libraries/LibMarkdown/List.cpp index aab24d0c31..15cd47d80a 100644 --- a/Libraries/LibMarkdown/List.cpp +++ b/Libraries/LibMarkdown/List.cpp @@ -66,21 +66,26 @@ String List::render_for_terminal() const return builder.build(); } -bool List::parse(Vector<StringView>::ConstIterator& lines) +OwnPtr<List> List::parse(Vector<StringView>::ConstIterator& lines) { + Vector<Text> items; + bool is_ordered = false; + bool first = true; size_t offset = 0; StringBuilder item_builder; auto flush_item_if_needed = [&] { if (first) - return; + return true; + + auto text = Text::parse(item_builder.string_view()); + if (!text.has_value()) + return false; - Text text; - bool success = text.parse(item_builder.string_view()); - ASSERT(success); - m_items.append(move(text)); + items.append(move(text.value())); item_builder.clear(); + return true; }; while (true) { @@ -115,21 +120,22 @@ bool List::parse(Vector<StringView>::ConstIterator& lines) if (appears_unordered || appears_ordered) { if (first) - m_is_ordered = appears_ordered; - else if (m_is_ordered != appears_ordered) - return false; + is_ordered = appears_ordered; + else if (is_ordered != appears_ordered) + return nullptr; - flush_item_if_needed(); + if (!flush_item_if_needed()) + return nullptr; while (offset + 1 < line.length() && line[offset + 1] == ' ') offset++; } else { if (first) - return false; + return nullptr; for (size_t i = 0; i < offset; i++) { if (line[i] != ' ') - return false; + return nullptr; } } @@ -140,8 +146,9 @@ bool List::parse(Vector<StringView>::ConstIterator& lines) ++lines; } - flush_item_if_needed(); - return !first; + if (!flush_item_if_needed() || first) + return nullptr; + return make<List>(move(items), is_ordered); } } diff --git a/Libraries/LibMarkdown/List.h b/Libraries/LibMarkdown/List.h index b66e5c8495..e4fc98f54b 100644 --- a/Libraries/LibMarkdown/List.h +++ b/Libraries/LibMarkdown/List.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/OwnPtr.h> #include <AK/Vector.h> #include <LibMarkdown/Block.h> #include <LibMarkdown/Text.h> @@ -34,11 +35,17 @@ namespace Markdown { class List final : public Block { public: + List(Vector<Text>&& text, bool is_ordered) + : m_items(move(text)) + , m_is_ordered(is_ordered) + { + } virtual ~List() override {} virtual String render_to_html() const override; virtual String render_for_terminal() const override; - virtual bool parse(Vector<StringView>::ConstIterator& lines) override; + + static OwnPtr<List> parse(Vector<StringView>::ConstIterator& lines); private: // TODO: List items should be considered blocks of their own kind. diff --git a/Libraries/LibMarkdown/Paragraph.cpp b/Libraries/LibMarkdown/Paragraph.cpp index c1c9208900..764e555fbc 100644 --- a/Libraries/LibMarkdown/Paragraph.cpp +++ b/Libraries/LibMarkdown/Paragraph.cpp @@ -46,10 +46,10 @@ String Paragraph::render_for_terminal() const return builder.build(); } -bool Paragraph::parse(Vector<StringView>::ConstIterator& lines) +OwnPtr<Paragraph> Paragraph::parse(Vector<StringView>::ConstIterator& lines) { if (lines.is_end()) - return false; + return nullptr; bool first = true; StringBuilder builder; @@ -86,11 +86,13 @@ bool Paragraph::parse(Vector<StringView>::ConstIterator& lines) } if (first) - return false; + return nullptr; - bool success = m_text.parse(builder.build()); - ASSERT(success); - return true; + auto text = Text::parse(builder.build()); + if (!text.has_value()) + return nullptr; + + return make<Paragraph>(move(text.value())); } } diff --git a/Libraries/LibMarkdown/Paragraph.h b/Libraries/LibMarkdown/Paragraph.h index 98b3b9192b..e66b5c18c9 100644 --- a/Libraries/LibMarkdown/Paragraph.h +++ b/Libraries/LibMarkdown/Paragraph.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/OwnPtr.h> #include <LibMarkdown/Block.h> #include <LibMarkdown/Text.h> @@ -33,11 +34,12 @@ namespace Markdown { class Paragraph final : public Block { public: + explicit Paragraph(Text&& text) : m_text(move(text)) {} virtual ~Paragraph() override {} virtual String render_to_html() const override; virtual String render_for_terminal() const override; - virtual bool parse(Vector<StringView>::ConstIterator& lines) override; + static OwnPtr<Paragraph> parse(Vector<StringView>::ConstIterator& lines); private: Text m_text; diff --git a/Libraries/LibMarkdown/Text.cpp b/Libraries/LibMarkdown/Text.cpp index dd9b60a4d4..60094005dc 100644 --- a/Libraries/LibMarkdown/Text.cpp +++ b/Libraries/LibMarkdown/Text.cpp @@ -181,12 +181,13 @@ String Text::render_for_terminal() const return builder.build(); } -bool Text::parse(const StringView& str) +Optional<Text> Text::parse(const StringView& str) { Style current_style; size_t current_span_start = 0; int first_span_in_the_current_link = -1; bool current_link_is_actually_img = false; + Vector<Span> spans; auto append_span_if_needed = [&](size_t offset) { ASSERT(current_span_start <= offset); @@ -195,7 +196,7 @@ bool Text::parse(const StringView& str) unescape(str.substring_view(current_span_start, offset - current_span_start)), current_style }; - m_spans.append(move(span)); + spans.append(move(span)); current_span_start = offset; } }; @@ -239,7 +240,7 @@ bool Text::parse(const StringView& str) case '[': if (first_span_in_the_current_link != -1) dbg() << "Dropping the outer link"; - first_span_in_the_current_link = m_spans.size(); + first_span_in_the_current_link = spans.size(); break; case ']': { if (first_span_in_the_current_link == -1) { @@ -262,11 +263,11 @@ bool Text::parse(const StringView& str) offset--; const StringView href = str.substring_view(start_of_href, offset - start_of_href); - for (size_t i = first_span_in_the_current_link; i < m_spans.size(); i++) { + for (size_t i = first_span_in_the_current_link; i < spans.size(); i++) { if (current_link_is_actually_img) - m_spans[i].style.img = href; + spans[i].style.img = href; else - m_spans[i].style.href = href; + spans[i].style.href = href; } break; } @@ -282,7 +283,7 @@ bool Text::parse(const StringView& str) append_span_if_needed(str.length()); - return true; + return Text(move(spans)); } } diff --git a/Libraries/LibMarkdown/Text.h b/Libraries/LibMarkdown/Text.h index 4ac8c7e5c2..74dd59ee26 100644 --- a/Libraries/LibMarkdown/Text.h +++ b/Libraries/LibMarkdown/Text.h @@ -26,12 +26,14 @@ #pragma once +#include <AK/Noncopyable.h> #include <AK/String.h> #include <AK/Vector.h> namespace Markdown { class Text final { + AK_MAKE_NONCOPYABLE(Text); public: struct Style { bool emph { false }; @@ -46,14 +48,21 @@ public: Style style; }; + Text(Text&& text) = default; + const Vector<Span>& spans() const { return m_spans; } String render_to_html() const; String render_for_terminal() const; - bool parse(const StringView&); + static Optional<Text> parse(const StringView&); private: + Text(Vector<Span>&& spans) + : m_spans(move(spans)) + { + } + Vector<Span> m_spans; }; diff --git a/Userland/md.cpp b/Userland/md.cpp index 45a6041854..f0b4268a14 100644 --- a/Userland/md.cpp +++ b/Userland/md.cpp @@ -25,6 +25,7 @@ */ #include <AK/ByteBuffer.h> +#include <AK/OwnPtr.h> #include <AK/String.h> #include <LibCore/File.h> #include <LibMarkdown/Document.h> |