Skip to content

Commit cadca0b

Browse files
authored
Merge pull request #1318 from 1c-syntax/feature/workspaceSymbol
Реализация workspaceSymbol
2 parents 57603d2 + 177902d commit cadca0b

File tree

10 files changed

+281
-22
lines changed

10 files changed

+281
-22
lines changed

src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
7171
capabilities.setCodeActionProvider(Boolean.TRUE);
7272
capabilities.setCodeLensProvider(new CodeLensOptions());
7373
capabilities.setDocumentLinkProvider(new DocumentLinkOptions());
74+
capabilities.setWorkspaceSymbolProvider(Boolean.TRUE);
7475

7576
InitializeResult result = new InitializeResult(capabilities);
7677

src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLWorkspaceService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package com.github._1c_syntax.bsl.languageserver;
2323

2424
import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
25+
import com.github._1c_syntax.bsl.languageserver.providers.SymbolProvider;
2526
import lombok.RequiredArgsConstructor;
2627
import org.apache.commons.beanutils.PropertyUtils;
2728
import org.eclipse.lsp4j.DidChangeConfigurationParams;
@@ -40,10 +41,11 @@
4041
public class BSLWorkspaceService implements WorkspaceService {
4142

4243
private final LanguageServerConfiguration configuration;
44+
private final SymbolProvider symbolProvider;
4345

4446
@Override
4547
public CompletableFuture<List<? extends SymbolInformation>> symbol(WorkspaceSymbolParams params) {
46-
return null;
48+
return CompletableFuture.supplyAsync(() -> symbolProvider.getSymbols(params));
4749
}
4850

4951
@Override

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/MethodSymbol.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import lombok.Value;
3232
import lombok.experimental.NonFinal;
3333
import org.eclipse.lsp4j.Range;
34+
import org.eclipse.lsp4j.SymbolKind;
3435

3536
import java.util.ArrayList;
3637
import java.util.List;
@@ -43,6 +44,9 @@
4344
public class MethodSymbol implements Symbol {
4445
String name;
4546

47+
@Builder.Default
48+
SymbolKind symbolKind = SymbolKind.Method;
49+
4650
Range range;
4751
Range subNameRange;
4852

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/RegionSymbol.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import lombok.Value;
3131
import lombok.experimental.NonFinal;
3232
import org.eclipse.lsp4j.Range;
33+
import org.eclipse.lsp4j.SymbolKind;
3334

3435
import java.util.ArrayList;
3536
import java.util.List;
@@ -42,6 +43,8 @@
4243
@ToString(exclude = {"children", "parent"})
4344
public class RegionSymbol implements Symbol {
4445
String name;
46+
@Builder.Default
47+
SymbolKind symbolKind = SymbolKind.Namespace;
4548
Range range;
4649
Range startRange;
4750
Range endRange;

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/Symbol.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import lombok.Getter;
2626
import lombok.Setter;
2727
import org.eclipse.lsp4j.Range;
28+
import org.eclipse.lsp4j.SymbolKind;
2829

2930
import java.util.Collections;
3031
import java.util.List;
@@ -34,6 +35,8 @@ public interface Symbol {
3435

3536
String getName();
3637

38+
SymbolKind getSymbolKind();
39+
3740
Range getRange();
3841

3942
Optional<Symbol> getParent();
@@ -42,6 +45,10 @@ public interface Symbol {
4245

4346
List<Symbol> getChildren();
4447

48+
default boolean isDeprecated() {
49+
return false;
50+
}
51+
4552
default Optional<Symbol> getRootParent() {
4653
return getParent().flatMap(Symbol::getRootParent).or(() -> Optional.of(this));
4754
}
@@ -53,6 +60,8 @@ static Symbol emptySymbol() {
5360
@Getter
5461
private final String name = "empty";
5562
@Getter
63+
private final SymbolKind symbolKind = SymbolKind.Null;
64+
@Getter
5665
private final Range range = Ranges.create(-1, 0, -1, 0);
5766
@Getter
5867
@Setter

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/VariableSymbol.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import lombok.Value;
3232
import lombok.experimental.NonFinal;
3333
import org.eclipse.lsp4j.Range;
34+
import org.eclipse.lsp4j.SymbolKind;
3435

3536
import java.util.Collections;
3637
import java.util.List;
@@ -42,6 +43,8 @@
4243
@ToString(exclude = {"children", "parent"})
4344
public class VariableSymbol implements Symbol {
4445
String name;
46+
@Builder.Default
47+
SymbolKind symbolKind = SymbolKind.Variable;
4548
Range range;
4649
Range variableNameRange;
4750

src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DocumentSymbolProvider.java

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,15 @@
2929
import org.eclipse.lsp4j.DocumentSymbol;
3030
import org.eclipse.lsp4j.Range;
3131
import org.eclipse.lsp4j.SymbolInformation;
32-
import org.eclipse.lsp4j.SymbolKind;
3332
import org.eclipse.lsp4j.jsonrpc.messages.Either;
3433
import org.springframework.stereotype.Component;
3534

3635
import java.util.List;
37-
import java.util.Map;
3836
import java.util.stream.Collectors;
3937

4038
@Component
4139
public final class DocumentSymbolProvider {
4240

43-
private static final Map<Class<? extends Symbol>, SymbolKind> symbolKinds = Map.of(
44-
MethodSymbol.class, SymbolKind.Method,
45-
RegionSymbol.class, SymbolKind.Namespace,
46-
VariableSymbol.class, SymbolKind.Variable
47-
);
48-
4941
public List<Either<SymbolInformation, DocumentSymbol>> getDocumentSymbols(DocumentContext documentContext) {
5042
return documentContext.getSymbolTree().getChildren().stream()
5143
.map(DocumentSymbolProvider::toDocumentSymbol)
@@ -56,7 +48,7 @@ public List<Either<SymbolInformation, DocumentSymbol>> getDocumentSymbols(Docume
5648
private static DocumentSymbol toDocumentSymbol(Symbol symbol) {
5749
var documentSymbol = new DocumentSymbol(
5850
symbol.getName(),
59-
symbolKinds.get(symbol.getClass()),
51+
symbol.getSymbolKind(),
6052
symbol.getRange(),
6153
getSelectionRange(symbol)
6254
);
@@ -65,7 +57,7 @@ private static DocumentSymbol toDocumentSymbol(Symbol symbol) {
6557
.map(DocumentSymbolProvider::toDocumentSymbol)
6658
.collect(Collectors.toList());
6759

68-
documentSymbol.setDeprecated(isDeprecated(symbol));
60+
documentSymbol.setDeprecated(symbol.isDeprecated());
6961
documentSymbol.setChildren(children);
7062

7163
return documentSymbol;
@@ -85,13 +77,4 @@ private static Range getSelectionRange(Symbol symbol) {
8577
return selectionRange;
8678
}
8779

88-
private static boolean isDeprecated(Symbol symbol) {
89-
boolean deprecated;
90-
if (symbol instanceof MethodSymbol) {
91-
deprecated = ((MethodSymbol) symbol).isDeprecated();
92-
} else {
93-
deprecated = false;
94-
}
95-
return deprecated;
96-
}
9780
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* This file is a part of BSL Language Server.
3+
*
4+
* Copyright © 2018-2020
5+
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Gryzlov <nixel2007@gmail.com> 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.providers;
23+
24+
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
25+
import com.github._1c_syntax.bsl.languageserver.context.ServerContext;
26+
import com.github._1c_syntax.bsl.languageserver.context.symbol.Symbol;
27+
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
28+
import com.github._1c_syntax.bsl.languageserver.context.symbol.variable.VariableKind;
29+
import com.github._1c_syntax.utils.CaseInsensitivePattern;
30+
import lombok.RequiredArgsConstructor;
31+
import lombok.extern.slf4j.Slf4j;
32+
import org.apache.commons.lang3.tuple.Pair;
33+
import org.eclipse.lsp4j.Location;
34+
import org.eclipse.lsp4j.SymbolInformation;
35+
import org.eclipse.lsp4j.WorkspaceSymbolParams;
36+
import org.springframework.stereotype.Component;
37+
38+
import java.net.URI;
39+
import java.util.Collections;
40+
import java.util.List;
41+
import java.util.Optional;
42+
import java.util.regex.Pattern;
43+
import java.util.regex.PatternSyntaxException;
44+
import java.util.stream.Collectors;
45+
import java.util.stream.Stream;
46+
47+
@Slf4j
48+
@Component
49+
@RequiredArgsConstructor
50+
public class SymbolProvider {
51+
52+
private final ServerContext context;
53+
54+
public List<? extends SymbolInformation> getSymbols(WorkspaceSymbolParams params) {
55+
var queryString = Optional.ofNullable(params.getQuery())
56+
.orElse("");
57+
58+
Pattern pattern;
59+
try {
60+
pattern = CaseInsensitivePattern.compile(queryString);
61+
} catch (PatternSyntaxException e) {
62+
LOGGER.debug(e.getMessage(), e);
63+
return Collections.emptyList();
64+
}
65+
66+
return context.getDocuments().values().stream()
67+
.flatMap(SymbolProvider::getSymbolPairs)
68+
.filter(symbolPair -> queryString.isEmpty() || pattern.matcher(symbolPair.getValue().getName()).find())
69+
.map(SymbolProvider::createSymbolInformation)
70+
.collect(Collectors.toList());
71+
}
72+
73+
private static Stream<Pair<URI, Symbol>> getSymbolPairs(DocumentContext documentContext) {
74+
return documentContext.getSymbolTree().getChildrenFlat().stream()
75+
.filter(SymbolProvider::isSupported)
76+
.map(symbol -> Pair.of(documentContext.getUri(), symbol));
77+
}
78+
79+
private static boolean isSupported(Symbol symbol) {
80+
var symbolKind = symbol.getSymbolKind();
81+
switch (symbolKind) {
82+
case Method:
83+
return true;
84+
case Variable:
85+
return ((VariableSymbol) symbol).getKind() != VariableKind.LOCAL;
86+
default:
87+
return false;
88+
}
89+
}
90+
91+
private static SymbolInformation createSymbolInformation(Pair<URI, Symbol> symbolPair) {
92+
var uri = symbolPair.getKey();
93+
var symbol = symbolPair.getValue();
94+
var symbolInformation = new SymbolInformation(
95+
symbol.getName(),
96+
symbol.getSymbolKind(),
97+
new Location(uri.toString(), symbol.getRange())
98+
);
99+
symbolInformation.setDeprecated(symbol.isDeprecated());
100+
return symbolInformation;
101+
}
102+
}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.junit.jupiter.api.Test;
4040
import org.springframework.beans.factory.annotation.Autowired;
4141
import org.springframework.boot.test.context.SpringBootTest;
42+
import org.springframework.test.annotation.DirtiesContext;
4243

4344
import java.util.Collections;
4445
import java.util.List;
@@ -47,6 +48,7 @@
4748
import static org.assertj.core.api.Assertions.assertThat;
4849

4950
@SpringBootTest
51+
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
5052
class CodeActionProviderTest {
5153

5254
@Autowired
@@ -87,11 +89,11 @@ void testGetCodeActions() {
8789

8890
// then
8991
assertThat(codeActions)
90-
.hasSize(3)
9192
.extracting(Either::getRight)
93+
.hasSizeGreaterThanOrEqualTo(3)
9294
.anyMatch(codeAction -> codeAction.getDiagnostics().contains(diagnostics.get(0)))
9395
.anyMatch(codeAction -> codeAction.getDiagnostics().contains(diagnostics.get(1)))
94-
.allMatch(codeAction -> codeAction.getKind().equals(CodeActionKind.QuickFix))
96+
.anyMatch(codeAction -> codeAction.getKind().equals(CodeActionKind.QuickFix))
9597
;
9698
}
9799

@@ -117,6 +119,7 @@ void testEmptyDiagnosticList() {
117119

118120
// then
119121
assertThat(codeActions)
122+
.filteredOn(codeAction -> codeAction.getRight().getKind().equals(CodeActionKind.QuickFix))
120123
.isEmpty();
121124
}
122125
}

0 commit comments

Comments
 (0)