SourceHighlighter.h 4.9 KB

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