Skip to content

Commit e5b5781

Browse files
authored
Merge pull request #3714 from 1c-syntax/copilot/refactor-string-function-parameters
Add configurable template function highlighting for semantic tokens
2 parents 1cb9cc0 + 8aec16e commit e5b5781

File tree

11 files changed

+979
-199
lines changed

11 files changed

+979
-199
lines changed

src/main/java/com/github/_1c_syntax/bsl/languageserver/configuration/LanguageServerConfiguration.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.github._1c_syntax.bsl.languageserver.configuration.formating.FormattingOptions;
3434
import com.github._1c_syntax.bsl.languageserver.configuration.inlayhints.InlayHintOptions;
3535
import com.github._1c_syntax.bsl.languageserver.configuration.references.ReferencesOptions;
36+
import com.github._1c_syntax.bsl.languageserver.configuration.semantictokens.SemanticTokensOptions;
3637
import com.github._1c_syntax.utils.Absolute;
3738
import jakarta.annotation.PostConstruct;
3839
import lombok.AccessLevel;
@@ -102,6 +103,10 @@ public class LanguageServerConfiguration {
102103
@Setter(value = AccessLevel.NONE)
103104
private ReferencesOptions referencesOptions = new ReferencesOptions();
104105

106+
@JsonProperty("semanticTokens")
107+
@Setter(value = AccessLevel.NONE)
108+
private SemanticTokensOptions semanticTokensOptions = new SemanticTokensOptions();
109+
105110
private String siteRoot = "https://1c-syntax.github.io/bsl-language-server";
106111
private boolean useDevSite;
107112

@@ -217,5 +222,6 @@ private void copyPropertiesFrom(LanguageServerConfiguration configuration) {
217222
PropertyUtils.copyProperties(this.documentLinkOptions, configuration.documentLinkOptions);
218223
PropertyUtils.copyProperties(this.formattingOptions, configuration.formattingOptions);
219224
PropertyUtils.copyProperties(this.referencesOptions, configuration.referencesOptions);
225+
PropertyUtils.copyProperties(this.semanticTokensOptions, configuration.semanticTokensOptions);
220226
}
221227
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2025
5+
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package com.github._1c_syntax.bsl.languageserver.configuration.semantictokens;
23+
24+
import java.util.Map;
25+
import java.util.Set;
26+
27+
/**
28+
* Предварительно разобранные паттерны функций-шаблонизаторов.
29+
* <p>
30+
* Структура:
31+
* <ul>
32+
* <li>localMethods: Set методов для локального вызова (без модуля)</li>
33+
* <li>moduleMethodPairs: Map из имени модуля -> Set методов этого модуля</li>
34+
* </ul>
35+
*
36+
* @param localMethods Методы для локального вызова (без указания модуля)
37+
* @param moduleMethodPairs Методы с указанием модуля (модуль -> набор методов)
38+
*/
39+
public record ParsedStrTemplateMethods(
40+
Set<String> localMethods,
41+
Map<String, Set<String>> moduleMethodPairs
42+
) {
43+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2025
5+
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
package com.github._1c_syntax.bsl.languageserver.configuration.semantictokens;
23+
24+
import com.fasterxml.jackson.annotation.JsonCreator;
25+
import com.fasterxml.jackson.annotation.JsonIgnore;
26+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
27+
import lombok.AllArgsConstructor;
28+
import lombok.Getter;
29+
import lombok.NoArgsConstructor;
30+
31+
import java.util.ArrayList;
32+
import java.util.HashMap;
33+
import java.util.HashSet;
34+
import java.util.List;
35+
import java.util.Locale;
36+
import java.util.Map;
37+
import java.util.Set;
38+
39+
/**
40+
* Настройки для семантических токенов.
41+
* <p>
42+
* Позволяет указать дополнительные функции-шаблонизаторы строк,
43+
* аналогичные СтрШаблон/StrTemplate, для подсветки плейсхолдеров (%1, %2 и т.д.).
44+
*/
45+
@Getter
46+
@AllArgsConstructor(onConstructor = @__({@JsonCreator(mode = JsonCreator.Mode.DISABLED)}))
47+
@NoArgsConstructor
48+
@JsonIgnoreProperties(ignoreUnknown = true)
49+
public class SemanticTokensOptions {
50+
51+
private static final List<String> DEFAULT_STR_TEMPLATE_METHODS = List.of(
52+
// Локальный вызов
53+
"ПодставитьПараметрыВСтроку",
54+
"SubstituteParametersToString",
55+
// Стандартный модуль БСП
56+
"СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку",
57+
// Английский вариант
58+
"StringFunctionsClientServer.SubstituteParametersToString"
59+
);
60+
61+
/**
62+
* Список паттернов "Модуль.Метод" для функций-шаблонизаторов строк.
63+
* <p>
64+
* Строки внутри вызовов этих функций будут подсвечиваться так же,
65+
* как строки в СтрШаблон/StrTemplate (с выделением плейсхолдеров %1, %2 и т.д.).
66+
* <p>
67+
* Формат: "ИмяМодуля.ИмяМетода", например:
68+
* <ul>
69+
* <li>"СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку"</li>
70+
* <li>"StringFunctionsClientServer.SubstituteParametersToString"</li>
71+
* <li>"ПодставитьПараметрыВСтроку" - для локального вызова без указания модуля</li>
72+
* </ul>
73+
* <p>
74+
* По умолчанию включает стандартные варианты из БСП.
75+
*/
76+
private List<String> strTemplateMethods = new ArrayList<>(DEFAULT_STR_TEMPLATE_METHODS);
77+
78+
/**
79+
* Кэшированные разобранные паттерны функций-шаблонизаторов.
80+
*/
81+
@JsonIgnore
82+
private ParsedStrTemplateMethods parsedStrTemplateMethods = parseStrTemplateMethods(DEFAULT_STR_TEMPLATE_METHODS);
83+
84+
/**
85+
* Устанавливает список паттернов функций-шаблонизаторов и пересчитывает кэш.
86+
*
87+
* @param strTemplateMethods Список паттернов
88+
*/
89+
public void setStrTemplateMethods(List<String> strTemplateMethods) {
90+
this.strTemplateMethods = strTemplateMethods;
91+
this.parsedStrTemplateMethods = parseStrTemplateMethods(strTemplateMethods);
92+
}
93+
94+
/**
95+
* Возвращает предварительно разобранные паттерны функций-шаблонизаторов.
96+
*
97+
* @return Разобранные паттерны для быстрого поиска
98+
*/
99+
@JsonIgnore
100+
public ParsedStrTemplateMethods getParsedStrTemplateMethods() {
101+
return parsedStrTemplateMethods;
102+
}
103+
104+
private static ParsedStrTemplateMethods parseStrTemplateMethods(List<String> methods) {
105+
var localMethods = new HashSet<String>();
106+
var moduleMethodPairs = new HashMap<String, Set<String>>();
107+
108+
for (var pattern : methods) {
109+
if (pattern.isBlank()) {
110+
continue;
111+
}
112+
var patternLower = pattern.toLowerCase(Locale.ENGLISH);
113+
114+
if (patternLower.contains(".")) {
115+
var parts = patternLower.split("\\.", 2);
116+
if (parts.length == 2 && !parts[0].isEmpty() && !parts[1].isEmpty()) {
117+
moduleMethodPairs
118+
.computeIfAbsent(parts[0], k -> new HashSet<>())
119+
.add(parts[1]);
120+
}
121+
} else {
122+
localMethods.add(patternLower);
123+
}
124+
}
125+
126+
return new ParsedStrTemplateMethods(localMethods, moduleMethodPairs);
127+
}
128+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright (c) 2018-2025
5+
* Alexey Sosnoviy <[email protected]>, Nikita Fedkin <[email protected]> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* BSL Language Server is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* BSL Language Server is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with BSL Language Server.
21+
*/
22+
/**
23+
* Пакет содержит настройки для семантических токенов.
24+
*/
25+
@NullMarked
26+
package com.github._1c_syntax.bsl.languageserver.configuration.semantictokens;
27+
28+
import org.jspecify.annotations.NullMarked;

src/main/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/StringSemanticTokensSupplier.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
*/
2222
package com.github._1c_syntax.bsl.languageserver.semantictokens;
2323

24+
import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
25+
import com.github._1c_syntax.bsl.languageserver.configuration.events.LanguageServerConfigurationChangedEvent;
26+
import com.github._1c_syntax.bsl.languageserver.configuration.semantictokens.ParsedStrTemplateMethods;
2427
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
2528
import com.github._1c_syntax.bsl.languageserver.semantictokens.strings.AstTokenInfo;
2629
import com.github._1c_syntax.bsl.languageserver.semantictokens.strings.QueryContext;
@@ -33,11 +36,13 @@
3336
import com.github._1c_syntax.bsl.languageserver.utils.MultilingualStringAnalyser;
3437
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
3538
import com.github._1c_syntax.bsl.parser.BSLLexer;
39+
import jakarta.annotation.PostConstruct;
3640
import lombok.RequiredArgsConstructor;
3741
import org.antlr.v4.runtime.Token;
3842
import org.eclipse.lsp4j.Position;
3943
import org.eclipse.lsp4j.Range;
4044
import org.eclipse.lsp4j.SemanticTokenTypes;
45+
import org.springframework.context.event.EventListener;
4146
import org.springframework.stereotype.Component;
4247

4348
import java.util.ArrayList;
@@ -57,6 +62,7 @@
5762
* <li>Запросы SDBL: разбивает строки на части вокруг токенов запроса и добавляет токены SDBL</li>
5863
* <li>НСтр/NStr: подсвечивает языковые ключи (ru=, en=)</li>
5964
* <li>СтрШаблон/StrTemplate: подсвечивает плейсхолдеры (%1, %2)</li>
65+
* <li>Конфигурируемые функции-шаблонизаторы: подсвечивает плейсхолдеры (%1, %2)</li>
6066
* <li>Обычные строки: выдаёт токен для всей строки</li>
6167
* </ul>
6268
*/
@@ -72,6 +78,30 @@ public class StringSemanticTokensSupplier implements SemanticTokensSupplier {
7278
);
7379

7480
private final SemanticTokensHelper helper;
81+
private final LanguageServerConfiguration configuration;
82+
83+
private volatile ParsedStrTemplateMethods parsedStrTemplateMethods;
84+
85+
@PostConstruct
86+
private void init() {
87+
updateParsedStrTemplateMethods();
88+
}
89+
90+
/**
91+
* Обработчик события {@link LanguageServerConfigurationChangedEvent}.
92+
* <p>
93+
* Обновляет кэшированные паттерны функций-шаблонизаторов при изменении конфигурации.
94+
*
95+
* @param event Событие
96+
*/
97+
@EventListener
98+
public void handleEvent(LanguageServerConfigurationChangedEvent event) {
99+
updateParsedStrTemplateMethods();
100+
}
101+
102+
private void updateParsedStrTemplateMethods() {
103+
parsedStrTemplateMethods = configuration.getSemanticTokensOptions().getParsedStrTemplateMethods();
104+
}
75105

76106
@Override
77107
public List<SemanticTokenEntry> getSemanticTokens(DocumentContext documentContext) {
@@ -277,7 +307,7 @@ private void processSpecialContext(
277307

278308
private Map<Token, StringContext> collectSpecialStringContexts(DocumentContext documentContext) {
279309
Map<Token, StringContext> contexts = new HashMap<>();
280-
var visitor = new SpecialContextVisitor(contexts);
310+
var visitor = new SpecialContextVisitor(contexts, parsedStrTemplateMethods);
281311
visitor.visit(documentContext.getAst());
282312
return contexts;
283313
}

0 commit comments

Comments
 (0)