From 5cc984d74c9453fa71ea8bb2d600d5bdb9135fb4 Mon Sep 17 00:00:00 2001 From: Arda Cinar Date: Fri, 23 Dec 2022 12:25:00 +0300 Subject: [PATCH] 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 :^) --- Userland/Libraries/LibMarkdown/Block.h | 2 +- Userland/Libraries/LibMarkdown/BlockQuote.cpp | 7 ++--- Userland/Libraries/LibMarkdown/BlockQuote.h | 2 +- Userland/Libraries/LibMarkdown/CodeBlock.cpp | 26 ++++++++++--------- Userland/Libraries/LibMarkdown/CodeBlock.h | 2 +- .../Libraries/LibMarkdown/CommentBlock.cpp | 5 ++-- Userland/Libraries/LibMarkdown/CommentBlock.h | 2 +- .../Libraries/LibMarkdown/ContainerBlock.cpp | 11 ++++---- .../Libraries/LibMarkdown/ContainerBlock.h | 2 +- Userland/Libraries/LibMarkdown/Document.cpp | 8 +++++- Userland/Libraries/LibMarkdown/Heading.cpp | 8 +++--- Userland/Libraries/LibMarkdown/Heading.h | 2 +- .../Libraries/LibMarkdown/HorizontalRule.cpp | 4 +-- .../Libraries/LibMarkdown/HorizontalRule.h | 2 +- Userland/Libraries/LibMarkdown/List.cpp | 24 ++++++++++++++--- Userland/Libraries/LibMarkdown/List.h | 2 +- Userland/Libraries/LibMarkdown/Paragraph.cpp | 9 +++---- Userland/Libraries/LibMarkdown/Paragraph.h | 2 +- Userland/Libraries/LibMarkdown/Table.cpp | 18 ++++++++----- Userland/Libraries/LibMarkdown/Table.h | 2 +- 20 files changed, 85 insertions(+), 55 deletions(-) diff --git a/Userland/Libraries/LibMarkdown/Block.h b/Userland/Libraries/LibMarkdown/Block.h index bbe276a910..ef4cd706d5 100644 --- a/Userland/Libraries/LibMarkdown/Block.h +++ b/Userland/Libraries/LibMarkdown/Block.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const = 0; virtual RecursionDecision walk(Visitor&) const = 0; }; diff --git a/Userland/Libraries/LibMarkdown/BlockQuote.cpp b/Userland/Libraries/LibMarkdown/BlockQuote.cpp index 03abca725a..6b91db1758 100644 --- a/Userland/Libraries/LibMarkdown/BlockQuote.cpp +++ b/Userland/Libraries/LibMarkdown/BlockQuote.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -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 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 diff --git a/Userland/Libraries/LibMarkdown/BlockQuote.h b/Userland/Libraries/LibMarkdown/BlockQuote.h index 44c49dc4a2..e09912e16c 100644 --- a/Userland/Libraries/LibMarkdown/BlockQuote.h +++ b/Userland/Libraries/LibMarkdown/BlockQuote.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr
parse(LineIterator& lines); diff --git a/Userland/Libraries/LibMarkdown/CodeBlock.cpp b/Userland/Libraries/LibMarkdown/CodeBlock.cpp index 709252bee6..1a2f1e753d 100644 --- a/Userland/Libraries/LibMarkdown/CodeBlock.cpp +++ b/Userland/Libraries/LibMarkdown/CodeBlock.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -53,22 +54,23 @@ DeprecatedString CodeBlock::render_to_html(bool) const return builder.build(); } -DeprecatedString CodeBlock::render_for_terminal(size_t) const +Vector CodeBlock::render_lines_for_terminal(size_t) const { - StringBuilder builder; + Vector 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 diff --git a/Userland/Libraries/LibMarkdown/CodeBlock.h b/Userland/Libraries/LibMarkdown/CodeBlock.h index 4ac55cc1bd..1163cf252e 100644 --- a/Userland/Libraries/LibMarkdown/CodeBlock.h +++ b/Userland/Libraries/LibMarkdown/CodeBlock.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr parse(LineIterator& lines, Heading* current_section); diff --git a/Userland/Libraries/LibMarkdown/CommentBlock.cpp b/Userland/Libraries/LibMarkdown/CommentBlock.cpp index edd68bd244..0b07ba7459 100644 --- a/Userland/Libraries/LibMarkdown/CommentBlock.cpp +++ b/Userland/Libraries/LibMarkdown/CommentBlock.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -22,9 +23,9 @@ DeprecatedString CommentBlock::render_to_html(bool) const return builder.build(); } -DeprecatedString CommentBlock::render_for_terminal(size_t) const +Vector CommentBlock::render_lines_for_terminal(size_t) const { - return ""; + return Vector {}; } RecursionDecision CommentBlock::walk(Visitor& visitor) const diff --git a/Userland/Libraries/LibMarkdown/CommentBlock.h b/Userland/Libraries/LibMarkdown/CommentBlock.h index 2ccde4dd63..381c536145 100644 --- a/Userland/Libraries/LibMarkdown/CommentBlock.h +++ b/Userland/Libraries/LibMarkdown/CommentBlock.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr parse(LineIterator& lines); diff --git a/Userland/Libraries/LibMarkdown/ContainerBlock.cpp b/Userland/Libraries/LibMarkdown/ContainerBlock.cpp index f137e470d3..5810b8276b 100644 --- a/Userland/Libraries/LibMarkdown/ContainerBlock.cpp +++ b/Userland/Libraries/LibMarkdown/ContainerBlock.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -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 ContainerBlock::render_lines_for_terminal(size_t view_width) const { - StringBuilder builder; + Vector 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 diff --git a/Userland/Libraries/LibMarkdown/ContainerBlock.h b/Userland/Libraries/LibMarkdown/ContainerBlock.h index 3ffc864f4a..c9666685a7 100644 --- a/Userland/Libraries/LibMarkdown/ContainerBlock.h +++ b/Userland/Libraries/LibMarkdown/ContainerBlock.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr parse(LineIterator& lines); diff --git a/Userland/Libraries/LibMarkdown/Document.cpp b/Userland/Libraries/LibMarkdown/Document.cpp index be35b81f8b..df088e326e 100644 --- a/Userland/Libraries/LibMarkdown/Document.cpp +++ b/Userland/Libraries/LibMarkdown/Document.cpp @@ -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 diff --git a/Userland/Libraries/LibMarkdown/Heading.cpp b/Userland/Libraries/LibMarkdown/Heading.cpp index 26611c8c62..e31db29959 100644 --- a/Userland/Libraries/LibMarkdown/Heading.cpp +++ b/Userland/Libraries/LibMarkdown/Heading.cpp @@ -15,7 +15,7 @@ DeprecatedString Heading::render_to_html(bool) const return DeprecatedString::formatted("{}\n", m_level, m_text.render_to_html(), m_level); } -DeprecatedString Heading::render_for_terminal(size_t) const +Vector 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 { builder.build() }; } RecursionDecision Heading::walk(Visitor& visitor) const diff --git a/Userland/Libraries/LibMarkdown/Heading.h b/Userland/Libraries/LibMarkdown/Heading.h index f084c304e7..37da2d0b97 100644 --- a/Userland/Libraries/LibMarkdown/Heading.h +++ b/Userland/Libraries/LibMarkdown/Heading.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr parse(LineIterator& lines); diff --git a/Userland/Libraries/LibMarkdown/HorizontalRule.cpp b/Userland/Libraries/LibMarkdown/HorizontalRule.cpp index 47ffb9ae73..472cfa9573 100644 --- a/Userland/Libraries/LibMarkdown/HorizontalRule.cpp +++ b/Userland/Libraries/LibMarkdown/HorizontalRule.cpp @@ -17,13 +17,13 @@ DeprecatedString HorizontalRule::render_to_html(bool) const return "
\n"; } -DeprecatedString HorizontalRule::render_for_terminal(size_t view_width) const +Vector 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 { builder.to_deprecated_string() }; } RecursionDecision HorizontalRule::walk(Visitor& visitor) const diff --git a/Userland/Libraries/LibMarkdown/HorizontalRule.h b/Userland/Libraries/LibMarkdown/HorizontalRule.h index 94f52d3aa1..5512358b1b 100644 --- a/Userland/Libraries/LibMarkdown/HorizontalRule.h +++ b/Userland/Libraries/LibMarkdown/HorizontalRule.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr parse(LineIterator& lines); }; diff --git a/Userland/Libraries/LibMarkdown/List.cpp b/Userland/Libraries/LibMarkdown/List.cpp index c7dd17c9c0..ac5a48e221 100644 --- a/Userland/Libraries/LibMarkdown/List.cpp +++ b/Userland/Libraries/LibMarkdown/List.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -37,21 +38,36 @@ DeprecatedString List::render_to_html(bool) const return builder.build(); } -DeprecatedString List::render_for_terminal(size_t) const +Vector List::render_lines_for_terminal(size_t view_width) const { - StringBuilder builder; + Vector 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 diff --git a/Userland/Libraries/LibMarkdown/List.h b/Userland/Libraries/LibMarkdown/List.h index 953ec85cd8..12779f4ad7 100644 --- a/Userland/Libraries/LibMarkdown/List.h +++ b/Userland/Libraries/LibMarkdown/List.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr parse(LineIterator& lines); diff --git a/Userland/Libraries/LibMarkdown/Paragraph.cpp b/Userland/Libraries/LibMarkdown/Paragraph.cpp index 72fc1ebb4e..afb0d2860d 100644 --- a/Userland/Libraries/LibMarkdown/Paragraph.cpp +++ b/Userland/Libraries/LibMarkdown/Paragraph.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -27,13 +28,9 @@ DeprecatedString Paragraph::render_to_html(bool tight) const return builder.build(); } -DeprecatedString Paragraph::render_for_terminal(size_t) const +Vector 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::formatted(" {}", m_text.render_for_terminal()), "" }; } RecursionDecision Paragraph::walk(Visitor& visitor) const diff --git a/Userland/Libraries/LibMarkdown/Paragraph.h b/Userland/Libraries/LibMarkdown/Paragraph.h index 082e130641..f0efb24547 100644 --- a/Userland/Libraries/LibMarkdown/Paragraph.h +++ b/Userland/Libraries/LibMarkdown/Paragraph.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; private: diff --git a/Userland/Libraries/LibMarkdown/Table.cpp b/Userland/Libraries/LibMarkdown/Table.cpp index dfebf833e9..d1f8b37aab 100644 --- a/Userland/Libraries/LibMarkdown/Table.cpp +++ b/Userland/Libraries/LibMarkdown/Table.cpp @@ -6,15 +6,17 @@ #include #include +#include #include #include namespace Markdown { -DeprecatedString Table::render_for_terminal(size_t view_width) const +Vector 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 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 diff --git a/Userland/Libraries/LibMarkdown/Table.h b/Userland/Libraries/LibMarkdown/Table.h index a78ea33b8c..5f243d8e8f 100644 --- a/Userland/Libraries/LibMarkdown/Table.h +++ b/Userland/Libraries/LibMarkdown/Table.h @@ -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 render_lines_for_terminal(size_t view_width = 0) const override; virtual RecursionDecision walk(Visitor&) const override; static OwnPtr parse(LineIterator& lines);