summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorBen Wiederhake <BenWiederhake.GitHub@gmx.de>2021-09-10 21:36:29 +0200
committerBrian Gianforcaro <b.gianfo@gmail.com>2021-10-10 15:18:55 -0700
commit24e7196158e4673c90aca5c6bff89319d3427282 (patch)
treefc8ac5f328a16873809344541d4c952a5fd43a43 /Userland/Libraries
parentaca01932bd7e83cea4e026e204b43c2849cf936c (diff)
downloadserenity-24e7196158e4673c90aca5c6bff89319d3427282.zip
LibMarkdown: Implement introspection of the document tree
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibMarkdown/Block.h3
-rw-r--r--Userland/Libraries/LibMarkdown/BlockQuote.cpp10
-rw-r--r--Userland/Libraries/LibMarkdown/BlockQuote.h1
-rw-r--r--Userland/Libraries/LibMarkdown/CodeBlock.cpp17
-rw-r--r--Userland/Libraries/LibMarkdown/CodeBlock.h1
-rw-r--r--Userland/Libraries/LibMarkdown/ContainerBlock.cpp16
-rw-r--r--Userland/Libraries/LibMarkdown/ContainerBlock.h1
-rw-r--r--Userland/Libraries/LibMarkdown/Document.cpp10
-rw-r--r--Userland/Libraries/LibMarkdown/Document.h11
-rw-r--r--Userland/Libraries/LibMarkdown/Forward.h26
-rw-r--r--Userland/Libraries/LibMarkdown/Heading.cpp10
-rw-r--r--Userland/Libraries/LibMarkdown/Heading.h1
-rw-r--r--Userland/Libraries/LibMarkdown/HorizontalRule.cpp10
-rw-r--r--Userland/Libraries/LibMarkdown/HorizontalRule.h1
-rw-r--r--Userland/Libraries/LibMarkdown/List.cpp16
-rw-r--r--Userland/Libraries/LibMarkdown/List.h1
-rw-r--r--Userland/Libraries/LibMarkdown/Paragraph.cpp10
-rw-r--r--Userland/Libraries/LibMarkdown/Paragraph.h1
-rw-r--r--Userland/Libraries/LibMarkdown/Table.cpp35
-rw-r--r--Userland/Libraries/LibMarkdown/Table.h3
-rw-r--r--Userland/Libraries/LibMarkdown/Text.cpp75
-rw-r--r--Userland/Libraries/LibMarkdown/Text.h10
-rw-r--r--Userland/Libraries/LibMarkdown/Visitor.h50
23 files changed, 319 insertions, 0 deletions
diff --git a/Userland/Libraries/LibMarkdown/Block.h b/Userland/Libraries/LibMarkdown/Block.h
index bc5ec0e897..ed71c9933e 100644
--- a/Userland/Libraries/LibMarkdown/Block.h
+++ b/Userland/Libraries/LibMarkdown/Block.h
@@ -6,8 +6,10 @@
#pragma once
+#include <AK/RecursionDecision.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
+#include <LibMarkdown/Forward.h>
namespace Markdown {
@@ -17,6 +19,7 @@ public:
virtual String render_to_html(bool tight = false) const = 0;
virtual String render_for_terminal(size_t view_width = 0) const = 0;
+ virtual RecursionDecision walk(Visitor&) const = 0;
};
}
diff --git a/Userland/Libraries/LibMarkdown/BlockQuote.cpp b/Userland/Libraries/LibMarkdown/BlockQuote.cpp
index a40a24dbc1..df879a3c05 100644
--- a/Userland/Libraries/LibMarkdown/BlockQuote.cpp
+++ b/Userland/Libraries/LibMarkdown/BlockQuote.cpp
@@ -6,6 +6,7 @@
#include <AK/StringBuilder.h>
#include <LibMarkdown/BlockQuote.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -24,6 +25,15 @@ String BlockQuote::render_for_terminal(size_t view_width) const
return m_contents->render_for_terminal(view_width);
}
+RecursionDecision BlockQuote::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return m_contents->walk(visitor);
+}
+
OwnPtr<BlockQuote> BlockQuote::parse(LineIterator& lines)
{
lines.push_context(LineIterator::Context::block_quote());
diff --git a/Userland/Libraries/LibMarkdown/BlockQuote.h b/Userland/Libraries/LibMarkdown/BlockQuote.h
index 5c9abbbfab..a3eacdb0e7 100644
--- a/Userland/Libraries/LibMarkdown/BlockQuote.h
+++ b/Userland/Libraries/LibMarkdown/BlockQuote.h
@@ -22,6 +22,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
static OwnPtr<BlockQuote> parse(LineIterator& lines);
diff --git a/Userland/Libraries/LibMarkdown/CodeBlock.cpp b/Userland/Libraries/LibMarkdown/CodeBlock.cpp
index d433d3c61e..455045d9ad 100644
--- a/Userland/Libraries/LibMarkdown/CodeBlock.cpp
+++ b/Userland/Libraries/LibMarkdown/CodeBlock.cpp
@@ -7,6 +7,7 @@
#include <AK/StringBuilder.h>
#include <LibJS/MarkupGenerator.h>
#include <LibMarkdown/CodeBlock.h>
+#include <LibMarkdown/Visitor.h>
#include <LibRegex/Regex.h>
namespace Markdown {
@@ -54,6 +55,22 @@ String CodeBlock::render_for_terminal(size_t) const
return builder.build();
}
+RecursionDecision CodeBlock::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ rd = visitor.visit(m_code);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ // Don't recurse on m_language and m_style.
+
+ // Normalize return value.
+ return RecursionDecision::Continue;
+}
+
static Regex<ECMA262> style_spec_re("\\s*([\\*_]*)\\s*([^\\*_\\s]*).*");
OwnPtr<CodeBlock> CodeBlock::parse(LineIterator& lines)
diff --git a/Userland/Libraries/LibMarkdown/CodeBlock.h b/Userland/Libraries/LibMarkdown/CodeBlock.h
index c4b7ff7885..aa6c7f099b 100644
--- a/Userland/Libraries/LibMarkdown/CodeBlock.h
+++ b/Userland/Libraries/LibMarkdown/CodeBlock.h
@@ -25,6 +25,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
static OwnPtr<CodeBlock> parse(LineIterator& lines);
private:
diff --git a/Userland/Libraries/LibMarkdown/ContainerBlock.cpp b/Userland/Libraries/LibMarkdown/ContainerBlock.cpp
index 8ae1213459..0682bc89b0 100644
--- a/Userland/Libraries/LibMarkdown/ContainerBlock.cpp
+++ b/Userland/Libraries/LibMarkdown/ContainerBlock.cpp
@@ -12,6 +12,7 @@
#include <LibMarkdown/List.h>
#include <LibMarkdown/Paragraph.h>
#include <LibMarkdown/Table.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -50,6 +51,21 @@ String ContainerBlock::render_for_terminal(size_t view_width) const
return builder.build();
}
+RecursionDecision ContainerBlock::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ for (auto const& block : m_blocks) {
+ rd = block.walk(visitor);
+ if (rd == RecursionDecision::Break)
+ return rd;
+ }
+
+ return RecursionDecision::Continue;
+}
+
template<typename BlockType>
static bool try_parse_block(LineIterator& lines, NonnullOwnPtrVector<Block>& blocks)
{
diff --git a/Userland/Libraries/LibMarkdown/ContainerBlock.h b/Userland/Libraries/LibMarkdown/ContainerBlock.h
index c737a6fc0e..e1fe9a9b28 100644
--- a/Userland/Libraries/LibMarkdown/ContainerBlock.h
+++ b/Userland/Libraries/LibMarkdown/ContainerBlock.h
@@ -27,6 +27,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
static OwnPtr<ContainerBlock> parse(LineIterator& lines);
diff --git a/Userland/Libraries/LibMarkdown/Document.cpp b/Userland/Libraries/LibMarkdown/Document.cpp
index e1fd47cc9f..ee53bf9686 100644
--- a/Userland/Libraries/LibMarkdown/Document.cpp
+++ b/Userland/Libraries/LibMarkdown/Document.cpp
@@ -8,6 +8,7 @@
#include <AK/StringBuilder.h>
#include <LibMarkdown/Document.h>
#include <LibMarkdown/LineIterator.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -41,6 +42,15 @@ String Document::render_for_terminal(size_t view_width) const
return m_container->render_for_terminal(view_width);
}
+RecursionDecision Document::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return m_container->walk(visitor);
+}
+
OwnPtr<Document> Document::parse(const StringView& str)
{
const Vector<StringView> lines_vec = str.lines();
diff --git a/Userland/Libraries/LibMarkdown/Document.h b/Userland/Libraries/LibMarkdown/Document.h
index 796fdbda10..db3e0fc0d6 100644
--- a/Userland/Libraries/LibMarkdown/Document.h
+++ b/Userland/Libraries/LibMarkdown/Document.h
@@ -23,6 +23,17 @@ public:
String render_to_inline_html() const;
String render_for_terminal(size_t view_width = 0) const;
+ /*
+ * Walk recursively through the document tree. Returning `RecursionDecision::Recurse` from
+ * `Visitor::visit` proceeds with the next element of the pre-order walk, usually a child element.
+ * Returning `RecursionDecision::Continue` skips the subtree, and usually proceeds with the next
+ * sibling. Returning `RecursionDecision::Break` breaks the recursion, with no further calls to
+ * any of the `Visitor::visit` methods.
+ *
+ * Note that `walk()` will only return `RecursionDecision::Continue` or `RecursionDecision::Break`.
+ */
+ RecursionDecision walk(Visitor&) const;
+
static OwnPtr<Document> parse(const StringView&);
private:
diff --git a/Userland/Libraries/LibMarkdown/Forward.h b/Userland/Libraries/LibMarkdown/Forward.h
new file mode 100644
index 0000000000..4edf3ce6f2
--- /dev/null
+++ b/Userland/Libraries/LibMarkdown/Forward.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+namespace Markdown {
+
+class Block;
+class Document;
+class Text;
+
+class BlockQuote;
+class CodeBlock;
+class ContainerBlock;
+class Heading;
+class HoriziontalRule;
+class List;
+class Paragraph;
+class Table;
+
+class Visitor;
+
+}
diff --git a/Userland/Libraries/LibMarkdown/Heading.cpp b/Userland/Libraries/LibMarkdown/Heading.cpp
index 66c8d4b02d..1dd321f8e5 100644
--- a/Userland/Libraries/LibMarkdown/Heading.cpp
+++ b/Userland/Libraries/LibMarkdown/Heading.cpp
@@ -6,6 +6,7 @@
#include <AK/StringBuilder.h>
#include <LibMarkdown/Heading.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -35,6 +36,15 @@ String Heading::render_for_terminal(size_t) const
return builder.build();
}
+RecursionDecision Heading::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return m_text.walk(visitor);
+}
+
OwnPtr<Heading> Heading::parse(LineIterator& lines)
{
if (lines.is_end())
diff --git a/Userland/Libraries/LibMarkdown/Heading.h b/Userland/Libraries/LibMarkdown/Heading.h
index 4e7ffa1948..da8dc49102 100644
--- a/Userland/Libraries/LibMarkdown/Heading.h
+++ b/Userland/Libraries/LibMarkdown/Heading.h
@@ -27,6 +27,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
static OwnPtr<Heading> parse(LineIterator& lines);
private:
diff --git a/Userland/Libraries/LibMarkdown/HorizontalRule.cpp b/Userland/Libraries/LibMarkdown/HorizontalRule.cpp
index 5d884df3db..2e696143ed 100644
--- a/Userland/Libraries/LibMarkdown/HorizontalRule.cpp
+++ b/Userland/Libraries/LibMarkdown/HorizontalRule.cpp
@@ -7,6 +7,7 @@
#include <AK/String.h>
#include <AK/StringBuilder.h>
#include <LibMarkdown/HorizontalRule.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -24,6 +25,15 @@ String HorizontalRule::render_for_terminal(size_t view_width) const
return builder.to_string();
}
+RecursionDecision HorizontalRule::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+ // Normalize return value.
+ return RecursionDecision::Continue;
+}
+
OwnPtr<HorizontalRule> HorizontalRule::parse(LineIterator& lines)
{
if (lines.is_end())
diff --git a/Userland/Libraries/LibMarkdown/HorizontalRule.h b/Userland/Libraries/LibMarkdown/HorizontalRule.h
index 034b2233ea..affa84842a 100644
--- a/Userland/Libraries/LibMarkdown/HorizontalRule.h
+++ b/Userland/Libraries/LibMarkdown/HorizontalRule.h
@@ -23,6 +23,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
static OwnPtr<HorizontalRule> parse(LineIterator& lines);
};
diff --git a/Userland/Libraries/LibMarkdown/List.cpp b/Userland/Libraries/LibMarkdown/List.cpp
index 3e2b63a4df..187a5e5c11 100644
--- a/Userland/Libraries/LibMarkdown/List.cpp
+++ b/Userland/Libraries/LibMarkdown/List.cpp
@@ -8,6 +8,7 @@
#include <AK/StringBuilder.h>
#include <LibMarkdown/List.h>
#include <LibMarkdown/Paragraph.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -54,6 +55,21 @@ String List::render_for_terminal(size_t) const
return builder.build();
}
+RecursionDecision List::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ for (auto const& block : m_items) {
+ rd = block->walk(visitor);
+ if (rd == RecursionDecision::Break)
+ return rd;
+ }
+
+ return RecursionDecision::Continue;
+}
+
OwnPtr<List> List::parse(LineIterator& lines)
{
Vector<OwnPtr<ContainerBlock>> items;
diff --git a/Userland/Libraries/LibMarkdown/List.h b/Userland/Libraries/LibMarkdown/List.h
index 2881902200..5e62a78a6c 100644
--- a/Userland/Libraries/LibMarkdown/List.h
+++ b/Userland/Libraries/LibMarkdown/List.h
@@ -26,6 +26,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
static OwnPtr<List> parse(LineIterator& lines);
diff --git a/Userland/Libraries/LibMarkdown/Paragraph.cpp b/Userland/Libraries/LibMarkdown/Paragraph.cpp
index df0e3f2aea..ab30bdd0bb 100644
--- a/Userland/Libraries/LibMarkdown/Paragraph.cpp
+++ b/Userland/Libraries/LibMarkdown/Paragraph.cpp
@@ -6,6 +6,7 @@
#include <AK/StringBuilder.h>
#include <LibMarkdown/Paragraph.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -34,4 +35,13 @@ String Paragraph::render_for_terminal(size_t) const
return builder.build();
}
+RecursionDecision Paragraph::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return m_text.walk(visitor);
+}
+
}
diff --git a/Userland/Libraries/LibMarkdown/Paragraph.h b/Userland/Libraries/LibMarkdown/Paragraph.h
index e9c8db692e..e2af98a717 100644
--- a/Userland/Libraries/LibMarkdown/Paragraph.h
+++ b/Userland/Libraries/LibMarkdown/Paragraph.h
@@ -24,6 +24,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
private:
Text m_text;
diff --git a/Userland/Libraries/LibMarkdown/Table.cpp b/Userland/Libraries/LibMarkdown/Table.cpp
index 37f3c1ad5a..995738f718 100644
--- a/Userland/Libraries/LibMarkdown/Table.cpp
+++ b/Userland/Libraries/LibMarkdown/Table.cpp
@@ -7,6 +7,7 @@
#include <AK/Debug.h>
#include <AK/StringBuilder.h>
#include <LibMarkdown/Table.h>
+#include <LibMarkdown/Visitor.h>
namespace Markdown {
@@ -96,6 +97,21 @@ String Table::render_to_html(bool) const
return builder.to_string();
}
+RecursionDecision Table::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ for (auto const& column : m_columns) {
+ rd = column.walk(visitor);
+ if (rd == RecursionDecision::Break)
+ return rd;
+ }
+
+ return RecursionDecision::Continue;
+}
+
OwnPtr<Table> Table::parse(LineIterator& lines)
{
auto peek_it = lines;
@@ -207,4 +223,23 @@ OwnPtr<Table> Table::parse(LineIterator& lines)
return table;
}
+RecursionDecision Table::Column::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ rd = header.walk(visitor);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ for (auto const& row : rows) {
+ rd = row.walk(visitor);
+ if (rd == RecursionDecision::Break)
+ return rd;
+ }
+
+ return RecursionDecision::Continue;
+}
+
}
diff --git a/Userland/Libraries/LibMarkdown/Table.h b/Userland/Libraries/LibMarkdown/Table.h
index a4f4d0e578..c0073a0ad9 100644
--- a/Userland/Libraries/LibMarkdown/Table.h
+++ b/Userland/Libraries/LibMarkdown/Table.h
@@ -27,6 +27,8 @@ public:
Vector<Text> rows;
Alignment alignment { Alignment::Left };
size_t relative_width { 0 };
+
+ RecursionDecision walk(Visitor&) const;
};
Table() { }
@@ -34,6 +36,7 @@ public:
virtual String render_to_html(bool tight = false) const override;
virtual String render_for_terminal(size_t view_width = 0) const override;
+ virtual RecursionDecision walk(Visitor&) const override;
static OwnPtr<Table> parse(LineIterator& lines);
private:
diff --git a/Userland/Libraries/LibMarkdown/Text.cpp b/Userland/Libraries/LibMarkdown/Text.cpp
index 64a548fb1a..dfa72ab319 100644
--- a/Userland/Libraries/LibMarkdown/Text.cpp
+++ b/Userland/Libraries/LibMarkdown/Text.cpp
@@ -9,6 +9,7 @@
#include <AK/ScopeGuard.h>
#include <AK/StringBuilder.h>
#include <LibMarkdown/Text.h>
+#include <LibMarkdown/Visitor.h>
#include <ctype.h>
#include <string.h>
@@ -39,6 +40,15 @@ size_t Text::EmphasisNode::terminal_length() const
return child->terminal_length();
}
+RecursionDecision Text::EmphasisNode::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return child->walk(visitor);
+}
+
void Text::CodeNode::render_to_html(StringBuilder& builder) const
{
builder.append("<code>");
@@ -58,6 +68,15 @@ size_t Text::CodeNode::terminal_length() const
return code->terminal_length();
}
+RecursionDecision Text::CodeNode::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return code->walk(visitor);
+}
+
void Text::BreakNode::render_to_html(StringBuilder& builder) const
{
builder.append("<br />");
@@ -72,6 +91,15 @@ size_t Text::BreakNode::terminal_length() const
return 0;
}
+RecursionDecision Text::BreakNode::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+ // Normalize return value
+ return RecursionDecision::Continue;
+}
+
void Text::TextNode::render_to_html(StringBuilder& builder) const
{
builder.append(escape_html_entities(text));
@@ -95,6 +123,18 @@ size_t Text::TextNode::terminal_length() const
return text.length();
}
+RecursionDecision Text::TextNode::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+ rd = visitor.visit(text);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+ // Normalize return value
+ return RecursionDecision::Continue;
+}
+
void Text::LinkNode::render_to_html(StringBuilder& builder) const
{
if (is_image) {
@@ -134,6 +174,17 @@ size_t Text::LinkNode::terminal_length() const
return text->terminal_length();
}
+RecursionDecision Text::LinkNode::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ // Don't recurse on href.
+
+ return text->walk(visitor);
+}
+
void Text::MultiNode::render_to_html(StringBuilder& builder) const
{
for (auto& child : children) {
@@ -157,6 +208,21 @@ size_t Text::MultiNode::terminal_length() const
return length;
}
+RecursionDecision Text::MultiNode::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ for (auto const& child : children) {
+ rd = child.walk(visitor);
+ if (rd == RecursionDecision::Break)
+ return rd;
+ }
+
+ return RecursionDecision::Continue;
+}
+
size_t Text::terminal_length() const
{
return m_node->terminal_length();
@@ -176,6 +242,15 @@ String Text::render_for_terminal() const
return builder.build().trim(" \n\t");
}
+RecursionDecision Text::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return m_node->walk(visitor);
+}
+
Text Text::parse(StringView const& str)
{
Text text;
diff --git a/Userland/Libraries/LibMarkdown/Text.h b/Userland/Libraries/LibMarkdown/Text.h
index bacfedb0e2..7549fb94eb 100644
--- a/Userland/Libraries/LibMarkdown/Text.h
+++ b/Userland/Libraries/LibMarkdown/Text.h
@@ -10,7 +10,9 @@
#include <AK/Noncopyable.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/OwnPtr.h>
+#include <AK/RecursionDecision.h>
#include <AK/String.h>
+#include <LibMarkdown/Forward.h>
namespace Markdown {
@@ -21,6 +23,7 @@ public:
virtual void render_to_html(StringBuilder& builder) const = 0;
virtual void render_for_terminal(StringBuilder& builder) const = 0;
virtual size_t terminal_length() const = 0;
+ virtual RecursionDecision walk(Visitor&) const = 0;
virtual ~Node() { }
};
@@ -39,6 +42,7 @@ public:
virtual void render_to_html(StringBuilder& builder) const override;
virtual void render_for_terminal(StringBuilder& builder) const override;
virtual size_t terminal_length() const override;
+ virtual RecursionDecision walk(Visitor&) const override;
};
class CodeNode : public Node {
@@ -53,6 +57,7 @@ public:
virtual void render_to_html(StringBuilder& builder) const override;
virtual void render_for_terminal(StringBuilder& builder) const override;
virtual size_t terminal_length() const override;
+ virtual RecursionDecision walk(Visitor&) const override;
};
class BreakNode : public Node {
@@ -60,6 +65,7 @@ public:
virtual void render_to_html(StringBuilder& builder) const override;
virtual void render_for_terminal(StringBuilder& builder) const override;
virtual size_t terminal_length() const override;
+ virtual RecursionDecision walk(Visitor&) const override;
};
class TextNode : public Node {
@@ -82,6 +88,7 @@ public:
virtual void render_to_html(StringBuilder& builder) const override;
virtual void render_for_terminal(StringBuilder& builder) const override;
virtual size_t terminal_length() const override;
+ virtual RecursionDecision walk(Visitor&) const override;
};
class LinkNode : public Node {
@@ -100,6 +107,7 @@ public:
virtual void render_to_html(StringBuilder& builder) const override;
virtual void render_for_terminal(StringBuilder& builder) const override;
virtual size_t terminal_length() const override;
+ virtual RecursionDecision walk(Visitor&) const override;
};
class MultiNode : public Node {
@@ -109,12 +117,14 @@ public:
virtual void render_to_html(StringBuilder& builder) const override;
virtual void render_for_terminal(StringBuilder& builder) const override;
virtual size_t terminal_length() const override;
+ virtual RecursionDecision walk(Visitor&) const override;
};
size_t terminal_length() const;
String render_to_html() const;
String render_for_terminal() const;
+ RecursionDecision walk(Visitor&) const;
static Text parse(StringView const&);
diff --git a/Userland/Libraries/LibMarkdown/Visitor.h b/Userland/Libraries/LibMarkdown/Visitor.h
new file mode 100644
index 0000000000..d2035811a9
--- /dev/null
+++ b/Userland/Libraries/LibMarkdown/Visitor.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RecursionDecision.h>
+#include <LibMarkdown/BlockQuote.h>
+#include <LibMarkdown/CodeBlock.h>
+#include <LibMarkdown/Document.h>
+#include <LibMarkdown/Heading.h>
+#include <LibMarkdown/HorizontalRule.h>
+#include <LibMarkdown/List.h>
+#include <LibMarkdown/Paragraph.h>
+#include <LibMarkdown/Table.h>
+
+namespace Markdown {
+
+class Visitor {
+public:
+ Visitor() = default;
+ virtual ~Visitor() = default;
+
+ virtual RecursionDecision visit(Document const&) { return RecursionDecision::Recurse; }
+
+ virtual RecursionDecision visit(BlockQuote const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(CodeBlock const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(ContainerBlock const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Heading const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(HorizontalRule const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(List const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Paragraph const&) { return RecursionDecision::Recurse; }
+
+ virtual RecursionDecision visit(Table const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Table::Column const&) { return RecursionDecision::Recurse; }
+
+ virtual RecursionDecision visit(Text const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Text::BreakNode const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Text::CodeNode const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Text::EmphasisNode const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Text::LinkNode const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Text::MultiNode const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Text::TextNode const&) { return RecursionDecision::Recurse; }
+
+ virtual RecursionDecision visit(String const&) { return RecursionDecision::Recurse; }
+};
+
+}