Jelajahi Sumber

LibMarkdown: Recognize and handle comments

This also improves Commonmark coverage, e.g. it fixes tests
HTML_blocks_ex179_2894..2906 and Lists_ex308_5439..5457.

In other words, we go from 271 out of 652 to 273 out of 652.
Ben Wiederhake 3 tahun lalu
induk
melakukan
d2f9fee4ab

+ 1 - 0
Userland/Libraries/LibMarkdown/CMakeLists.txt

@@ -1,6 +1,7 @@
 set(SOURCES
     BlockQuote.cpp
     CodeBlock.cpp
+    CommentBlock.cpp
     ContainerBlock.cpp
     Document.cpp
     Heading.cpp

+ 74 - 0
Userland/Libraries/LibMarkdown/CommentBlock.cpp

@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2021, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/StringBuilder.h>
+#include <LibMarkdown/CommentBlock.h>
+#include <LibMarkdown/Visitor.h>
+
+namespace Markdown {
+
+String CommentBlock::render_to_html(bool) const
+{
+    StringBuilder builder;
+
+    builder.append("<!--");
+    builder.append(escape_html_entities(m_comment));
+    // TODO: This is probably incorrect, because we technically need to escape "--" in some form. However, Browser does not care about this.
+    builder.append("-->\n");
+
+    return builder.build();
+}
+
+String CommentBlock::render_for_terminal(size_t) const
+{
+    return "";
+}
+
+RecursionDecision CommentBlock::walk(Visitor& visitor) const
+{
+    RecursionDecision rd = visitor.visit(*this);
+    if (rd != RecursionDecision::Recurse)
+        return rd;
+
+    // Normalize return value.
+    return RecursionDecision::Continue;
+}
+
+OwnPtr<CommentBlock> CommentBlock::parse(LineIterator& lines)
+{
+    if (lines.is_end())
+        return {};
+
+    constexpr auto comment_start = "<!--"sv;
+    constexpr auto comment_end = "-->"sv;
+
+    StringView line = *lines;
+    if (!line.starts_with(comment_start))
+        return {};
+    line = line.substring_view(comment_start.length());
+
+    StringBuilder builder;
+
+    while (true) {
+        // Invariant: At the beginning of the loop, `line` is valid and should be added the the builder.
+        bool ends_here = line.ends_with(comment_end);
+        if (ends_here)
+            line = line.substring_view(0, line.length() - comment_end.length());
+        builder.append(line);
+        if (!ends_here)
+            builder.append('\n');
+
+        ++lines;
+        if (lines.is_end() || ends_here) {
+            break;
+        }
+        line = *lines;
+    }
+
+    return make<CommentBlock>(builder.build());
+}
+
+}

+ 33 - 0
Userland/Libraries/LibMarkdown/CommentBlock.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/OwnPtr.h>
+#include <AK/String.h>
+#include <LibMarkdown/Block.h>
+#include <LibMarkdown/LineIterator.h>
+
+namespace Markdown {
+
+class CommentBlock final : public Block {
+public:
+    CommentBlock(String const& comment)
+        : m_comment(comment)
+    {
+    }
+    virtual ~CommentBlock() override { }
+
+    virtual String render_to_html(bool tight = false) const override;
+    virtual String render_for_terminal(size_t view_width = 0) const override;
+    virtual RecursionDecision walk(Visitor&) const override;
+    static OwnPtr<CommentBlock> parse(LineIterator& lines);
+
+private:
+    String m_comment;
+};
+
+}

+ 6 - 2
Userland/Libraries/LibMarkdown/ContainerBlock.cpp

@@ -107,8 +107,12 @@ OwnPtr<ContainerBlock> ContainerBlock::parse(LineIterator& lines)
             has_blank_lines = has_blank_lines || has_trailing_blank_lines;
         }
 
-        bool any = try_parse_block<Table>(lines, blocks) || try_parse_block<List>(lines, blocks) || try_parse_block<CodeBlock>(lines, blocks)
-            || try_parse_block<Heading>(lines, blocks) || try_parse_block<HorizontalRule>(lines, blocks)
+        bool any = try_parse_block<Table>(lines, blocks)
+            || try_parse_block<List>(lines, blocks)
+            || try_parse_block<CodeBlock>(lines, blocks)
+            || try_parse_block<CommentBlock>(lines, blocks)
+            || try_parse_block<Heading>(lines, blocks)
+            || try_parse_block<HorizontalRule>(lines, blocks)
             || try_parse_block<BlockQuote>(lines, blocks);
 
         if (any) {

+ 2 - 0
Userland/Libraries/LibMarkdown/Visitor.h

@@ -9,6 +9,7 @@
 #include <AK/RecursionDecision.h>
 #include <LibMarkdown/BlockQuote.h>
 #include <LibMarkdown/CodeBlock.h>
+#include <LibMarkdown/CommentBlock.h>
 #include <LibMarkdown/Document.h>
 #include <LibMarkdown/Heading.h>
 #include <LibMarkdown/HorizontalRule.h>
@@ -27,6 +28,7 @@ public:
 
     virtual RecursionDecision visit(BlockQuote const&) { return RecursionDecision::Recurse; }
     virtual RecursionDecision visit(CodeBlock const&) { return RecursionDecision::Recurse; }
+    virtual RecursionDecision visit(CommentBlock const&) { return RecursionDecision::Recurse; }
     virtual RecursionDecision visit(ContainerBlock const&) { return RecursionDecision::Recurse; }
     virtual RecursionDecision visit(Heading const&) { return RecursionDecision::Recurse; }
     virtual RecursionDecision visit(HorizontalRule const&) { return RecursionDecision::Recurse; }