Text.h 4.9 KB

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