1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 00:47:45 +00:00

LibMarkdown: Allow non-text items in Lists

This commit is contained in:
Peter Elliott 2021-09-26 20:14:58 -06:00 committed by Ali Mohammad Pur
parent 10f6f6a723
commit 5bb87c630c
2 changed files with 33 additions and 53 deletions

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
* Copyright (c) 2021, Peter Elliott <pelliott@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -17,8 +18,8 @@ String List::render_to_html() const
builder.appendff("<{}>\n", tag); builder.appendff("<{}>\n", tag);
for (auto& item : m_items) { for (auto& item : m_items) {
builder.append("<li>"); builder.append("<li>\n");
builder.append(item.render_to_html()); builder.append(item->render_to_html());
builder.append("</li>\n"); builder.append("</li>\n");
} }
@ -38,7 +39,7 @@ String List::render_for_terminal(size_t) const
builder.appendff("{}. ", ++i); builder.appendff("{}. ", ++i);
else else
builder.append("* "); builder.append("* ");
builder.append(item.render_for_terminal()); builder.append(item->render_for_terminal());
builder.append("\n"); builder.append("\n");
} }
builder.append("\n"); builder.append("\n");
@ -48,26 +49,13 @@ String List::render_for_terminal(size_t) const
OwnPtr<List> List::parse(LineIterator& lines) OwnPtr<List> List::parse(LineIterator& lines)
{ {
Vector<Text> items; Vector<OwnPtr<ContainerBlock>> items;
bool is_ordered = false;
bool first = true; bool first = true;
bool is_ordered = false;
while (!lines.is_end()) {
size_t offset = 0; size_t offset = 0;
StringBuilder item_builder;
auto flush_item_if_needed = [&] {
if (first)
return true;
auto text = Text::parse(item_builder.string_view());
items.append(move(text));
item_builder.clear();
return true;
};
while (true) {
if (lines.is_end())
break;
const StringView& line = *lines; const StringView& line = *lines;
if (line.is_empty()) if (line.is_empty())
break; break;
@ -76,7 +64,7 @@ OwnPtr<List> List::parse(LineIterator& lines)
if (line.length() > 2) { if (line.length() > 2) {
if (line[1] == ' ' && (line[0] == '*' || line[0] == '-')) { if (line[1] == ' ' && (line[0] == '*' || line[0] == '-')) {
appears_unordered = true; appears_unordered = true;
offset = 2; offset = 1;
} }
} }
@ -94,39 +82,33 @@ OwnPtr<List> List::parse(LineIterator& lines)
} }
VERIFY(!(appears_unordered && appears_ordered)); VERIFY(!(appears_unordered && appears_ordered));
if (!appears_unordered && !appears_ordered) {
if (appears_unordered || appears_ordered) {
if (first) if (first)
is_ordered = appears_ordered;
else if (is_ordered != appears_ordered)
return {}; return {};
if (!flush_item_if_needed()) break;
return {}; }
while (offset + 1 < line.length() && line[offset + 1] == ' ') while (offset < line.length() && line[offset] == ' ')
offset++; offset++;
} else { if (first) {
if (first) is_ordered = appears_ordered;
return {}; } else if (appears_ordered != is_ordered) {
for (size_t i = 0; i < offset; i++) { break;
if (line[i] != ' ')
return {};
}
} }
size_t saved_indent = lines.indent();
lines.set_indent(saved_indent + offset);
lines.ignore_next_prefix();
items.append(ContainerBlock::parse(lines));
lines.set_indent(saved_indent);
first = false; first = false;
if (!item_builder.is_empty())
item_builder.append(' ');
VERIFY(offset <= line.length());
item_builder.append(line.substring_view(offset, line.length() - offset));
++lines;
offset = 0;
} }
if (!flush_item_if_needed() || first)
return {};
return make<List>(move(items), is_ordered); return make<List>(move(items), is_ordered);
} }

View file

@ -7,17 +7,16 @@
#pragma once #pragma once
#include <AK/OwnPtr.h> #include <AK/OwnPtr.h>
#include <AK/Vector.h>
#include <LibMarkdown/Block.h> #include <LibMarkdown/Block.h>
#include <LibMarkdown/ContainerBlock.h>
#include <LibMarkdown/LineIterator.h> #include <LibMarkdown/LineIterator.h>
#include <LibMarkdown/Text.h>
namespace Markdown { namespace Markdown {
class List final : public Block { class List final : public Block {
public: public:
List(Vector<Text>&& text, bool is_ordered) List(Vector<OwnPtr<ContainerBlock>> items, bool is_ordered)
: m_items(move(text)) : m_items(move(items))
, m_is_ordered(is_ordered) , m_is_ordered(is_ordered)
{ {
} }
@ -29,8 +28,7 @@ public:
static OwnPtr<List> parse(LineIterator& lines); static OwnPtr<List> parse(LineIterator& lines);
private: private:
// TODO: List items should be considered blocks of their own kind. Vector<OwnPtr<ContainerBlock>> m_items;
Vector<Text> m_items;
bool m_is_ordered { false }; bool m_is_ordered { false };
}; };