Serenity Operating System
at master 167 lines 6.2 kB view raw
1/* 2 * Copyright (c) 2020-2022, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Noncopyable.h> 10#include <AK/WeakPtr.h> 11#include <LibGUI/TextDocument.h> 12#include <LibGfx/Palette.h> 13#include <LibSyntax/HighlighterClient.h> 14#include <LibSyntax/Language.h> 15 16namespace Syntax { 17 18struct TextStyle { 19 const Gfx::Color color; 20 bool const bold { false }; 21}; 22 23class Highlighter { 24 AK_MAKE_NONCOPYABLE(Highlighter); 25 AK_MAKE_NONMOVABLE(Highlighter); 26 27public: 28 virtual ~Highlighter() = default; 29 30 virtual Language language() const = 0; 31 virtual Optional<StringView> comment_prefix() const = 0; 32 virtual Optional<StringView> comment_suffix() const = 0; 33 virtual void rehighlight(Palette const&) = 0; 34 virtual void highlight_matching_token_pair(); 35 36 virtual bool is_identifier(u64) const { return false; }; 37 virtual bool is_navigatable(u64) const { return false; }; 38 39 void attach(HighlighterClient&); 40 void detach(); 41 void cursor_did_change(); 42 43 struct MatchingTokenPair { 44 u64 open; 45 u64 close; 46 }; 47 Vector<MatchingTokenPair> matching_token_pairs() const; 48 49 template<typename T> 50 bool fast_is() const = delete; 51 52 // FIXME: When other syntax highlighters start using a language server, we should add a common base class here. 53 virtual bool is_cpp_semantic_highlighter() const { return false; } 54 55protected: 56 Highlighter() = default; 57 58 // FIXME: This should be WeakPtr somehow 59 HighlighterClient* m_client { nullptr }; 60 61 virtual Vector<MatchingTokenPair> matching_token_pairs_impl() const = 0; 62 virtual bool token_types_equal(u64, u64) const = 0; 63 void register_nested_token_pairs(Vector<MatchingTokenPair>); 64 void clear_nested_token_pairs() { m_nested_token_pairs.clear(); } 65 size_t first_free_token_kind_serial_value() const { return m_nested_token_pairs.size(); } 66 67 struct BuddySpan { 68 int index { -1 }; 69 GUI::TextDocumentSpan span_backup; 70 }; 71 72 bool m_has_brace_buddies { false }; 73 BuddySpan m_brace_buddies[2]; 74 HashTable<MatchingTokenPair> m_nested_token_pairs; 75}; 76 77class ProxyHighlighterClient final : public Syntax::HighlighterClient { 78public: 79 ProxyHighlighterClient(Syntax::HighlighterClient& client, GUI::TextPosition start, u64 nested_kind_start_value, StringView source) 80 : m_document(client.get_document()) 81 , m_text(source) 82 , m_start(start) 83 , m_nested_kind_start_value(nested_kind_start_value) 84 { 85 } 86 87 Vector<GUI::TextDocumentSpan> corrected_spans() const 88 { 89 Vector<GUI::TextDocumentSpan> spans { m_spans }; 90 for (auto& entry : spans) { 91 entry.range.start() = { 92 entry.range.start().line() + m_start.line(), 93 entry.range.start().line() == 0 ? entry.range.start().column() + m_start.column() : entry.range.start().column(), 94 }; 95 entry.range.end() = { 96 entry.range.end().line() + m_start.line(), 97 entry.range.end().line() == 0 ? entry.range.end().column() + m_start.column() : entry.range.end().column(), 98 }; 99 if (entry.data != (u64)-1) 100 entry.data += m_nested_kind_start_value; 101 } 102 103 return spans; 104 } 105 106 Vector<GUI::TextDocumentFoldingRegion> corrected_folding_regions() const 107 { 108 Vector<GUI::TextDocumentFoldingRegion> folding_regions { m_folding_regions }; 109 for (auto& entry : folding_regions) { 110 entry.range.start() = { 111 entry.range.start().line() + m_start.line(), 112 entry.range.start().line() == 0 ? entry.range.start().column() + m_start.column() : entry.range.start().column(), 113 }; 114 entry.range.end() = { 115 entry.range.end().line() + m_start.line(), 116 entry.range.end().line() == 0 ? entry.range.end().column() + m_start.column() : entry.range.end().column(), 117 }; 118 } 119 120 return folding_regions; 121 } 122 123 Vector<Syntax::Highlighter::MatchingTokenPair> corrected_token_pairs(Vector<Syntax::Highlighter::MatchingTokenPair> pairs) const 124 { 125 for (auto& pair : pairs) { 126 pair.close += m_nested_kind_start_value; 127 pair.open += m_nested_kind_start_value; 128 } 129 return pairs; 130 } 131 132private: 133 virtual Vector<GUI::TextDocumentSpan>& spans() override { return m_spans; } 134 virtual Vector<GUI::TextDocumentSpan> const& spans() const override { return m_spans; } 135 virtual void set_span_at_index(size_t index, GUI::TextDocumentSpan span) override { m_spans.at(index) = move(span); } 136 137 virtual Vector<GUI::TextDocumentFoldingRegion>& folding_regions() override { return m_folding_regions; } 138 virtual Vector<GUI::TextDocumentFoldingRegion> const& folding_regions() const override { return m_folding_regions; } 139 140 virtual DeprecatedString highlighter_did_request_text() const override { return m_text; } 141 virtual void highlighter_did_request_update() override { } 142 virtual GUI::TextDocument& highlighter_did_request_document() override { return m_document; } 143 virtual GUI::TextPosition highlighter_did_request_cursor() const override { return {}; } 144 virtual void highlighter_did_set_spans(Vector<GUI::TextDocumentSpan> spans) override { m_spans = move(spans); } 145 virtual void highlighter_did_set_folding_regions(Vector<GUI::TextDocumentFoldingRegion> folding_regions) override { m_folding_regions = folding_regions; } 146 147 Vector<GUI::TextDocumentSpan> m_spans; 148 Vector<GUI::TextDocumentFoldingRegion> m_folding_regions; 149 GUI::TextDocument& m_document; 150 StringView m_text; 151 GUI::TextPosition m_start; 152 u64 m_nested_kind_start_value { 0 }; 153}; 154 155} 156 157template<> 158struct AK::Traits<Syntax::Highlighter::MatchingTokenPair> : public AK::GenericTraits<Syntax::Highlighter::MatchingTokenPair> { 159 static unsigned hash(Syntax::Highlighter::MatchingTokenPair const& pair) 160 { 161 return pair_int_hash(u64_hash(pair.open), u64_hash(pair.close)); 162 } 163 static bool equals(Syntax::Highlighter::MatchingTokenPair const& a, Syntax::Highlighter::MatchingTokenPair const& b) 164 { 165 return a.open == b.open && a.close == b.close; 166 } 167};