LibMarkdown: Render lines to terminal instead of a single string
With this patch, the blocks in a markdown document render a vector of lines. These lines get concatenated in Document::render_to_terminal, so this does not change any external APIs of LibMarkdown. This change makes it possible to indent individual lines in the rendered markdown. So, rendering blockquotes in a similar way to code blocks :^)
This commit is contained in:
parent
7a4b912ece
commit
5cc984d74c
Notes:
sideshowbarker
2024-07-17 02:24:10 +09:00
Author: https://github.com/kuzux Commit: https://github.com/SerenityOS/serenity/commit/5cc984d74c Pull-request: https://github.com/SerenityOS/serenity/pull/16633 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/kleinesfilmroellchen ✅
20 changed files with 85 additions and 55 deletions
|
@ -19,7 +19,7 @@ public:
|
|||
virtual ~Block() = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const = 0;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const = 0;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const = 0;
|
||||
virtual RecursionDecision walk(Visitor&) const = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibMarkdown/BlockQuote.h>
|
||||
#include <LibMarkdown/Visitor.h>
|
||||
|
||||
|
@ -19,10 +20,10 @@ DeprecatedString BlockQuote::render_to_html(bool) const
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
DeprecatedString BlockQuote::render_for_terminal(size_t view_width) const
|
||||
Vector<DeprecatedString> BlockQuote::render_lines_for_terminal(size_t view_width) const
|
||||
{
|
||||
// FIXME: Rewrite the whole terminal renderer to make blockquote rendering possible
|
||||
return m_contents->render_for_terminal(view_width);
|
||||
// FIXME: Indent lines inside the blockquote
|
||||
return m_contents->render_lines_for_terminal(view_width);
|
||||
}
|
||||
|
||||
RecursionDecision BlockQuote::walk(Visitor& visitor) const
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
virtual ~BlockQuote() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
|
||||
static OwnPtr<BlockQuote> parse(LineIterator& lines);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/MarkupGenerator.h>
|
||||
#include <LibMarkdown/CodeBlock.h>
|
||||
|
@ -53,22 +54,23 @@ DeprecatedString CodeBlock::render_to_html(bool) const
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
DeprecatedString CodeBlock::render_for_terminal(size_t) const
|
||||
Vector<DeprecatedString> CodeBlock::render_lines_for_terminal(size_t) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
Vector<DeprecatedString> lines;
|
||||
|
||||
for (auto const& line : m_code.split('\n')) {
|
||||
// Do not indent too much if we are in the synopsis
|
||||
if (!(m_current_section && m_current_section->render_for_terminal().contains("SYNOPSIS"sv)))
|
||||
builder.append(" "sv);
|
||||
|
||||
builder.append(" "sv);
|
||||
builder.append(line);
|
||||
builder.append("\n"sv);
|
||||
// Do not indent too much if we are in the synopsis
|
||||
auto indentation = " "sv;
|
||||
if (m_current_section != nullptr) {
|
||||
auto current_section_name = m_current_section->render_lines_for_terminal()[0];
|
||||
if (current_section_name.contains("SYNOPSIS"sv))
|
||||
indentation = " "sv;
|
||||
}
|
||||
builder.append("\n"sv);
|
||||
|
||||
return builder.build();
|
||||
for (auto const& line : m_code.split('\n'))
|
||||
lines.append(DeprecatedString::formatted("{}{}", indentation, line));
|
||||
lines.append("");
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
RecursionDecision CodeBlock::walk(Visitor& visitor) const
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
virtual ~CodeBlock() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
static OwnPtr<CodeBlock> parse(LineIterator& lines, Heading* current_section);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibMarkdown/CommentBlock.h>
|
||||
#include <LibMarkdown/Visitor.h>
|
||||
|
@ -22,9 +23,9 @@ DeprecatedString CommentBlock::render_to_html(bool) const
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
DeprecatedString CommentBlock::render_for_terminal(size_t) const
|
||||
Vector<DeprecatedString> CommentBlock::render_lines_for_terminal(size_t) const
|
||||
{
|
||||
return "";
|
||||
return Vector<DeprecatedString> {};
|
||||
}
|
||||
|
||||
RecursionDecision CommentBlock::walk(Visitor& visitor) const
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
virtual ~CommentBlock() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
static OwnPtr<CommentBlock> parse(LineIterator& lines);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibMarkdown/BlockQuote.h>
|
||||
#include <LibMarkdown/CodeBlock.h>
|
||||
#include <LibMarkdown/ContainerBlock.h>
|
||||
|
@ -39,16 +40,16 @@ DeprecatedString ContainerBlock::render_to_html(bool tight) const
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
DeprecatedString ContainerBlock::render_for_terminal(size_t view_width) const
|
||||
Vector<DeprecatedString> ContainerBlock::render_lines_for_terminal(size_t view_width) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
Vector<DeprecatedString> lines;
|
||||
|
||||
for (auto& block : m_blocks) {
|
||||
auto s = block.render_for_terminal(view_width);
|
||||
builder.append(s);
|
||||
for (auto& line : block.render_lines_for_terminal(view_width))
|
||||
lines.append(move(line));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
return lines;
|
||||
}
|
||||
|
||||
RecursionDecision ContainerBlock::walk(Visitor& visitor) const
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
virtual ~ContainerBlock() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
|
||||
static OwnPtr<ContainerBlock> parse(LineIterator& lines);
|
||||
|
|
|
@ -45,7 +45,13 @@ DeprecatedString Document::render_to_inline_html() const
|
|||
|
||||
DeprecatedString Document::render_for_terminal(size_t view_width) const
|
||||
{
|
||||
return m_container->render_for_terminal(view_width);
|
||||
StringBuilder builder;
|
||||
for (auto& line : m_container->render_lines_for_terminal(view_width)) {
|
||||
builder.append(line);
|
||||
builder.append("\n"sv);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
RecursionDecision Document::walk(Visitor& visitor) const
|
||||
|
|
|
@ -15,7 +15,7 @@ DeprecatedString Heading::render_to_html(bool) const
|
|||
return DeprecatedString::formatted("<h{}>{}</h{}>\n", m_level, m_text.render_to_html(), m_level);
|
||||
}
|
||||
|
||||
DeprecatedString Heading::render_for_terminal(size_t) const
|
||||
Vector<DeprecatedString> Heading::render_lines_for_terminal(size_t) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
|
||||
|
@ -24,15 +24,15 @@ DeprecatedString Heading::render_for_terminal(size_t) const
|
|||
case 1:
|
||||
case 2:
|
||||
builder.append(m_text.render_for_terminal().to_uppercase());
|
||||
builder.append("\033[0m\n"sv);
|
||||
builder.append("\033[0m"sv);
|
||||
break;
|
||||
default:
|
||||
builder.append(m_text.render_for_terminal());
|
||||
builder.append("\033[0m\n"sv);
|
||||
builder.append("\033[0m"sv);
|
||||
break;
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
return Vector<DeprecatedString> { builder.build() };
|
||||
}
|
||||
|
||||
RecursionDecision Heading::walk(Visitor& visitor) const
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
virtual ~Heading() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
static OwnPtr<Heading> parse(LineIterator& lines);
|
||||
|
||||
|
|
|
@ -17,13 +17,13 @@ DeprecatedString HorizontalRule::render_to_html(bool) const
|
|||
return "<hr />\n";
|
||||
}
|
||||
|
||||
DeprecatedString HorizontalRule::render_for_terminal(size_t view_width) const
|
||||
Vector<DeprecatedString> HorizontalRule::render_lines_for_terminal(size_t view_width) const
|
||||
{
|
||||
StringBuilder builder(view_width + 1);
|
||||
for (size_t i = 0; i < view_width; ++i)
|
||||
builder.append('-');
|
||||
builder.append("\n\n"sv);
|
||||
return builder.to_deprecated_string();
|
||||
return Vector<DeprecatedString> { builder.to_deprecated_string() };
|
||||
}
|
||||
|
||||
RecursionDecision HorizontalRule::walk(Visitor& visitor) const
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
virtual ~HorizontalRule() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
static OwnPtr<HorizontalRule> parse(LineIterator& lines);
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibMarkdown/List.h>
|
||||
#include <LibMarkdown/Paragraph.h>
|
||||
|
@ -37,21 +38,36 @@ DeprecatedString List::render_to_html(bool) const
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
DeprecatedString List::render_for_terminal(size_t) const
|
||||
Vector<DeprecatedString> List::render_lines_for_terminal(size_t view_width) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
Vector<DeprecatedString> lines;
|
||||
|
||||
int i = 0;
|
||||
for (auto& item : m_items) {
|
||||
auto item_lines = item->render_lines_for_terminal(view_width);
|
||||
auto first_line = item_lines.take_first();
|
||||
|
||||
StringBuilder builder;
|
||||
builder.append(" "sv);
|
||||
if (m_is_ordered)
|
||||
builder.appendff("{}.", ++i);
|
||||
else
|
||||
builder.append('*');
|
||||
builder.append(item->render_for_terminal());
|
||||
auto item_indentation = builder.length();
|
||||
|
||||
builder.append(first_line);
|
||||
|
||||
lines.append(builder.build());
|
||||
|
||||
for (auto& line : item_lines) {
|
||||
builder.clear();
|
||||
builder.append(DeprecatedString::repeated(' ', item_indentation));
|
||||
builder.append(line);
|
||||
lines.append(builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
return lines;
|
||||
}
|
||||
|
||||
RecursionDecision List::walk(Visitor& visitor) const
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
virtual ~List() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
|
||||
static OwnPtr<List> parse(LineIterator& lines);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibMarkdown/Paragraph.h>
|
||||
#include <LibMarkdown/Visitor.h>
|
||||
|
@ -27,13 +28,9 @@ DeprecatedString Paragraph::render_to_html(bool tight) const
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
DeprecatedString Paragraph::render_for_terminal(size_t) const
|
||||
Vector<DeprecatedString> Paragraph::render_lines_for_terminal(size_t) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
builder.append(" "sv);
|
||||
builder.append(m_text.render_for_terminal());
|
||||
builder.append("\n\n"sv);
|
||||
return builder.build();
|
||||
return Vector<DeprecatedString> { DeprecatedString::formatted(" {}", m_text.render_for_terminal()), "" };
|
||||
}
|
||||
|
||||
RecursionDecision Paragraph::walk(Visitor& visitor) const
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
virtual ~Paragraph() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -6,15 +6,17 @@
|
|||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibMarkdown/Table.h>
|
||||
#include <LibMarkdown/Visitor.h>
|
||||
|
||||
namespace Markdown {
|
||||
|
||||
DeprecatedString Table::render_for_terminal(size_t view_width) const
|
||||
Vector<DeprecatedString> Table::render_lines_for_terminal(size_t view_width) const
|
||||
{
|
||||
auto unit_width_length = view_width == 0 ? 4 : ((float)(view_width - m_columns.size()) / (float)m_total_width);
|
||||
StringBuilder builder;
|
||||
Vector<DeprecatedString> lines;
|
||||
|
||||
auto write_aligned = [&](auto const& text, auto width, auto alignment) {
|
||||
size_t original_length = text.terminal_length();
|
||||
|
@ -42,10 +44,13 @@ DeprecatedString Table::render_for_terminal(size_t view_width) const
|
|||
write_aligned(col.header, width, col.alignment);
|
||||
}
|
||||
|
||||
builder.append('\n');
|
||||
lines.append(builder.build());
|
||||
builder.clear();
|
||||
|
||||
for (size_t i = 0; i < view_width; ++i)
|
||||
builder.append('-');
|
||||
builder.append('\n');
|
||||
lines.append(builder.build());
|
||||
builder.clear();
|
||||
|
||||
for (size_t i = 0; i < m_row_count; ++i) {
|
||||
bool first = true;
|
||||
|
@ -60,12 +65,13 @@ DeprecatedString Table::render_for_terminal(size_t view_width) const
|
|||
size_t width = col.relative_width * unit_width_length;
|
||||
write_aligned(cell, width, col.alignment);
|
||||
}
|
||||
builder.append('\n');
|
||||
lines.append(builder.build());
|
||||
builder.clear();
|
||||
}
|
||||
|
||||
builder.append('\n');
|
||||
lines.append("");
|
||||
|
||||
return builder.to_deprecated_string();
|
||||
return lines;
|
||||
}
|
||||
|
||||
DeprecatedString Table::render_to_html(bool) const
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
virtual ~Table() override = default;
|
||||
|
||||
virtual DeprecatedString render_to_html(bool tight = false) const override;
|
||||
virtual DeprecatedString render_for_terminal(size_t view_width = 0) const override;
|
||||
virtual Vector<DeprecatedString> render_lines_for_terminal(size_t view_width = 0) const override;
|
||||
virtual RecursionDecision walk(Visitor&) const override;
|
||||
static OwnPtr<Table> parse(LineIterator& lines);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue