2020-01-18 09:38:21 +01:00
|
|
|
/*
|
2020-01-24 16:45:29 +03:00
|
|
|
* Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
|
2021-09-06 19:11:46 -06:00
|
|
|
* Copyright (c) 2021, Peter Elliott <pelliott@serenityos.org>
|
2022-03-04 13:21:26 -07:00
|
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
2020-01-18 09:38:21 +01:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
|
2019-09-21 00:46:18 +03:00
|
|
|
#pragma once
|
|
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
#include <AK/ByteString.h>
|
2020-05-18 16:58:00 -04:00
|
|
|
#include <AK/Noncopyable.h>
|
2021-09-06 19:11:46 -06:00
|
|
|
#include <AK/OwnPtr.h>
|
2021-09-10 21:36:29 +02:00
|
|
|
#include <AK/RecursionDecision.h>
|
2023-03-06 17:39:59 +01:00
|
|
|
#include <AK/Vector.h>
|
2021-09-10 21:36:29 +02:00
|
|
|
#include <LibMarkdown/Forward.h>
|
2019-09-21 00:46:18 +03:00
|
|
|
|
2020-04-28 21:04:25 +02:00
|
|
|
namespace Markdown {
|
|
|
|
|
|
|
|
|
|
class Text final {
|
2019-09-21 00:46:18 +03:00
|
|
|
public:
|
2021-09-06 19:11:46 -06:00
|
|
|
class Node {
|
|
|
|
|
public:
|
|
|
|
|
virtual void render_to_html(StringBuilder& builder) const = 0;
|
|
|
|
|
virtual void render_for_terminal(StringBuilder& builder) const = 0;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const = 0;
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual size_t terminal_length() const = 0;
|
2021-09-10 21:36:29 +02:00
|
|
|
virtual RecursionDecision walk(Visitor&) const = 0;
|
2021-09-06 19:11:46 -06:00
|
|
|
|
2022-03-04 13:21:26 -07:00
|
|
|
virtual ~Node() = default;
|
2021-09-06 19:11:46 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual size_t terminal_length() const override;
|
2021-09-10 21:36:29 +02:00
|
|
|
virtual RecursionDecision walk(Visitor&) const override;
|
2019-09-21 00:46:18 +03:00
|
|
|
};
|
|
|
|
|
|
2021-09-06 19:11:46 -06:00
|
|
|
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;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual size_t terminal_length() const override;
|
2021-09-10 21:36:29 +02:00
|
|
|
virtual RecursionDecision walk(Visitor&) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
};
|
|
|
|
|
|
2021-09-10 00:45:45 -06:00
|
|
|
class BreakNode : public Node {
|
|
|
|
|
public:
|
|
|
|
|
virtual void render_to_html(StringBuilder& builder) const override;
|
|
|
|
|
virtual void render_for_terminal(StringBuilder& builder) const override;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const override;
|
2021-09-10 00:45:45 -06:00
|
|
|
virtual size_t terminal_length() const override;
|
2021-09-10 21:36:29 +02:00
|
|
|
virtual RecursionDecision walk(Visitor&) const override;
|
2021-09-10 00:45:45 -06:00
|
|
|
};
|
|
|
|
|
|
2021-09-06 19:11:46 -06:00
|
|
|
class TextNode : public Node {
|
|
|
|
|
public:
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString text;
|
2021-09-10 00:50:42 -06:00
|
|
|
bool collapsible;
|
2021-09-06 19:11:46 -06:00
|
|
|
|
2021-11-11 00:55:02 +01:00
|
|
|
TextNode(StringView text)
|
2021-09-06 19:11:46 -06:00
|
|
|
: text(text)
|
2021-09-10 00:50:42 -06:00
|
|
|
, collapsible(true)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-11 00:55:02 +01:00
|
|
|
TextNode(StringView text, bool collapsible)
|
2021-09-10 00:50:42 -06:00
|
|
|
: text(text)
|
|
|
|
|
, collapsible(collapsible)
|
2021-09-06 19:11:46 -06:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void render_to_html(StringBuilder& builder) const override;
|
|
|
|
|
virtual void render_for_terminal(StringBuilder& builder) const override;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual size_t terminal_length() const override;
|
2021-09-10 21:36:29 +02:00
|
|
|
virtual RecursionDecision walk(Visitor&) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class LinkNode : public Node {
|
|
|
|
|
public:
|
|
|
|
|
bool is_image;
|
|
|
|
|
NonnullOwnPtr<Node> text;
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString href;
|
2022-08-03 00:11:58 +01:00
|
|
|
Optional<int> image_width;
|
|
|
|
|
Optional<int> image_height;
|
2021-09-06 19:11:46 -06:00
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
LinkNode(bool is_image, NonnullOwnPtr<Node> text, ByteString href, Optional<int> image_width, Optional<int> image_height)
|
2021-09-06 19:11:46 -06:00
|
|
|
: is_image(is_image)
|
|
|
|
|
, text(move(text))
|
|
|
|
|
, href(move(href))
|
2022-08-03 00:11:58 +01:00
|
|
|
, image_width(image_width)
|
|
|
|
|
, image_height(image_height)
|
2021-09-06 19:11:46 -06:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-03 00:11:58 +01:00
|
|
|
bool has_image_dimensions() const
|
|
|
|
|
{
|
|
|
|
|
return image_width.has_value() || image_height.has_value();
|
|
|
|
|
}
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual void render_to_html(StringBuilder& builder) const override;
|
|
|
|
|
virtual void render_for_terminal(StringBuilder& builder) const override;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual size_t terminal_length() const override;
|
2021-09-10 21:36:29 +02:00
|
|
|
virtual RecursionDecision walk(Visitor&) const override;
|
2019-09-21 00:46:18 +03:00
|
|
|
};
|
|
|
|
|
|
2021-09-06 19:11:46 -06:00
|
|
|
class MultiNode : public Node {
|
|
|
|
|
public:
|
2023-03-06 17:16:25 +01:00
|
|
|
Vector<NonnullOwnPtr<Node>> children;
|
2020-09-20 16:43:19 +04:30
|
|
|
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual void render_to_html(StringBuilder& builder) const override;
|
|
|
|
|
virtual void render_for_terminal(StringBuilder& builder) const override;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
virtual size_t terminal_length() const override;
|
2021-09-10 21:36:29 +02:00
|
|
|
virtual RecursionDecision walk(Visitor&) const override;
|
2021-09-06 19:11:46 -06:00
|
|
|
};
|
2020-05-18 16:58:00 -04:00
|
|
|
|
2022-04-26 21:34:29 -07:00
|
|
|
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;
|
2023-07-20 14:43:39 +03:00
|
|
|
virtual void render_for_raw_print(StringBuilder& builder) const override;
|
2022-04-26 21:34:29 -07:00
|
|
|
virtual size_t terminal_length() const override;
|
|
|
|
|
virtual RecursionDecision walk(Visitor&) const override;
|
|
|
|
|
};
|
|
|
|
|
|
2021-09-06 19:11:46 -06:00
|
|
|
size_t terminal_length() const;
|
2019-09-21 00:46:18 +03:00
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString render_to_html() const;
|
|
|
|
|
ByteString render_for_terminal() const;
|
|
|
|
|
ByteString render_for_raw_print() const;
|
2021-09-10 21:36:29 +02:00
|
|
|
RecursionDecision walk(Visitor&) const;
|
2019-09-21 00:46:18 +03:00
|
|
|
|
2021-11-11 00:55:02 +01:00
|
|
|
static Text parse(StringView);
|
2019-09-21 00:46:18 +03:00
|
|
|
|
|
|
|
|
private:
|
2021-09-06 19:11:46 -06:00
|
|
|
struct Token {
|
2023-12-16 17:49:34 +03:30
|
|
|
ByteString data;
|
2021-09-06 19:11:46 -06:00
|
|
|
// Flanking basically means that a delimiter run has a non-whitespace,
|
2021-09-30 20:03:41 -04:00
|
|
|
// non-punctuation character on the corresponding side. For a more exact
|
2021-09-06 19:11:46 -06:00
|
|
|
// definition, see the CommonMark spec.
|
|
|
|
|
bool left_flanking;
|
|
|
|
|
bool right_flanking;
|
2021-09-09 23:22:07 -06:00
|
|
|
bool punct_before;
|
|
|
|
|
bool punct_after;
|
2021-09-06 19:11:46 -06:00
|
|
|
// is_run indicates that this token is a 'delimiter run'. A delimiter
|
2022-01-07 05:04:05 -07:00
|
|
|
// run occurs when several of the same syntactical character ('`', '_',
|
2021-09-06 19:11:46 -06:00
|
|
|
// 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();
|
|
|
|
|
}
|
2021-09-10 00:45:45 -06:00
|
|
|
bool is_space() const
|
|
|
|
|
{
|
|
|
|
|
return data[0] == ' ';
|
|
|
|
|
}
|
2021-11-11 00:55:02 +01:00
|
|
|
bool operator==(StringView str) const { return str == data; }
|
2021-09-06 19:11:46 -06:00
|
|
|
};
|
|
|
|
|
|
2021-11-11 00:55:02 +01:00
|
|
|
static Vector<Token> tokenize(StringView);
|
2021-09-06 19:11:46 -06:00
|
|
|
|
|
|
|
|
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);
|
2021-09-10 00:45:45 -06:00
|
|
|
static NonnullOwnPtr<Node> parse_break(Vector<Token>::ConstIterator& tokens);
|
|
|
|
|
static NonnullOwnPtr<Node> parse_newline(Vector<Token>::ConstIterator& tokens);
|
2021-09-06 19:11:46 -06:00
|
|
|
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);
|
2022-04-26 21:34:29 -07:00
|
|
|
static NonnullOwnPtr<Node> parse_strike_through(Vector<Token>::ConstIterator& tokens);
|
2020-05-18 16:58:00 -04:00
|
|
|
|
2021-09-06 19:11:46 -06:00
|
|
|
OwnPtr<Node> m_node;
|
2019-09-21 00:46:18 +03:00
|
|
|
};
|
2020-04-28 21:04:25 +02:00
|
|
|
|
|
|
|
|
}
|