diff --git a/Userland/Libraries/LibMarkdown/Text.cpp b/Userland/Libraries/LibMarkdown/Text.cpp
index 54d78ffb69..b4088ebb60 100644
--- a/Userland/Libraries/LibMarkdown/Text.cpp
+++ b/Userland/Libraries/LibMarkdown/Text.cpp
@@ -223,6 +223,34 @@ RecursionDecision Text::MultiNode::walk(Visitor& visitor) const
return RecursionDecision::Continue;
}
+void Text::StrikeThroughNode::render_to_html(StringBuilder& builder) const
+{
+ builder.append("");
+ striked_text->render_to_html(builder);
+ builder.append("");
+}
+
+void Text::StrikeThroughNode::render_for_terminal(StringBuilder& builder) const
+{
+ builder.append("\e[9m");
+ striked_text->render_for_terminal(builder);
+ builder.append("\e[29m");
+}
+
+size_t Text::StrikeThroughNode::terminal_length() const
+{
+ return striked_text->terminal_length();
+}
+
+RecursionDecision Text::StrikeThroughNode::walk(Visitor& visitor) const
+{
+ RecursionDecision rd = visitor.visit(*this);
+ if (rd != RecursionDecision::Recurse)
+ return rd;
+
+ return striked_text->walk(visitor);
+}
+
size_t Text::terminal_length() const
{
return m_node->terminal_length();
@@ -330,7 +358,7 @@ Vector Text::tokenize(StringView str)
if (ch == '\\' && offset + 1 < str.length() && ispunct(str[offset + 1])) {
current_token.append(str[offset + 1]);
++offset;
- } else if (ch == '*' || ch == '_' || ch == '`') {
+ } else if (ch == '*' || ch == '_' || ch == '`' || ch == '~') {
flush_token();
char delim = ch;
@@ -388,6 +416,9 @@ NonnullOwnPtr Text::parse_sequence(Vector::ConstIterator
case '`':
node->children.append(parse_code(tokens));
break;
+ case '~':
+ node->children.append(parse_strike_through(tokens));
+ break;
}
} else if (*tokens == "[" || *tokens == " {
+ return token.is_run && token.run_char() == '~' && token.run_length() == opening.run_length();
+ };
+
+ bool is_all_whitespace = true;
+ auto striked_text = make();
+ for (auto iterator = tokens + 1; !iterator.is_end(); ++iterator) {
+ if (is_closing(*iterator)) {
+ tokens = iterator;
+
+ if (!is_all_whitespace) {
+ auto& first = dynamic_cast(striked_text->children.first());
+ auto& last = dynamic_cast(striked_text->children.last());
+ if (first.text.starts_with(" ") && last.text.ends_with(" ")) {
+ first.text = first.text.substring(1);
+ last.text = last.text.substring(0, last.text.length() - 1);
+ }
+ }
+
+ return make(move(striked_text));
+ }
+
+ is_all_whitespace = is_all_whitespace && iterator->data.is_whitespace();
+ striked_text->children.append(make((*iterator == "\n") ? " " : iterator->data, false));
+ }
+
+ return make(opening.data);
+}
+
}
diff --git a/Userland/Libraries/LibMarkdown/Text.h b/Userland/Libraries/LibMarkdown/Text.h
index ad76d5ecea..3fc6c48503 100644
--- a/Userland/Libraries/LibMarkdown/Text.h
+++ b/Userland/Libraries/LibMarkdown/Text.h
@@ -121,6 +121,21 @@ public:
virtual RecursionDecision walk(Visitor&) const override;
};
+ class StrikeThroughNode : public Node {
+ public:
+ NonnullOwnPtr striked_text;
+
+ StrikeThroughNode(NonnullOwnPtr striked_text)
+ : striked_text(move(striked_text))
+ {
+ }
+
+ virtual void render_to_html(StringBuilder& builder) const override;
+ virtual void render_for_terminal(StringBuilder& builder) const override;
+ virtual size_t terminal_length() const override;
+ virtual RecursionDecision walk(Visitor&) const override;
+ };
+
size_t terminal_length() const;
String render_to_html() const;
@@ -172,6 +187,7 @@ private:
static NonnullOwnPtr parse_emph(Vector::ConstIterator& tokens, bool in_link);
static NonnullOwnPtr parse_code(Vector::ConstIterator& tokens);
static NonnullOwnPtr parse_link(Vector::ConstIterator& tokens);
+ static NonnullOwnPtr parse_strike_through(Vector::ConstIterator& tokens);
OwnPtr m_node;
};
diff --git a/Userland/Libraries/LibMarkdown/Visitor.h b/Userland/Libraries/LibMarkdown/Visitor.h
index 7341b404f3..abbd6e9d3d 100644
--- a/Userland/Libraries/LibMarkdown/Visitor.h
+++ b/Userland/Libraries/LibMarkdown/Visitor.h
@@ -44,6 +44,7 @@ public:
virtual RecursionDecision visit(Text::EmphasisNode const&) { return RecursionDecision::Recurse; }
virtual RecursionDecision visit(Text::LinkNode const&) { return RecursionDecision::Recurse; }
virtual RecursionDecision visit(Text::MultiNode const&) { return RecursionDecision::Recurse; }
+ virtual RecursionDecision visit(Text::StrikeThroughNode const&) { return RecursionDecision::Recurse; }
virtual RecursionDecision visit(Text::TextNode const&) { return RecursionDecision::Recurse; }
virtual RecursionDecision visit(String const&) { return RecursionDecision::Recurse; }