123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- /*
- * 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/ByteString.h>
- #include <AK/Noncopyable.h>
- #include <AK/OwnPtr.h>
- #include <AK/RecursionDecision.h>
- #include <AK/Vector.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 void render_for_raw_print(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 void render_for_raw_print(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 void render_for_raw_print(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 void render_for_raw_print(StringBuilder& builder) const override;
- virtual size_t terminal_length() const override;
- virtual RecursionDecision walk(Visitor&) const override;
- };
- class TextNode : public Node {
- public:
- ByteString 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 void render_for_raw_print(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;
- ByteString href;
- Optional<int> image_width;
- Optional<int> image_height;
- LinkNode(bool is_image, NonnullOwnPtr<Node> text, ByteString href, Optional<int> image_width, Optional<int> image_height)
- : is_image(is_image)
- , text(move(text))
- , href(move(href))
- , image_width(image_width)
- , image_height(image_height)
- {
- }
- bool has_image_dimensions() const
- {
- return image_width.has_value() || image_height.has_value();
- }
- virtual void render_to_html(StringBuilder& builder) const override;
- virtual void render_for_terminal(StringBuilder& builder) const override;
- virtual void render_for_raw_print(StringBuilder& builder) const override;
- virtual size_t terminal_length() const override;
- virtual RecursionDecision walk(Visitor&) const override;
- };
- class MultiNode : public Node {
- public:
- Vector<NonnullOwnPtr<Node>> children;
- virtual void render_to_html(StringBuilder& builder) const override;
- virtual void render_for_terminal(StringBuilder& builder) const override;
- virtual void render_for_raw_print(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 void render_for_raw_print(StringBuilder& builder) const override;
- virtual size_t terminal_length() const override;
- virtual RecursionDecision walk(Visitor&) const override;
- };
- size_t terminal_length() const;
- ByteString render_to_html() const;
- ByteString render_for_terminal() const;
- ByteString render_for_raw_print() const;
- RecursionDecision walk(Visitor&) const;
- static Text parse(StringView);
- private:
- struct Token {
- ByteString 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;
- };
- }
|