diff options
-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; } |