summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFalseHonesty <thefalsehonesty@gmail.com>2020-05-18 16:58:00 -0400
committerAndreas Kling <kling@serenityos.org>2020-05-30 00:32:12 +0200
commit20faa93cb0371c033a2e8ba8271aec5ef4dd6dfe (patch)
treee9976e07d67d8f893790c79725dbd06f9b95842d
parent7ca562b200e9a15bc02bdd23f5c9faedf53e6a26 (diff)
downloadserenity-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.cpp9
-rw-r--r--Libraries/LibMarkdown/Block.h1
-rw-r--r--Libraries/LibMarkdown/CodeBlock.cpp14
-rw-r--r--Libraries/LibMarkdown/CodeBlock.h10
-rw-r--r--Libraries/LibMarkdown/Document.cpp11
-rw-r--r--Libraries/LibMarkdown/Document.h4
-rw-r--r--Libraries/LibMarkdown/Heading.cpp24
-rw-r--r--Libraries/LibMarkdown/Heading.h12
-rw-r--r--Libraries/LibMarkdown/List.cpp35
-rw-r--r--Libraries/LibMarkdown/List.h9
-rw-r--r--Libraries/LibMarkdown/Paragraph.cpp14
-rw-r--r--Libraries/LibMarkdown/Paragraph.h4
-rw-r--r--Libraries/LibMarkdown/Text.cpp15
-rw-r--r--Libraries/LibMarkdown/Text.h11
-rw-r--r--Userland/md.cpp1
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>