| 
									
										
										
										
											2020-03-14 00:07:44 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2022-01-17 19:35:06 -08:00
										 |  |  |  * Copyright (c) 2020-2022, the SerenityOS developers. | 
					
						
							| 
									
										
										
										
											2020-03-14 00:07:44 +02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-03-14 00:07:44 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AK/Noncopyable.h>
 | 
					
						
							|  |  |  | #include <AK/WeakPtr.h>
 | 
					
						
							|  |  |  | #include <LibGUI/TextDocument.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 01:05:06 +02:00
										 |  |  | #include <LibGfx/Palette.h>
 | 
					
						
							| 
									
										
										
										
											2021-02-07 16:56:02 +01:00
										 |  |  | #include <LibSyntax/HighlighterClient.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  | namespace Syntax { | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  | enum class Language { | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:02 +02:00
										 |  |  |     Cpp, | 
					
						
							| 
									
										
										
										
											2021-10-21 21:29:10 +01:00
										 |  |  |     CSS, | 
					
						
							| 
									
										
										
										
											2022-01-17 19:35:06 -08:00
										 |  |  |     GitCommit, | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  |     GML, | 
					
						
							| 
									
										
										
										
											2021-05-20 23:15:33 +04:30
										 |  |  |     HTML, | 
					
						
							|  |  |  |     INI, | 
					
						
							|  |  |  |     JavaScript, | 
					
						
							|  |  |  |     PlainText, | 
					
						
							| 
									
										
										
										
											2021-05-08 18:30:18 -07:00
										 |  |  |     SQL, | 
					
						
							| 
									
										
										
										
											2021-05-20 23:15:33 +04:30
										 |  |  |     Shell, | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:02 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct TextStyle { | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  |     const Gfx::Color color; | 
					
						
							| 
									
										
										
										
											2020-12-28 15:51:43 +01:00
										 |  |  |     const bool bold { false }; | 
					
						
							| 
									
										
										
										
											2020-03-12 16:36:25 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  | class Highlighter { | 
					
						
							|  |  |  |     AK_MAKE_NONCOPYABLE(Highlighter); | 
					
						
							|  |  |  |     AK_MAKE_NONMOVABLE(Highlighter); | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  |     virtual ~Highlighter(); | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  |     virtual Language language() const = 0; | 
					
						
							| 
									
										
										
										
											2022-02-22 15:00:56 -05:00
										 |  |  |     StringView language_string(Language) const; | 
					
						
							| 
									
										
										
										
											2021-02-11 23:52:39 +01:00
										 |  |  |     virtual void rehighlight(const Palette&) = 0; | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:02 +02:00
										 |  |  |     virtual void highlight_matching_token_pair(); | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 12:03:09 +04:30
										 |  |  |     virtual bool is_identifier(u64) const { return false; }; | 
					
						
							|  |  |  |     virtual bool is_navigatable(u64) const { return false; }; | 
					
						
							| 
									
										
										
										
											2020-03-12 17:23:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-07 16:56:02 +01:00
										 |  |  |     void attach(HighlighterClient&); | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  |     void detach(); | 
					
						
							|  |  |  |     void cursor_did_change(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 12:03:09 +04:30
										 |  |  |     struct MatchingTokenPair { | 
					
						
							|  |  |  |         u64 open; | 
					
						
							|  |  |  |         u64 close; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     Vector<MatchingTokenPair> matching_token_pairs() const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-06 23:02:34 +02:00
										 |  |  |     template<typename T> | 
					
						
							|  |  |  |     bool fast_is() const = delete; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // FIXME: When other syntax highlighters start using a language server, we should add a common base class here.
 | 
					
						
							|  |  |  |     virtual bool is_cpp_semantic_highlighter() const { return false; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | protected: | 
					
						
							| 
									
										
										
										
											2021-02-07 15:15:10 +01:00
										 |  |  |     Highlighter() { } | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-07 16:56:02 +01:00
										 |  |  |     // FIXME: This should be WeakPtr somehow
 | 
					
						
							|  |  |  |     HighlighterClient* m_client { nullptr }; | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-07 12:03:09 +04:30
										 |  |  |     virtual Vector<MatchingTokenPair> matching_token_pairs_impl() const = 0; | 
					
						
							|  |  |  |     virtual bool token_types_equal(u64, u64) const = 0; | 
					
						
							|  |  |  |     void register_nested_token_pairs(Vector<MatchingTokenPair>); | 
					
						
							|  |  |  |     void clear_nested_token_pairs() { m_nested_token_pairs.clear(); } | 
					
						
							|  |  |  |     size_t first_free_token_kind_serial_value() const { return m_nested_token_pairs.size(); } | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  |     struct BuddySpan { | 
					
						
							|  |  |  |         int index { -1 }; | 
					
						
							|  |  |  |         GUI::TextDocumentSpan span_backup; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool m_has_brace_buddies { false }; | 
					
						
							|  |  |  |     BuddySpan m_brace_buddies[2]; | 
					
						
							| 
									
										
										
										
											2021-06-07 12:03:09 +04:30
										 |  |  |     HashTable<MatchingTokenPair> m_nested_token_pairs; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ProxyHighlighterClient final : public Syntax::HighlighterClient { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     ProxyHighlighterClient(Syntax::HighlighterClient& client, GUI::TextPosition start, u64 nested_kind_start_value, StringView source) | 
					
						
							|  |  |  |         : m_document(client.get_document()) | 
					
						
							|  |  |  |         , m_text(source) | 
					
						
							|  |  |  |         , m_start(start) | 
					
						
							|  |  |  |         , m_nested_kind_start_value(nested_kind_start_value) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector<GUI::TextDocumentSpan> corrected_spans() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Vector<GUI::TextDocumentSpan> spans { m_spans }; | 
					
						
							|  |  |  |         for (auto& entry : spans) { | 
					
						
							|  |  |  |             entry.range.start() = { | 
					
						
							|  |  |  |                 entry.range.start().line() + m_start.line(), | 
					
						
							|  |  |  |                 entry.range.start().line() == 0 ? entry.range.start().column() + m_start.column() : entry.range.start().column(), | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             entry.range.end() = { | 
					
						
							|  |  |  |                 entry.range.end().line() + m_start.line(), | 
					
						
							|  |  |  |                 entry.range.end().line() == 0 ? entry.range.end().column() + m_start.column() : entry.range.end().column(), | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             if (entry.data != (u64)-1) | 
					
						
							|  |  |  |                 entry.data += m_nested_kind_start_value; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return spans; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector<Syntax::Highlighter::MatchingTokenPair> corrected_token_pairs(Vector<Syntax::Highlighter::MatchingTokenPair> pairs) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (auto& pair : pairs) { | 
					
						
							|  |  |  |             pair.close += m_nested_kind_start_value; | 
					
						
							|  |  |  |             pair.open += m_nested_kind_start_value; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return pairs; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     virtual Vector<GUI::TextDocumentSpan>& spans() override { return m_spans; } | 
					
						
							|  |  |  |     virtual const Vector<GUI::TextDocumentSpan>& spans() const override { return m_spans; } | 
					
						
							|  |  |  |     virtual void set_span_at_index(size_t index, GUI::TextDocumentSpan span) override { m_spans.at(index) = move(span); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual String highlighter_did_request_text() const override { return m_text; } | 
					
						
							|  |  |  |     virtual void highlighter_did_request_update() override { } | 
					
						
							|  |  |  |     virtual GUI::TextDocument& highlighter_did_request_document() override { return m_document; } | 
					
						
							|  |  |  |     virtual GUI::TextPosition highlighter_did_request_cursor() const override { return {}; } | 
					
						
							|  |  |  |     virtual void highlighter_did_set_spans(Vector<GUI::TextDocumentSpan> spans) override { m_spans = move(spans); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector<GUI::TextDocumentSpan> m_spans; | 
					
						
							|  |  |  |     GUI::TextDocument& m_document; | 
					
						
							|  |  |  |     StringView m_text; | 
					
						
							|  |  |  |     GUI::TextPosition m_start; | 
					
						
							|  |  |  |     u64 m_nested_kind_start_value { 0 }; | 
					
						
							| 
									
										
										
										
											2020-02-07 20:07:15 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-07 12:03:09 +04:30
										 |  |  | 
 | 
					
						
							|  |  |  | template<> | 
					
						
							|  |  |  | struct AK::Traits<Syntax::Highlighter::MatchingTokenPair> : public AK::GenericTraits<Syntax::Highlighter::MatchingTokenPair> { | 
					
						
							|  |  |  |     static unsigned hash(Syntax::Highlighter::MatchingTokenPair const& pair) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return pair_int_hash(u64_hash(pair.open), u64_hash(pair.close)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     static bool equals(Syntax::Highlighter::MatchingTokenPair const& a, Syntax::Highlighter::MatchingTokenPair const& b) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return a.open == b.open && a.close == b.close; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; |