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>
|
2020-03-16 01:05:06 +02:00
|
|
|
#include <LibGfx/Palette.h>
|
2023-08-29 12:43:41 +03:30
|
|
|
#include <LibSyntax/Document.h>
|
2021-02-07 16:56:02 +01:00
|
|
|
#include <LibSyntax/HighlighterClient.h>
|
2023-03-08 16:10:16 +00:00
|
|
|
#include <LibSyntax/Language.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
|
|
|
class Highlighter {
|
|
|
|
AK_MAKE_NONCOPYABLE(Highlighter);
|
|
|
|
AK_MAKE_NONMOVABLE(Highlighter);
|
2020-02-07 20:07:15 +01:00
|
|
|
|
|
|
|
public:
|
2022-03-04 13:26:19 -07:00
|
|
|
virtual ~Highlighter() = default;
|
2020-02-07 20:07:15 +01:00
|
|
|
|
2021-02-07 15:15:10 +01:00
|
|
|
virtual Language language() const = 0;
|
2022-10-26 10:01:13 -05:00
|
|
|
virtual Optional<StringView> comment_prefix() const = 0;
|
|
|
|
virtual Optional<StringView> comment_suffix() const = 0;
|
2022-04-01 20:58:27 +03:00
|
|
|
virtual void rehighlight(Palette const&) = 0;
|
2020-03-13 00:51:02 +02:00
|
|
|
virtual void highlight_matching_token_pair();
|
2020-02-07 20:07:15 +01:00
|
|
|
|
2023-07-07 22:48:11 -04:00
|
|
|
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:
|
2022-03-04 13:26:19 -07:00
|
|
|
Highlighter() = default;
|
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 };
|
2023-08-29 12:43:41 +03:30
|
|
|
TextDocumentSpan span_backup;
|
2020-02-07 20:07:15 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
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:
|
2023-08-29 12:43:41 +03:30
|
|
|
ProxyHighlighterClient(Syntax::HighlighterClient& client, TextPosition start, u64 nested_kind_start_value, StringView source)
|
2021-06-07 12:03:09 +04:30
|
|
|
: m_document(client.get_document())
|
|
|
|
, m_text(source)
|
|
|
|
, m_start(start)
|
|
|
|
, m_nested_kind_start_value(nested_kind_start_value)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-08-29 12:43:41 +03:30
|
|
|
Vector<TextDocumentSpan> corrected_spans() const
|
2021-06-07 12:03:09 +04:30
|
|
|
{
|
2023-08-29 12:43:41 +03:30
|
|
|
Vector<TextDocumentSpan> spans { m_spans };
|
2021-06-07 12:03:09 +04:30
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-08-29 12:43:41 +03:30
|
|
|
Vector<TextDocumentFoldingRegion> corrected_folding_regions() const
|
2023-03-03 14:28:23 +00:00
|
|
|
{
|
2023-08-29 12:43:41 +03:30
|
|
|
Vector<TextDocumentFoldingRegion> folding_regions { m_folding_regions };
|
2023-03-03 14:28:23 +00:00
|
|
|
for (auto& entry : folding_regions) {
|
|
|
|
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(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return folding_regions;
|
|
|
|
}
|
|
|
|
|
2021-06-07 12:03:09 +04:30
|
|
|
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:
|
2023-08-29 12:43:41 +03:30
|
|
|
virtual Vector<TextDocumentSpan> const& spans() const override { return m_spans; }
|
|
|
|
virtual void set_span_at_index(size_t index, TextDocumentSpan span) override { m_spans.at(index) = move(span); }
|
2021-06-07 12:03:09 +04:30
|
|
|
|
2023-08-29 12:43:41 +03:30
|
|
|
virtual Vector<TextDocumentFoldingRegion>& folding_regions() override { return m_folding_regions; }
|
|
|
|
virtual Vector<TextDocumentFoldingRegion> const& folding_regions() const override { return m_folding_regions; }
|
2023-02-23 15:33:48 +00:00
|
|
|
|
2023-12-16 17:49:34 +03:30
|
|
|
virtual ByteString highlighter_did_request_text() const override { return m_text; }
|
2021-06-07 12:03:09 +04:30
|
|
|
virtual void highlighter_did_request_update() override { }
|
2023-08-29 12:43:41 +03:30
|
|
|
virtual Document& highlighter_did_request_document() override { return m_document; }
|
|
|
|
virtual TextPosition highlighter_did_request_cursor() const override { return {}; }
|
|
|
|
virtual void highlighter_did_set_spans(Vector<TextDocumentSpan> spans) override { m_spans = move(spans); }
|
|
|
|
virtual void highlighter_did_set_folding_regions(Vector<TextDocumentFoldingRegion> folding_regions) override { m_folding_regions = folding_regions; }
|
|
|
|
|
|
|
|
Vector<TextDocumentSpan> m_spans;
|
|
|
|
Vector<TextDocumentFoldingRegion> m_folding_regions;
|
|
|
|
Document& m_document;
|
2021-06-07 12:03:09 +04:30
|
|
|
StringView m_text;
|
2023-08-29 12:43:41 +03:30
|
|
|
TextPosition m_start;
|
2021-06-07 12:03:09 +04:30
|
|
|
u64 m_nested_kind_start_value { 0 };
|
2020-02-07 20:07:15 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
2021-06-07 12:03:09 +04:30
|
|
|
|
|
|
|
template<>
|
2023-11-08 20:29:12 +01:00
|
|
|
struct AK::Traits<Syntax::Highlighter::MatchingTokenPair> : public AK::DefaultTraits<Syntax::Highlighter::MatchingTokenPair> {
|
2021-06-07 12:03:09 +04:30
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|