SourceHighlighter.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
  3. * Copyright (c) 2024, Sam Atkins <sam@ladybird.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/String.h>
  9. #include <AK/StringView.h>
  10. #include <LibSyntax/Document.h>
  11. #include <LibSyntax/HighlighterClient.h>
  12. #include <LibSyntax/Language.h>
  13. namespace WebView {
  14. enum class HighlightOutputMode {
  15. FullDocument, // Include HTML header, title, style sheet, etc
  16. SourceOnly, // Just the highlighted source
  17. };
  18. class SourceDocument final : public Syntax::Document {
  19. public:
  20. static NonnullRefPtr<SourceDocument> create(StringView source)
  21. {
  22. return adopt_ref(*new (nothrow) SourceDocument(source));
  23. }
  24. virtual ~SourceDocument() = default;
  25. StringView text() const { return m_source; }
  26. size_t line_count() const { return m_lines.size(); }
  27. // ^ Syntax::Document
  28. virtual Syntax::TextDocumentLine const& line(size_t line_index) const override;
  29. virtual Syntax::TextDocumentLine& line(size_t line_index) override;
  30. private:
  31. SourceDocument(StringView source);
  32. // ^ Syntax::Document
  33. virtual void update_views(Badge<Syntax::TextDocumentLine>) override { }
  34. StringView m_source;
  35. Vector<Syntax::TextDocumentLine> m_lines;
  36. };
  37. class SourceHighlighterClient final : public Syntax::HighlighterClient {
  38. public:
  39. SourceHighlighterClient(StringView source, Syntax::Language);
  40. virtual ~SourceHighlighterClient() = default;
  41. String to_html_string(String const&, HighlightOutputMode) const;
  42. private:
  43. // ^ Syntax::HighlighterClient
  44. virtual Vector<Syntax::TextDocumentSpan> const& spans() const override;
  45. virtual void set_span_at_index(size_t index, Syntax::TextDocumentSpan span) override;
  46. virtual Vector<Syntax::TextDocumentFoldingRegion>& folding_regions() override;
  47. virtual Vector<Syntax::TextDocumentFoldingRegion> const& folding_regions() const override;
  48. virtual ByteString highlighter_did_request_text() const override;
  49. virtual void highlighter_did_request_update() override;
  50. virtual Syntax::Document& highlighter_did_request_document() override;
  51. virtual Syntax::TextPosition highlighter_did_request_cursor() const override;
  52. virtual void highlighter_did_set_spans(Vector<Syntax::TextDocumentSpan>) override;
  53. virtual void highlighter_did_set_folding_regions(Vector<Syntax::TextDocumentFoldingRegion>) override;
  54. StringView class_for_token(u64 token_type) const;
  55. SourceDocument& document() const { return *m_document; }
  56. NonnullRefPtr<SourceDocument> m_document;
  57. OwnPtr<Syntax::Highlighter> m_highlighter;
  58. };
  59. String highlight_source(String const&, StringView, Syntax::Language, HighlightOutputMode);
  60. constexpr inline StringView HTML_HIGHLIGHTER_STYLE = R"~~~(
  61. @media (prefers-color-scheme: dark) {
  62. /* FIXME: We should be able to remove the HTML style when "color-scheme" is supported */
  63. html {
  64. background-color: rgb(30, 30, 30);
  65. color: white;
  66. counter-reset: line;
  67. }
  68. :root {
  69. --comment-color: lightgreen;
  70. --keyword-color: orangered;
  71. --name-color: orange;
  72. --value-color: deepskyblue;
  73. --internal-color: darkgrey;
  74. --string-color: goldenrod;
  75. --error-color: red;
  76. --line-number-color: darkgrey;
  77. }
  78. }
  79. @media (prefers-color-scheme: light) {
  80. :root {
  81. --comment-color: green;
  82. --keyword-color: red;
  83. --name-color: darkorange;
  84. --value-color: blue;
  85. --internal-color: dimgrey;
  86. --string-color: darkgoldenrod;
  87. --error-color: darkred;
  88. --line-number-color: dimgrey;
  89. }
  90. }
  91. .html {
  92. font-size: 10pt;
  93. font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  94. }
  95. .line {
  96. counter-increment: line;
  97. white-space: pre;
  98. }
  99. .line::before {
  100. content: counter(line) " ";
  101. display: inline-block;
  102. width: 2.5em;
  103. padding-right: 0.5em;
  104. text-align: right;
  105. color: var(--line-number-color);
  106. }
  107. .tag {
  108. font-weight: 600;
  109. color: var(--keyword-color);
  110. }
  111. .comment {
  112. color: var(--comment-color);
  113. }
  114. .attribute-name {
  115. color: var(--name-color);
  116. }
  117. .attribute-value {
  118. color: var(--value-color);
  119. }
  120. .internal {
  121. color: var(--internal-color);
  122. }
  123. .invalid {
  124. color: var(--error-color);
  125. text-decoration: currentColor wavy underline;
  126. }
  127. .at-keyword, .function, .keyword, .control-keyword, .url {
  128. color: var(--keyword-color);
  129. }
  130. .number, .hash {
  131. color: var(--value-color);
  132. }
  133. .string {
  134. color: var(--string-color);
  135. }
  136. )~~~"sv;
  137. }