summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Userland/Libraries/LibMarkdown/LineIterator.cpp56
-rw-r--r--Userland/Libraries/LibMarkdown/LineIterator.h47
-rw-r--r--Userland/Libraries/LibMarkdown/List.cpp6
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;
}