1
#include "script/ScriptDocumentOperation.h"
2
#include "script/ScriptSemanticTokenLegend.h"
6
using SemanticTokenModifiers = variable::BitFlags<SemanticTokenModifier>;
9
/// \see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens
11
/// \todo Очень непонятно и очень некрасиво. Стоит переписать, чтобы было более понятно.
12
SemanticTokenType ScriptDocumentOperation::selectSemanticTokenType(const variable::Variable & var, const SemanticTokenType function_index) const {
13
if (var.type() == variable::ValueType::Function)
14
return function_index;
16
const std::vector<std::u16string> & tokenTypes = _doc.server().server_capabilities().semanticTokensProvider.legend.tokenTypes;
18
if (const variable::Value & spec_origin_value = var.spec().object()->find(variable::SPEC_ORIGIN); spec_origin_value.isString())
19
for (size_t type_index = 0; type_index < tokenTypes.size(); ++type_index)
20
if (spec_origin_value.getString() == tokenTypes[type_index])
21
return static_cast<SemanticTokenType>(type_index);
23
if (!var.spec().object()->variables().empty())
24
return SemanticTokenType::BuiltInModule; // \todo Проверить, тот ли тип?
27
case variable::ValueType::Object:
28
return SemanticTokenType::Struct; // \todo Проверить, тот ли тип?
32
return SemanticTokenType::Property; // \todo Проверить, тот ли тип?
35
SemanticTokenModifiers makeSemanticTokenModifiers(const variable::Variable & var) {
36
SemanticTokenModifiers modifiers;
38
if (!var.spec().object()->find(variable::SPEC_READONLY).isNull()) modifiers.set(SemanticTokenModifier::Readonly);
39
if (!var.spec().object()->find(variable::SPEC_PARAMETER).isNull()) modifiers.set(SemanticTokenModifier::Parameter);
40
if (!var.spec().object()->find(variable::SPEC_INPUT).isNull()) modifiers.set(SemanticTokenModifier::Input);
41
if (!var.spec().object()->find(variable::SPEC_OUTPUT).isNull()) modifiers.set(SemanticTokenModifier::Output);
46
struct TokenInfo { int64_t length, type, modifiers; };
48
bool operator() (const lsp::Position & x1, const lsp::Position & x2) const { return x1 < x2; }
51
variable::Value ScriptDocumentOperation::produceSemanticTokensResponse() const
53
std::map<lsp::Position, TokenInfo, PositionComp> tokens;
54
const std::function insertToken =
55
[&tokens](const inout::TokenLocation & loc, const SemanticTokenType type, const SemanticTokenModifiers & modifiers)
57
const auto & range = loc.range();
59
assert(range.start().line() == range.end().line()); // Предполагаем, что токен располагается на одной строке!
60
const TokenInfo & tokenInfo = {
61
.length = range.end().character() - range.start().character(),
62
.type = static_cast<int64_t>(type),
63
.modifiers = modifiers.getRawValue(),
66
tokens.insert({ loc.range().start(), tokenInfo });
69
for(const variable::Variable & v : _semantic_data.declared())
70
if (isInCurrentFile(v.location()) and not v.value().isError()) {
71
insertToken(v.location(),
72
selectSemanticTokenType(v, SemanticTokenType::Function), // \todo Проверить, тот ли тип?
73
makeSemanticTokenModifiers(v) | SemanticTokenModifier::Declaration); // \todo Проверить, тот ли модификатор?
76
for(const auto & [declared_variable, using_location] : _semantic_data.used())
77
if (isInCurrentFile(using_location)) {
78
SemanticTokenModifiers modifiers = makeSemanticTokenModifiers(declared_variable);
80
if (declared_variable.location().range() != inout::Range {{0,0},{0,0}})
81
modifiers.set(SemanticTokenModifier::Anchor);
83
if (isRemoteFunctionLaunch(using_location))
84
modifiers.set(SemanticTokenModifier::Remote);
86
insertToken(using_location,
87
selectSemanticTokenType(declared_variable, SemanticTokenType::Method), // \todo Проверить, тот ли тип?
88
modifiers); // \todo Проверить, тот ли модификатор?
91
for(const auto & [t, ref] : _semantic_data.refs())
92
if (isInCurrentFile(t.location())) {
93
insertToken(t.location(),
94
SemanticTokenType::String, // \todo Проверить, тот ли тип?
95
SemanticTokenModifier::Anchor); // \todo Проверить, тот ли модификатор?
98
for(const inout::Token & t : _semantic_data.tokens())
99
if (isInCurrentFile(t.location()) and t.qualification() == inout::TokenQualification::Keyword) {
100
SemanticTokenType type;
101
if (t.lexeme() == u"true" || t.lexeme() == u"false")
102
type = SemanticTokenType::Boolean; // \todo Проверить, тот ли тип?
103
else if (t.lexeme() == u"undef" || t.lexeme() == u"null")
104
type = SemanticTokenType::Number; // \todo Проверить, тот ли тип?
106
type = SemanticTokenType::Keyword; // \todo Проверить, тот ли тип?
108
insertToken(t.location(), type, SemanticTokenModifiers::Empty);
111
std::vector<variable::Value> sem_tokens;
113
for(const auto & [p, t] : tokens) {
114
sem_tokens.emplace_back(static_cast<int64_t>(p.line()));
115
sem_tokens.emplace_back(static_cast<int64_t>(p.character()));
116
sem_tokens.emplace_back(t.length);
117
sem_tokens.emplace_back(t.type);
118
sem_tokens.emplace_back(t.modifiers);
121
return variable::Object{{{ u"data", sem_tokens }}};