Skip to content

Commit cbf9bc9

Browse files
authored
Merge pull request #3779 from 1c-syntax/feature/fixes260116
Исправление ошибок в ролях и описании
2 parents f4137ab + 89bb49a commit cbf9bc9

File tree

11 files changed

+161
-180
lines changed

11 files changed

+161
-180
lines changed

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ dependencies {
8282
api("org.eclipse.lsp4j", "org.eclipse.lsp4j.websocket.jakarta", "0.24.0")
8383

8484
// 1c-syntax
85-
api("io.github.1c-syntax", "bsl-parser", "0.30.0-rc.2") {
85+
api("io.github.1c-syntax", "bsl-parser", "0.30.0-rc.5") {
8686
exclude("com.ibm.icu", "*")
8787
exclude("org.antlr", "ST4")
8888
exclude("org.antlr", "antlr-runtime")
8989
}
9090
api("io.github.1c-syntax", "utils", "0.6.8")
91-
api("io.github.1c-syntax", "mdclasses", "0.17.3")
91+
api("io.github.1c-syntax", "mdclasses", "0.17.4")
9292
api("io.github.1c-syntax", "bsl-common-library", "0.9.2")
9393
api("io.github.1c-syntax", "supportconf", "0.15.0")
9494

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ private void addBslDocTokensPerLine(
212212
int lineLength = lineText.length();
213213
int charOffset = (lineIdx == 0) ? fileStartChar : 0;
214214

215-
var lineElements = elementsByLine.getOrDefault(lineIdx, List.of());
215+
var lineElements = elementsByLine.getOrDefault(fileLine, List.of());
216216

217217
if (lineElements.isEmpty()) {
218218
if (lineLength > 0) {

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private void addDirectives(List<SemanticTokenEntry> entries, BSLParser.FileConte
9898
}
9999
}
100100

101-
// Other preprocessor directives: Macro for each HASH and PREPROC_* token,
101+
// Other preprocessor directives: Macro for entire directive keyword (#Если, #КонецЕсли, etc.),
102102
// excluding region start/end, native, use (handled as Namespace)
103103
private void addOtherPreprocs(List<SemanticTokenEntry> entries, BSLParser.FileContext ast) {
104104
for (var preprocessor : Trees.<BSLParser.PreprocessorContext>findAllRuleNodes(ast, BSLParser.RULE_preprocessor)) {
@@ -107,13 +107,30 @@ private void addOtherPreprocs(List<SemanticTokenEntry> entries, BSLParser.FileCo
107107
continue; // region handled as Namespace above
108108
}
109109

110+
// Find HASH token and keyword tokens to combine them into single token
111+
Token hashToken = null;
112+
boolean firstKeywordCombined = false;
113+
110114
for (Token token : Trees.getTokens(preprocessor)) {
111115
if (token.getChannel() != Token.DEFAULT_CHANNEL) {
112116
continue;
113117
}
114-
String symbolicName = BSLLexer.VOCABULARY.getSymbolicName(token.getType());
115-
if (token.getType() == BSLLexer.HASH || (symbolicName != null && symbolicName.startsWith("PREPROC_"))) {
116-
helper.addRange(entries, Ranges.create(token), SemanticTokenTypes.Macro);
118+
if (token.getType() == BSLLexer.HASH) {
119+
hashToken = token;
120+
} else {
121+
String symbolicName = BSLLexer.VOCABULARY.getSymbolicName(token.getType());
122+
if (symbolicName != null && symbolicName.startsWith("PREPROC_")) {
123+
// Track keyword tokens for combining with HASH
124+
if (hashToken != null && !firstKeywordCombined) {
125+
// First keyword after HASH - combine them into single token
126+
helper.addRange(entries, Ranges.create(hashToken, token), SemanticTokenTypes.Macro);
127+
firstKeywordCombined = true;
128+
} else {
129+
// Subsequent keywords (e.g., "Сервер", "Тогда" in "#Если Сервер Тогда")
130+
// or keyword without preceding HASH (shouldn't happen in valid syntax)
131+
helper.addRange(entries, Ranges.create(token), SemanticTokenTypes.Macro);
132+
}
133+
}
117134
}
118135
}
119136
}

src/test/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/description/MethodDescriptionTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ void testMethod12() {
142142
assertThat(type.description()).isEmpty();
143143
assertThat(type.fields()).isEmpty();
144144
assertThat(type).isInstanceOf(HyperlinkTypeDescription.class);
145-
assertThat(((HyperlinkTypeDescription) type).hyperlink()).isEqualTo(Hyperlink.create("ОбщийМодуль.Метод()"));
145+
assertThat(((HyperlinkTypeDescription) type).hyperlink().link()).isEqualTo("ОбщийМодуль.Метод");
146146
}
147147

148148
@Test
@@ -161,7 +161,7 @@ void testMethod11() {
161161
assertThat(param.name()).isEqualTo("ОбщийМодуль.Метод");
162162
assertThat(param.types()).hasSize(1);
163163
assertThat(param.isHyperlink()).isTrue();
164-
assertThat(param.link()).isEqualTo(Hyperlink.create("ОбщийМодуль.Метод()"));
164+
assertThat(param.link().link()).isEqualTo("ОбщийМодуль.Метод");
165165
}
166166

167167
@Test
@@ -175,7 +175,7 @@ void testMethod10() {
175175
assertThat(method.getCallOptions()).isEmpty();
176176
assertThat(method.getParameters()).isEmpty();
177177
assertThat(method.getReturnedValue()).isEmpty();
178-
assertThat(method.getLinks()).contains(Hyperlink.create("ОбщийМодуль.Метод()"));
178+
assertThat(method.getLinks()).extracting(Hyperlink::link).contains("ОбщийМодуль.Метод");
179179
}
180180

181181
@Test

src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/SemanticTokensProviderTest.java

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -346,18 +346,14 @@ void preprocessorDirectives() {
346346

347347
var decoded = getDecodedTokens(bsl);
348348

349-
// Verify preprocessor macro tokens on specific lines
349+
// Verify preprocessor macro tokens - # and keyword are combined into single token
350350
var expectedTokens = List.of(
351-
new ExpectedToken(0, 0, 1, SemanticTokenTypes.Macro, "#"),
352-
new ExpectedToken(0, 1, 4, SemanticTokenTypes.Macro, "Если"),
351+
new ExpectedToken(0, 0, 5, SemanticTokenTypes.Macro, "#Если"),
353352
new ExpectedToken(0, 6, 6, SemanticTokenTypes.Macro, "Сервер"),
354353
new ExpectedToken(0, 13, 5, SemanticTokenTypes.Macro, "Тогда"),
355-
new ExpectedToken(3, 0, 1, SemanticTokenTypes.Macro, "#"),
356-
new ExpectedToken(3, 1, 9, SemanticTokenTypes.Macro, "ИначеЕсли"),
357-
new ExpectedToken(4, 0, 1, SemanticTokenTypes.Macro, "#"),
358-
new ExpectedToken(4, 1, 5, SemanticTokenTypes.Macro, "Иначе"),
359-
new ExpectedToken(5, 0, 1, SemanticTokenTypes.Macro, "#"),
360-
new ExpectedToken(5, 1, 9, SemanticTokenTypes.Macro, "КонецЕсли")
354+
new ExpectedToken(3, 0, 10, SemanticTokenTypes.Macro, "#ИначеЕсли"),
355+
new ExpectedToken(4, 0, 6, SemanticTokenTypes.Macro, "#Иначе"),
356+
new ExpectedToken(5, 0, 10, SemanticTokenTypes.Macro, "#КонецЕсли")
361357
);
362358

363359
assertContainsTokens(decoded, expectedTokens);
@@ -391,6 +387,8 @@ void literals() {
391387
@Test
392388
void methodDescriptionComments() {
393389
String bsl = """
390+
// просто коммент
391+
394392
// Описание процедуры
395393
// Параметры:
396394
// Парам - Число - описание
@@ -402,41 +400,43 @@ void methodDescriptionComments() {
402400
var decoded = getDecodedTokens(bsl);
403401

404402
// Documentation comments are now split around BSL doc keywords and operators.
405-
// Line 0: "// Описание процедуры" - no BSL doc elements, full line as Comment+Documentation
406-
// Line 1: "// Параметры:" - keyword in structural position
407-
// Line 2: "// Парам - Число - описание" - parameter name, type, operator, description
403+
// Line 3: "// Описание процедуры" - no BSL doc elements, full line as Comment+Documentation
404+
// Line 4: "// Параметры:" - keyword in structural position
405+
// Line 4: "// Парам - Число - описание" - parameter name, type, operator, description
408406
// Body comment on line 4 should NOT have Documentation modifier
409407
var expected = List.of(
410-
// Line 0: full line as Comment+Documentation
411-
new ExpectedToken(0, 0, 21, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, "// Описание процедуры"),
412-
// Line 1: "// " before keyword
413-
new ExpectedToken(1, 0, 3, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, "// "),
414-
// Line 1: "Параметры:" keyword
415-
new ExpectedToken(1, 3, 10, SemanticTokenTypes.Macro, SemanticTokenModifiers.Documentation, "Параметры:"),
416-
// Line 2: "// " before param name
417-
new ExpectedToken(2, 0, 4, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, "// "),
418-
// Line 2: "Парам" parameter name
419-
new ExpectedToken(2, 4, 5, SemanticTokenTypes.Parameter, SemanticTokenModifiers.Documentation, "Парам"),
420-
// Line 2: " " between param name and dash
421-
new ExpectedToken(2, 9, 3, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, " - "),
422-
// Line 2: "Число" type
423-
new ExpectedToken(2, 12, 5, SemanticTokenTypes.Type, SemanticTokenModifiers.Documentation, "Число"),
424-
// Line 2: " " between type and second dash
425-
new ExpectedToken(2, 17, 11, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, " - описание"),
426-
// Line 3: Процедура keyword
427-
new ExpectedToken(3, 0, 9, SemanticTokenTypes.Keyword, "Процедура"),
428-
// Line 3: ДокТест method name
429-
new ExpectedToken(3, 10, 7, SemanticTokenTypes.Method, "ДокТест"),
430-
// Line 3: ( operator
431-
new ExpectedToken(3, 17, 1, SemanticTokenTypes.Operator, "("),
432-
// Line 3: Парам parameter definition
433-
new ExpectedToken(3, 18, 5, SemanticTokenTypes.Parameter, SemanticTokenModifiers.Definition, "Парам"),
434-
// Line 3: ) operator
435-
new ExpectedToken(3, 23, 1, SemanticTokenTypes.Operator, ")"),
436-
// Line 4: body comment (no Documentation modifier)
437-
new ExpectedToken(4, 2, 22, SemanticTokenTypes.Comment, "// обычный комментарий"),
438-
// Line 5: КонецПроцедуры keyword
439-
new ExpectedToken(5, 0, 14, SemanticTokenTypes.Keyword, "КонецПроцедуры")
408+
new ExpectedToken(0, 0, 17, SemanticTokenTypes.Comment, "// просто коммент"),
409+
410+
// Line 2: full line as Comment+Documentation
411+
new ExpectedToken(2, 0, 21, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, "// Описание процедуры"),
412+
// Line 3: "// " before keyword
413+
new ExpectedToken(3, 0, 3, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, "// "),
414+
// Line 3: "Параметры:" keyword
415+
new ExpectedToken(3, 3, 10, SemanticTokenTypes.Macro, SemanticTokenModifiers.Documentation, "Параметры:"),
416+
// Line 4: "// " before param name
417+
new ExpectedToken(4, 0, 4, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, "// "),
418+
// Line 4: "Парам" parameter name
419+
new ExpectedToken(4, 4, 5, SemanticTokenTypes.Parameter, SemanticTokenModifiers.Documentation, "Парам"),
420+
// Line 4: " " between param name and dash
421+
new ExpectedToken(4, 9, 3, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, " - "),
422+
// Line 4: "Число" type
423+
new ExpectedToken(4, 12, 5, SemanticTokenTypes.Type, SemanticTokenModifiers.Documentation, "Число"),
424+
// Line 4: " " between type and second dash
425+
new ExpectedToken(4, 17, 11, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, " - описание"),
426+
// Line 5: Процедура keyword
427+
new ExpectedToken(5, 0, 9, SemanticTokenTypes.Keyword, "Процедура"),
428+
// Line 5: ДокТест method name
429+
new ExpectedToken(5, 10, 7, SemanticTokenTypes.Method, "ДокТест"),
430+
// Line 5: ( operator
431+
new ExpectedToken(5, 17, 1, SemanticTokenTypes.Operator, "("),
432+
// Line 5: Парам parameter definition
433+
new ExpectedToken(5, 18, 5, SemanticTokenTypes.Parameter, SemanticTokenModifiers.Definition, "Парам"),
434+
// Line 5: ) operator
435+
new ExpectedToken(5, 23, 1, SemanticTokenTypes.Operator, ")"),
436+
// Line 6: body comment (no Documentation modifier)
437+
new ExpectedToken(6, 2, 22, SemanticTokenTypes.Comment, "// обычный комментарий"),
438+
// Line 7: КонецПроцедуры keyword
439+
new ExpectedToken(7, 0, 14, SemanticTokenTypes.Keyword, "КонецПроцедуры")
440440
);
441441

442442
assertTokensMatch(decoded, expected);
@@ -465,7 +465,6 @@ void variableDescriptionComments() {
465465
new ExpectedToken(1, 14, 8, SemanticTokenTypes.Comment, SemanticTokenModifiers.Documentation, "// трейл")
466466
);
467467

468-
469468
assertTokensMatch(decoded, expected);
470469
}
471470

src/test/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/BslDocSemanticTokensSupplierTest.java

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import com.github._1c_syntax.bsl.languageserver.util.TestUtils;
2828
import org.eclipse.lsp4j.SemanticTokenModifiers;
2929
import org.eclipse.lsp4j.SemanticTokenTypes;
30-
import org.eclipse.lsp4j.SemanticTokensLegend;
3130
import org.junit.jupiter.api.BeforeEach;
3231
import org.junit.jupiter.api.Test;
3332
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,8 +36,6 @@
3736
import java.util.List;
3837
import java.util.Set;
3938

40-
import static org.assertj.core.api.Assertions.assertThat;
41-
4239
@SpringBootTest
4340
@CleanupContextBeforeClassAndAfterEachTestMethod
4441
@Import(SemanticTokensTestHelper.class)
@@ -50,9 +47,6 @@ class BslDocSemanticTokensSupplierTest {
5047
@Autowired
5148
private SemanticTokensTestHelper helper;
5249

53-
@Autowired
54-
private SemanticTokensLegend legend;
55-
5650
@BeforeEach
5751
void init() {
5852
supplier.setMultilineTokenSupport(false);
@@ -198,15 +192,14 @@ void testMultipleTypesOnSeparateLines() {
198192
var decoded = helper.getDecodedTokens(bsl, supplier);
199193

200194
// then - All three types should be Type with Documentation modifier
201-
int typeTypeIdx = legend.getTokenTypes().indexOf(SemanticTokenTypes.Type);
202-
int docModifierMask = 1 << legend.getTokenModifiers().indexOf(SemanticTokenModifiers.Documentation);
203-
204-
var typeTokens = decoded.stream()
205-
.filter(t -> t.type() == typeTypeIdx && (t.modifiers() & docModifierMask) != 0)
206-
.toList();
207-
208-
// Should have 3 type tokens: СправочникСсылка, ДокументСсылка, ПеречислениеСсылка
209-
assertThat(typeTokens).hasSize(3);
195+
helper.assertContainsTokens(decoded, List.of(
196+
new ExpectedToken(2, 15, 16, SemanticTokenTypes.Type,
197+
Set.of(SemanticTokenModifiers.Documentation), "СправочникСсылка"),
198+
new ExpectedToken(3, 22, 14, SemanticTokenTypes.Type,
199+
Set.of(SemanticTokenModifiers.Documentation), "ДокументСсылка"),
200+
new ExpectedToken(4, 22, 18, SemanticTokenTypes.Type,
201+
Set.of(SemanticTokenModifiers.Documentation), "ПеречислениеСсылка")
202+
));
210203
}
211204

212205
@Test
@@ -226,15 +219,12 @@ void testMultipleReturnTypesOnSeparateLines() {
226219
var decoded = helper.getDecodedTokens(bsl, supplier);
227220

228221
// then - Both types should be Type with Documentation modifier
229-
int typeTypeIdx = legend.getTokenTypes().indexOf(SemanticTokenTypes.Type);
230-
int docModifierMask = 1 << legend.getTokenModifiers().indexOf(SemanticTokenModifiers.Documentation);
231-
232-
var typeTokens = decoded.stream()
233-
.filter(t -> t.type() == typeTypeIdx && (t.modifiers() & docModifierMask) != 0)
234-
.toList();
235-
236-
// Should have 2 type tokens: СправочникСсылка, ДокументСсылка
237-
assertThat(typeTokens).hasSize(2);
222+
helper.assertContainsTokens(decoded, List.of(
223+
new ExpectedToken(2, 4, 16, SemanticTokenTypes.Type,
224+
Set.of(SemanticTokenModifiers.Documentation), "СправочникСсылка"),
225+
new ExpectedToken(3, 6, 14, SemanticTokenTypes.Type,
226+
Set.of(SemanticTokenModifiers.Documentation), "ДокументСсылка")
227+
));
238228
}
239229

240230
@Test
@@ -250,27 +240,29 @@ void testMultilineSupport() {
250240

251241
var documentContext = TestUtils.getDocumentContext(bsl);
252242

253-
// Test without multiline support
243+
// Test without multiline support - should have 3 separate comment tokens (one per line)
254244
supplier.setMultilineTokenSupport(false);
255245
var tokensWithoutMultiline = helper.decodeFromEntries(supplier.getSemanticTokens(documentContext));
256246

257-
// Test with multiline support
247+
helper.assertContainsTokens(tokensWithoutMultiline, List.of(
248+
new ExpectedToken(0, 0, 25, SemanticTokenTypes.Comment,
249+
Set.of(SemanticTokenModifiers.Documentation), "// Первая строка описания"),
250+
new ExpectedToken(1, 0, 25, SemanticTokenTypes.Comment,
251+
Set.of(SemanticTokenModifiers.Documentation), "// Вторая строка описания"),
252+
new ExpectedToken(2, 0, 25, SemanticTokenTypes.Comment,
253+
Set.of(SemanticTokenModifiers.Documentation), "// Третья строка описания")
254+
));
255+
256+
// Test with multiline support - should merge consecutive lines into one token
258257
supplier.setMultilineTokenSupport(true);
259258
var tokensWithMultiline = helper.decodeFromEntries(supplier.getSemanticTokens(documentContext));
260259

261-
// Without multiline: should have 3 separate comment tokens (one per line)
262-
// With multiline: may merge consecutive lines into fewer tokens
263-
int commentTypeIdx = legend.getTokenTypes().indexOf(SemanticTokenTypes.Comment);
264-
265-
var commentTokensWithout = tokensWithoutMultiline.stream()
266-
.filter(t -> t.type() == commentTypeIdx)
267-
.toList();
268-
var commentTokensWith = tokensWithMultiline.stream()
269-
.filter(t -> t.type() == commentTypeIdx)
270-
.toList();
271-
272-
// With multiline support, we expect fewer or equal number of tokens
273-
assertThat(commentTokensWith.size()).isLessThanOrEqualTo(commentTokensWithout.size());
260+
// With multiline support, all 3 lines are merged into single token starting at line 0
261+
// Length is 77 (25 + 1 + 25 + 1 + 25 = 77 including newlines)
262+
helper.assertContainsTokens(tokensWithMultiline, List.of(
263+
new ExpectedToken(0, 0, 77, SemanticTokenTypes.Comment,
264+
Set.of(SemanticTokenModifiers.Documentation), "// Первая строка описания...")
265+
));
274266
}
275267
}
276268

src/test/java/com/github/_1c_syntax/bsl/languageserver/semantictokens/CommentSemanticTokensSupplierTest.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434

3535
import java.util.List;
3636

37-
import static org.assertj.core.api.Assertions.assertThat;
38-
3937
@SpringBootTest
4038
@CleanupContextBeforeClassAndAfterEachTestMethod
4139
@Import(SemanticTokensTestHelper.class)
@@ -134,19 +132,20 @@ void testMultilineCommentTokens() {
134132
supplier.setMultilineTokenSupport(false);
135133
var tokensWithoutMultiline = helper.decodeFromEntries(supplier.getSemanticTokens(documentContext));
136134

135+
helper.assertTokensMatch(tokensWithoutMultiline, List.of(
136+
new ExpectedToken(1, 2, 21, SemanticTokenTypes.Comment, "// Первый комментарий"),
137+
new ExpectedToken(2, 2, 21, SemanticTokenTypes.Comment, "// Второй комментарий"),
138+
new ExpectedToken(3, 2, 21, SemanticTokenTypes.Comment, "// Третий комментарий")
139+
));
140+
137141
// Test with multiline support - should have 1 merged token
138142
supplier.setMultilineTokenSupport(true);
139143
var tokensWithMultiline = helper.decodeFromEntries(supplier.getSemanticTokens(documentContext));
140144

141-
// then
142-
// Without multiline: 3 separate tokens
143-
assertThat(tokensWithoutMultiline).hasSize(3);
144-
145-
// With multiline: 1 merged token for consecutive comments
146-
assertThat(tokensWithMultiline).hasSize(1);
147-
148-
// The merged token should start on line 1 (0-indexed)
149-
assertThat(tokensWithMultiline.get(0).line()).isEqualTo(1);
145+
// With multiline: 1 merged token for consecutive comments (length = 21 + 1 + 21 + 1 + 21 = 65)
146+
helper.assertTokensMatch(tokensWithMultiline, List.of(
147+
new ExpectedToken(1, 2, 65, SemanticTokenTypes.Comment, "// Первый комментарий...")
148+
));
150149
}
151150

152151
@Test

0 commit comments

Comments
 (0)