Text.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. * Copyright (c) 2021, Peter Elliott <pelliott@serenityos.org>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #pragma once
  9. #include <AK/DeprecatedString.h>
  10. #include <AK/Noncopyable.h>
  11. #include <AK/OwnPtr.h>
  12. #include <AK/RecursionDecision.h>
  13. #include <AK/Vector.h>
  14. #include <LibMarkdown/Forward.h>
  15. namespace Markdown {
  16. class Text final {
  17. public:
  18. class Node {
  19. public:
  20. virtual void render_to_html(StringBuilder& builder) const = 0;
  21. virtual void render_for_terminal(StringBuilder& builder) const = 0;
  22. virtual size_t terminal_length() const = 0;
  23. virtual RecursionDecision walk(Visitor&) const = 0;
  24. virtual ~Node() = default;
  25. };
  26. class EmphasisNode : public Node {
  27. public:
  28. bool strong;
  29. NonnullOwnPtr<Node> child;
  30. EmphasisNode(bool strong, NonnullOwnPtr<Node> child)
  31. : strong(strong)
  32. , child(move(child))
  33. {
  34. }
  35. virtual void render_to_html(StringBuilder& builder) const override;
  36. virtual void render_for_terminal(StringBuilder& builder) const override;
  37. virtual size_t terminal_length() const override;
  38. virtual RecursionDecision walk(Visitor&) const override;
  39. };
  40. class CodeNode : public Node {
  41. public:
  42. NonnullOwnPtr<Node> code;
  43. CodeNode(NonnullOwnPtr<Node> code)
  44. : code(move(code))
  45. {
  46. }
  47. virtual void render_to_html(StringBuilder& builder) const override;
  48. virtual void render_for_terminal(StringBuilder& builder) const override;
  49. virtual size_t terminal_length() const override;
  50. virtual RecursionDecision walk(Visitor&) const override;
  51. };
  52. class BreakNode : public Node {
  53. public:
  54. virtual void render_to_html(StringBuilder& builder) const override;
  55. virtual void render_for_terminal(StringBuilder& builder) const override;
  56. virtual size_t terminal_length() const override;
  57. virtual RecursionDecision walk(Visitor&) const override;
  58. };
  59. class TextNode : public Node {
  60. public:
  61. DeprecatedString text;
  62. bool collapsible;
  63. TextNode(StringView text)
  64. : text(text)
  65. , collapsible(true)
  66. {
  67. }
  68. TextNode(StringView text, bool collapsible)
  69. : text(text)
  70. , collapsible(collapsible)
  71. {
  72. }
  73. virtual void render_to_html(StringBuilder& builder) const override;
  74. virtual void render_for_terminal(StringBuilder& builder) const override;
  75. virtual size_t terminal_length() const override;
  76. virtual RecursionDecision walk(Visitor&) const override;
  77. };
  78. class LinkNode : public Node {
  79. public:
  80. bool is_image;
  81. NonnullOwnPtr<Node> text;
  82. DeprecatedString href;
  83. Optional<int> image_width;
  84. Optional<int> image_height;
  85. LinkNode(bool is_image, NonnullOwnPtr<Node> text, DeprecatedString href, Optional<int> image_width, Optional<int> image_height)
  86. : is_image(is_image)
  87. , text(move(text))
  88. , href(move(href))
  89. , image_width(image_width)
  90. , image_height(image_height)
  91. {
  92. }
  93. bool has_image_dimensions() const
  94. {
  95. return image_width.has_value() || image_height.has_value();
  96. }
  97. virtual void render_to_html(StringBuilder& builder) const override;
  98. virtual void render_for_terminal(StringBuilder& builder) const override;
  99. virtual size_t terminal_length() const override;
  100. virtual RecursionDecision walk(Visitor&) const override;
  101. };
  102. class MultiNode : public Node {
  103. public:
  104. Vector<NonnullOwnPtr<Node>> children;
  105. virtual void render_to_html(StringBuilder& builder) const override;
  106. virtual void render_for_terminal(StringBuilder& builder) const override;
  107. virtual size_t terminal_length() const override;
  108. virtual RecursionDecision walk(Visitor&) const override;
  109. };
  110. class StrikeThroughNode : public Node {
  111. public:
  112. NonnullOwnPtr<Node> striked_text;
  113. StrikeThroughNode(NonnullOwnPtr<Node> striked_text)
  114. : striked_text(move(striked_text))
  115. {
  116. }
  117. virtual void render_to_html(StringBuilder& builder) const override;
  118. virtual void render_for_terminal(StringBuilder& builder) const override;
  119. virtual size_t terminal_length() const override;
  120. virtual RecursionDecision walk(Visitor&) const override;
  121. };
  122. size_t terminal_length() const;
  123. DeprecatedString render_to_html() const;
  124. DeprecatedString render_for_terminal() const;
  125. RecursionDecision walk(Visitor&) const;
  126. static Text parse(StringView);
  127. private:
  128. struct Token {
  129. DeprecatedString data;
  130. // Flanking basically means that a delimiter run has a non-whitespace,
  131. // non-punctuation character on the corresponding side. For a more exact
  132. // definition, see the CommonMark spec.
  133. bool left_flanking;
  134. bool right_flanking;
  135. bool punct_before;
  136. bool punct_after;
  137. // is_run indicates that this token is a 'delimiter run'. A delimiter
  138. // run occurs when several of the same syntactical character ('`', '_',
  139. // or '*') occur in a row.
  140. bool is_run;
  141. char run_char() const
  142. {
  143. VERIFY(is_run);
  144. return data[0];
  145. }
  146. char run_length() const
  147. {
  148. VERIFY(is_run);
  149. return data.length();
  150. }
  151. bool is_space() const
  152. {
  153. return data[0] == ' ';
  154. }
  155. bool operator==(StringView str) const { return str == data; }
  156. };
  157. static Vector<Token> tokenize(StringView);
  158. static bool can_open(Token const& opening);
  159. static bool can_close_for(Token const& opening, Token const& closing);
  160. static NonnullOwnPtr<MultiNode> parse_sequence(Vector<Token>::ConstIterator& tokens, bool in_link);
  161. static NonnullOwnPtr<Node> parse_break(Vector<Token>::ConstIterator& tokens);
  162. static NonnullOwnPtr<Node> parse_newline(Vector<Token>::ConstIterator& tokens);
  163. static NonnullOwnPtr<Node> parse_emph(Vector<Token>::ConstIterator& tokens, bool in_link);
  164. static NonnullOwnPtr<Node> parse_code(Vector<Token>::ConstIterator& tokens);
  165. static NonnullOwnPtr<Node> parse_link(Vector<Token>::ConstIterator& tokens);
  166. static NonnullOwnPtr<Node> parse_strike_through(Vector<Token>::ConstIterator& tokens);
  167. OwnPtr<Node> m_node;
  168. };
  169. }