mirror of
https://github.com/RGBCube/serenity
synced 2025-05-18 13:35:06 +00:00

Using ~~text~~ syntax will strike out the text between the two tildes. Only missing portion is the terminal rendering of strike through text. The ansi escape codes for strike through text are \e[9m and \e[29m but it appears the terminal does not support these. Please correct me if I am wrong. I tested that the render_to_terminal function was being called by giving it bold ANSI escape codes, and that did work so the function is being called correctly.
195 lines
6.1 KiB
C++
195 lines
6.1 KiB
C++
/*
|
|
* Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
|
|
* Copyright (c) 2021, Peter Elliott <pelliott@serenityos.org>
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Noncopyable.h>
|
|
#include <AK/NonnullOwnPtrVector.h>
|
|
#include <AK/OwnPtr.h>
|
|
#include <AK/RecursionDecision.h>
|
|
#include <AK/String.h>
|
|
#include <LibMarkdown/Forward.h>
|
|
|
|
namespace Markdown {
|
|
|
|
class Text final {
|
|
public:
|
|
class Node {
|
|
public:
|
|
virtual void render_to_html(StringBuilder& builder) const = 0;
|
|
virtual void render_for_terminal(StringBuilder& builder) const = 0;
|
|
virtual size_t terminal_length() const = 0;
|
|
virtual RecursionDecision walk(Visitor&) const = 0;
|
|
|
|
virtual ~Node() = default;
|
|
};
|
|
|
|
class EmphasisNode : public Node {
|
|
public:
|
|
bool strong;
|
|
NonnullOwnPtr<Node> child;
|
|
|
|
EmphasisNode(bool strong, NonnullOwnPtr<Node> child)
|
|
: strong(strong)
|
|
, child(move(child))
|
|
{
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
class CodeNode : public Node {
|
|
public:
|
|
NonnullOwnPtr<Node> code;
|
|
|
|
CodeNode(NonnullOwnPtr<Node> code)
|
|
: code(move(code))
|
|
{
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
class BreakNode : public Node {
|
|
public:
|
|
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;
|
|
};
|
|
|
|
class TextNode : public Node {
|
|
public:
|
|
String text;
|
|
bool collapsible;
|
|
|
|
TextNode(StringView text)
|
|
: text(text)
|
|
, collapsible(true)
|
|
{
|
|
}
|
|
|
|
TextNode(StringView text, bool collapsible)
|
|
: text(text)
|
|
, collapsible(collapsible)
|
|
{
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
class LinkNode : public Node {
|
|
public:
|
|
bool is_image;
|
|
NonnullOwnPtr<Node> text;
|
|
String href;
|
|
|
|
LinkNode(bool is_image, NonnullOwnPtr<Node> text, String href)
|
|
: is_image(is_image)
|
|
, text(move(text))
|
|
, href(move(href))
|
|
{
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
class MultiNode : public Node {
|
|
public:
|
|
NonnullOwnPtrVector<Node> children;
|
|
|
|
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;
|
|
};
|
|
|
|
class StrikeThroughNode : public Node {
|
|
public:
|
|
NonnullOwnPtr<Node> striked_text;
|
|
|
|
StrikeThroughNode(NonnullOwnPtr<Node> 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;
|
|
String render_for_terminal() const;
|
|
RecursionDecision walk(Visitor&) const;
|
|
|
|
static Text parse(StringView);
|
|
|
|
private:
|
|
struct Token {
|
|
String data;
|
|
// Flanking basically means that a delimiter run has a non-whitespace,
|
|
// non-punctuation character on the corresponding side. For a more exact
|
|
// definition, see the CommonMark spec.
|
|
bool left_flanking;
|
|
bool right_flanking;
|
|
bool punct_before;
|
|
bool punct_after;
|
|
// is_run indicates that this token is a 'delimiter run'. A delimiter
|
|
// run occurs when several of the same syntactical character ('`', '_',
|
|
// or '*') occur in a row.
|
|
bool is_run;
|
|
|
|
char run_char() const
|
|
{
|
|
VERIFY(is_run);
|
|
return data[0];
|
|
}
|
|
char run_length() const
|
|
{
|
|
VERIFY(is_run);
|
|
return data.length();
|
|
}
|
|
bool is_space() const
|
|
{
|
|
return data[0] == ' ';
|
|
}
|
|
bool operator==(StringView str) const { return str == data; }
|
|
};
|
|
|
|
static Vector<Token> tokenize(StringView);
|
|
|
|
static bool can_open(Token const& opening);
|
|
static bool can_close_for(Token const& opening, Token const& closing);
|
|
|
|
static NonnullOwnPtr<MultiNode> parse_sequence(Vector<Token>::ConstIterator& tokens, bool in_link);
|
|
static NonnullOwnPtr<Node> parse_break(Vector<Token>::ConstIterator& tokens);
|
|
static NonnullOwnPtr<Node> parse_newline(Vector<Token>::ConstIterator& tokens);
|
|
static NonnullOwnPtr<Node> parse_emph(Vector<Token>::ConstIterator& tokens, bool in_link);
|
|
static NonnullOwnPtr<Node> parse_code(Vector<Token>::ConstIterator& tokens);
|
|
static NonnullOwnPtr<Node> parse_link(Vector<Token>::ConstIterator& tokens);
|
|
static NonnullOwnPtr<Node> parse_strike_through(Vector<Token>::ConstIterator& tokens);
|
|
|
|
OwnPtr<Node> m_node;
|
|
};
|
|
|
|
}
|