diff options
author | Peter Elliott <pelliott@ualberta.ca> | 2021-10-03 21:45:10 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-10-06 12:35:46 +0200 |
commit | 2227a80f34d0a5fa02b4d7d782710d7845932e49 (patch) | |
tree | 83e9ffc118bfcc4fad27a82729b703ac96854708 /Userland/Libraries/LibMarkdown | |
parent | 4b091a7cc27ef07ba5c0d46a02454ecbb16f6575 (diff) | |
download | serenity-2227a80f34d0a5fa02b4d7d782710d7845932e49.zip |
LibMarkdown: Add blockquote support to LineIterator
This patch adds contexts to line iterator for nesting list items and
blockquotes. It also incidentally makes the api for LineIterator
simpler, and will make it easier to add other containers in the future.
Diffstat (limited to 'Userland/Libraries/LibMarkdown')
-rw-r--r-- | Userland/Libraries/LibMarkdown/LineIterator.cpp | 56 | ||||
-rw-r--r-- | Userland/Libraries/LibMarkdown/LineIterator.h | 47 | ||||
-rw-r--r-- | Userland/Libraries/LibMarkdown/List.cpp | 6 |
3 files changed, 78 insertions, 31 deletions
diff --git a/Userland/Libraries/LibMarkdown/LineIterator.cpp b/Userland/Libraries/LibMarkdown/LineIterator.cpp index 6966112be8..ec77ca1642 100644 --- a/Userland/Libraries/LibMarkdown/LineIterator.cpp +++ b/Userland/Libraries/LibMarkdown/LineIterator.cpp @@ -4,38 +4,62 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/Format.h> #include <LibMarkdown/LineIterator.h> namespace Markdown { -bool LineIterator::is_indented(StringView const& line) const +void LineIterator::reset_ignore_prefix() { - if (line.is_whitespace()) - return true; + for (auto& context : m_context_stack) { + context.ignore_prefix = false; + } +} - if (line.length() < m_indent) - return false; +Optional<StringView> LineIterator::match_context(StringView const& line) const +{ + bool is_ws = line.is_whitespace(); + size_t offset = 0; + for (auto& context : m_context_stack) { + switch (context.type) { + case Context::Type::ListItem: + if (is_ws) + break; - for (size_t i = 0; i < m_indent; ++i) { - if (line[i] != ' ') - return false; - } + if (offset + context.indent > line.length()) + return {}; + + if (!context.ignore_prefix && !line.substring_view(offset, context.indent).is_whitespace()) + return {}; - return true; + offset += context.indent; + + break; + case Context::Type::BlockQuote: + for (; offset < line.length() && line[offset] == ' '; ++offset) { } + if (offset >= line.length() || line[offset] != '>') { + return {}; + } + ++offset; + break; + } + + if (offset > line.length()) + return {}; + } + return line.substring_view(offset); } bool LineIterator::is_end() const { - return m_iterator.is_end() || (!m_ignore_prefix_mode && !is_indented(*m_iterator)); + return m_iterator.is_end() || !match_context(*m_iterator).has_value(); } StringView LineIterator::operator*() const { - VERIFY(m_ignore_prefix_mode || is_indented(*m_iterator)); - if (m_iterator->is_whitespace()) - return *m_iterator; - - return m_iterator->substring_view(m_indent); + auto line = match_context(*m_iterator); + VERIFY(line.has_value()); + return line.value(); } } diff --git a/Userland/Libraries/LibMarkdown/LineIterator.h b/Userland/Libraries/LibMarkdown/LineIterator.h index 04faad3b4e..8109e1d8e4 100644 --- a/Userland/Libraries/LibMarkdown/LineIterator.h +++ b/Userland/Libraries/LibMarkdown/LineIterator.h @@ -29,9 +29,22 @@ private: class LineIterator { public: - LineIterator(Vector<StringView>::ConstIterator const& lines, size_t indent = 0) + struct Context { + enum class Type { + ListItem, + BlockQuote, + }; + + Type type; + size_t indent; + bool ignore_prefix; + + static Context list_item(size_t indent) { return { Type::ListItem, indent, true }; } + static Context block_quote() { return { Type::BlockQuote, 0, false }; } + }; + + LineIterator(Vector<StringView>::ConstIterator const& lines) : m_iterator(lines) - , m_indent(indent) { } @@ -53,23 +66,35 @@ public: return tmp; } - LineIterator operator+(ptrdiff_t delta) const { return LineIterator { m_iterator + delta, m_indent }; } - LineIterator operator-(ptrdiff_t delta) const { return LineIterator { m_iterator - delta, m_indent }; } + LineIterator operator+(ptrdiff_t delta) const + { + LineIterator copy = *this; + copy.reset_ignore_prefix(); + copy.m_iterator = copy.m_iterator + delta; + return copy; + } + + LineIterator operator-(ptrdiff_t delta) const + { + LineIterator copy = *this; + copy.reset_ignore_prefix(); + copy.m_iterator = copy.m_iterator - delta; + return copy; + } + ptrdiff_t operator-(LineIterator other) const { return m_iterator - other.m_iterator; } FakePtr<StringView> operator->() const { return FakePtr<StringView>(operator*()); } - size_t indent() const { return m_indent; } - void set_indent(size_t indent) { m_indent = indent; } - void ignore_next_prefix() { m_ignore_prefix_mode = true; } + void push_context(Context context) { m_context_stack.append(move(context)); } + void pop_context() { m_context_stack.take_last(); } private: - void reset_ignore_prefix() { m_ignore_prefix_mode = false; } - bool is_indented(StringView const& line) const; + void reset_ignore_prefix(); + Optional<StringView> match_context(StringView const& line) const; Vector<StringView>::ConstIterator m_iterator; - size_t m_indent; - bool m_ignore_prefix_mode { false }; + Vector<Context> m_context_stack; }; } diff --git a/Userland/Libraries/LibMarkdown/List.cpp b/Userland/Libraries/LibMarkdown/List.cpp index 0b4df3584c..5308ec4b47 100644 --- a/Userland/Libraries/LibMarkdown/List.cpp +++ b/Userland/Libraries/LibMarkdown/List.cpp @@ -121,16 +121,14 @@ OwnPtr<List> List::parse(LineIterator& lines) is_tight = is_tight && !has_trailing_blank_lines; - size_t saved_indent = lines.indent(); - lines.set_indent(saved_indent + offset); - lines.ignore_next_prefix(); + lines.push_context(LineIterator::Context::list_item(offset)); auto list_item = ContainerBlock::parse(lines); is_tight = is_tight && !list_item->has_blank_lines(); has_trailing_blank_lines = has_trailing_blank_lines || list_item->has_trailing_blank_lines(); items.append(move(list_item)); - lines.set_indent(saved_indent); + lines.pop_context(); first = false; } |