Skip to content

Commit e7e2015

Browse files
committed
option added to generate workspace symbols from spring index on demand
1 parent 4e0ec92 commit e7e2015

File tree

10 files changed

+119
-15
lines changed

10 files changed

+119
-15
lines changed

eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/Constants.java

+2
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,6 @@ public class Constants {
5454

5555
public static final String PREF_BEANS_STRUCTURE_TREE = "boot-java.java.beans-structure-tree";
5656

57+
public static final String PREF_SYMBOLS_FROM_NEW_INDEX = "boot-java.java.symbols-from-new-index";
58+
5759
}

eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java

+1
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ private void sendConfiguration() {
201201
javaCompletionSettings.put("inject-bean", preferenceStore.getBoolean(Constants.PREF_COMPLETION_JAVA_INJECT_BEAN));
202202

203203
javaSettings.put("beans-structure-tree", preferenceStore.getBoolean(Constants.PREF_BEANS_STRUCTURE_TREE));
204+
javaSettings.put("symbols-from-new-index", preferenceStore.getBoolean(Constants.PREF_SYMBOLS_FROM_NEW_INDEX));
204205
javaSettings.put("completions", javaCompletionSettings);
205206
javaSettings.put("reconcilers", preferenceStore.getBoolean(Constants.PREF_JAVA_RECONCILE));
206207

eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/BootJavaPreferencesPage.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ protected void createFieldEditors() {
5757
addField(new BooleanFieldEditor(Constants.PREF_COMPLETION_JAVA_INJECT_BEAN, "Inject Bean completion proposals in Java editor", fieldEditorParent));
5858

5959
// Experimental Beans tree
60-
addField(new BooleanFieldEditor(Constants.PREF_BEANS_STRUCTURE_TREE, "Beans structure tree in the outline view", fieldEditorParent));
60+
addField(new BooleanFieldEditor(Constants.PREF_BEANS_STRUCTURE_TREE, "Beans structure tree in the outline view (experimental)", fieldEditorParent));
61+
62+
// Experimental symbols from new index
63+
addField(new BooleanFieldEditor(Constants.PREF_SYMBOLS_FROM_NEW_INDEX, "Generate workspace symbols from index (experimental)", fieldEditorParent));
6164

6265
Composite c = new Composite(fieldEditorParent, SWT.NONE);
6366
GridDataFactory.fillDefaults().grab(true, false).applyTo(c);

eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/PrefsInitializer.java

+1-6
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,13 @@ public void initializeDefaultPreferences() {
5959
}));
6060

6161
preferenceStore.setDefault(Constants.PREF_MODULITH, true);
62-
6362
preferenceStore.setDefault(Constants.PREF_LIVE_INFORMATION_ALL_JVM_PROCESSES, false);
64-
6563
preferenceStore.setDefault(Constants.PREF_JPQL, true);
66-
6764
preferenceStore.setDefault(Constants.PREF_PROPS_COMPLETIONS_ELIDE_PREFIX, false);
68-
6965
preferenceStore.setDefault(Constants.PREF_CRON_INLAY_HINTS, true);
70-
7166
preferenceStore.setDefault(Constants.PREF_COMPLETION_JAVA_INJECT_BEAN, true);
72-
7367
preferenceStore.setDefault(Constants.PREF_BEANS_STRUCTURE_TREE, false);
68+
preferenceStore.setDefault(Constants.PREF_SYMBOLS_FROM_NEW_INDEX, false);
7469
}
7570

7671
}

headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/SymbolElement.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import org.eclipse.lsp4j.DocumentSymbol;
1414

15-
public interface SymbolElement {
15+
public interface SymbolElement extends SpringIndexElement {
1616

1717
public DocumentSymbol getDocumentSymbol();
1818

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java

+5
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ public boolean isBeanStructureTreeEnabled() {
219219
return Boolean.TRUE.equals(b);
220220
}
221221

222+
public boolean isSymbolsFromNewIndexEnabled() {
223+
Boolean b = settings.getBoolean("boot-java", "java", "symbols-from-new-index");
224+
return Boolean.TRUE.equals(b);
225+
}
226+
222227
public Settings getRawSettings() {
223228
return settings;
224229
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java

+54-6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.function.BiConsumer;
4141
import java.util.function.BiFunction;
4242
import java.util.function.Consumer;
43+
import java.util.function.Predicate;
4344
import java.util.stream.Collectors;
4445
import java.util.stream.Stream;
4546

@@ -86,6 +87,7 @@
8687
import org.springframework.ide.vscode.commons.protocol.spring.BeansParams;
8788
import org.springframework.ide.vscode.commons.protocol.spring.DocumentElement;
8889
import org.springframework.ide.vscode.commons.protocol.spring.MatchingBeansParams;
90+
import org.springframework.ide.vscode.commons.protocol.spring.ProjectElement;
8991
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndex;
9092
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
9193
import org.springframework.ide.vscode.commons.util.Futures;
@@ -103,7 +105,6 @@
103105
public class SpringSymbolIndex implements InitializingBean, SpringIndex {
104106

105107
private static final String QUERY_PARAM_LOCATION_PREFIX = "locationPrefix:";
106-
private static final String OUTLINE_SYMBOLS_FROM_INDEX_PROPERTY = "outlineSymbolsFromIndex";
107108

108109
@Autowired SimpleLanguageServer server;
109110
@Autowired BootJavaConfig config;
@@ -681,6 +682,23 @@ public CompletableFuture<Void> deleteDocuments(String[] deletedPathURIs) {
681682
}
682683

683684
public List<WorkspaceSymbol> getAllSymbols(String query) {
685+
long start = System.currentTimeMillis();
686+
687+
try {
688+
if (config.isSymbolsFromNewIndexEnabled()) {
689+
return getAllSymbolsFromMetamodelIndex(query);
690+
}
691+
else {
692+
return getAllSymbolsFromSymbolsIndex(query);
693+
}
694+
}
695+
finally {
696+
long end = System.currentTimeMillis();
697+
log.info("workspace symbols computation took " + (end - start) + "ms");
698+
}
699+
}
700+
701+
private List<WorkspaceSymbol> getAllSymbolsFromSymbolsIndex(String query) {
684702
if (query != null && query.length() > 0) {
685703
synchronized(this.symbols) {
686704
return searchMatchingSymbols(this.symbols, query);
@@ -692,6 +710,37 @@ public List<WorkspaceSymbol> getAllSymbols(String query) {
692710
}
693711
}
694712

713+
private List<WorkspaceSymbol> getAllSymbolsFromMetamodelIndex(String query) {
714+
Collection<ProjectElement> projects = springIndex.getProjects();
715+
716+
String locationPrefix = "";
717+
if (query.startsWith(QUERY_PARAM_LOCATION_PREFIX)) {
718+
719+
int separatorIndex = query.indexOf("?");
720+
if (separatorIndex > 0) {
721+
locationPrefix = query.substring(QUERY_PARAM_LOCATION_PREFIX.length(), separatorIndex);
722+
query = query.substring(separatorIndex + 1);
723+
}
724+
else {
725+
locationPrefix = query.substring(QUERY_PARAM_LOCATION_PREFIX.length());
726+
query = query.substring(QUERY_PARAM_LOCATION_PREFIX.length() + locationPrefix.length());
727+
}
728+
}
729+
730+
if (query.startsWith("*")) {
731+
query = query.substring(1);
732+
}
733+
734+
final String finalQuery = query;
735+
final String finalLocationPrefix = locationPrefix;
736+
737+
Predicate<DocumentElement> locationPredicate = (document) -> document.getDocURI().startsWith(finalLocationPrefix);
738+
Predicate<DocumentSymbol> symbolPredicate = query != null && query.length() > 0 ? (symbol) -> StringUtil.containsCharactersCaseInsensitive(symbol.getName(), finalQuery) : (symbol) -> true;
739+
740+
List<WorkspaceSymbol> workspaceSymbols = SpringIndexToSymbolsConverter.createWorkspaceSymbols(projects, locationPredicate, symbolPredicate);
741+
return workspaceSymbols;
742+
}
743+
695744
synchronized private CompletableFuture<IJavaProject> projectInitializedFuture(IJavaProject project) {
696745
if (project == null) {
697746
return CompletableFuture.completedFuture(null);
@@ -702,7 +751,7 @@ synchronized private CompletableFuture<IJavaProject> projectInitializedFuture(IJ
702751
}
703752

704753
public List<? extends WorkspaceSymbol> getSymbols(String docURI) {
705-
if (System.getProperty(OUTLINE_SYMBOLS_FROM_INDEX_PROPERTY) != null) {
754+
if (config.isBeanStructureTreeEnabled()) {
706755
return getWorkspaceSymbolsFromMetamodelIndex(docURI);
707756
}
708757
else {
@@ -711,8 +760,7 @@ public List<? extends WorkspaceSymbol> getSymbols(String docURI) {
711760
}
712761

713762
public List<? extends DocumentSymbol> getDocumentSymbols(String docURI) {
714-
if (System.getProperty(OUTLINE_SYMBOLS_FROM_INDEX_PROPERTY) != null
715-
|| config.isBeanStructureTreeEnabled()) {
763+
if (config.isBeanStructureTreeEnabled()) {
716764
return getDocumentSymbolsFromMetamodelIndex(docURI);
717765
}
718766
else {
@@ -1095,9 +1143,9 @@ private void removeSymbolsByDoc(IJavaProject project, String docURI) {
10951143
List<WorkspaceSymbol> oldSymbols = symbolsByDoc.remove(docURI);
10961144
if (oldSymbols != null) {
10971145

1098-
List<WorkspaceSymbol> copy = null;
1146+
Set<WorkspaceSymbol> copy = null;
10991147
synchronized(oldSymbols) {
1100-
copy = new ArrayList<>(oldSymbols);
1148+
copy = new HashSet<>(oldSymbols); // use HashSet here in order to speed up removal of symbols from global list
11011149
}
11021150

11031151
synchronized(this.symbols) {

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringIndexToSymbolsConverter.java

+40
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,16 @@
1111
package org.springframework.ide.vscode.boot.index;
1212

1313
import java.util.ArrayList;
14+
import java.util.Collection;
1415
import java.util.List;
16+
import java.util.function.Predicate;
1517

1618
import org.eclipse.lsp4j.DocumentSymbol;
19+
import org.eclipse.lsp4j.Location;
20+
import org.eclipse.lsp4j.WorkspaceSymbol;
21+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
22+
import org.springframework.ide.vscode.commons.protocol.spring.DocumentElement;
23+
import org.springframework.ide.vscode.commons.protocol.spring.ProjectElement;
1724
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
1825
import org.springframework.ide.vscode.commons.protocol.spring.SymbolElement;
1926

@@ -28,7 +35,19 @@ public static List<DocumentSymbol> createDocumentSymbols(List<SpringIndexElement
2835

2936
return result;
3037
}
38+
39+
public static List<WorkspaceSymbol> createWorkspaceSymbols(Collection<ProjectElement> projects,
40+
Predicate<DocumentElement> documentPredicate, Predicate<DocumentSymbol> symbolPredicate) {
3141

42+
return projects.stream()
43+
.flatMap(project -> project.getChildren().stream())
44+
.filter(node -> node instanceof DocumentElement)
45+
.map(node -> (DocumentElement) node)
46+
.filter(documentPredicate)
47+
.flatMap(document -> createWorkspaceSymbols(document, symbolPredicate).stream())
48+
.toList();
49+
}
50+
3251
private static List<DocumentSymbol> createSymbol(SpringIndexElement indexElement) {
3352

3453
List<DocumentSymbol> subTreeSymbols = new ArrayList<>();
@@ -58,5 +77,26 @@ private static List<DocumentSymbol> createSymbol(SpringIndexElement indexElement
5877
return subTreeSymbols;
5978
}
6079
}
80+
81+
private static List<WorkspaceSymbol> createWorkspaceSymbols(DocumentElement document, Predicate<DocumentSymbol> symbolPredicate) {
82+
return SpringMetamodelIndex.getNodesOfType(SymbolElement.class, List.of(document)).stream()
83+
.map(symbolElement -> symbolElement.getDocumentSymbol())
84+
.filter(symbolPredicate)
85+
.map(documentSymbol -> createWorkspaceSymbol(documentSymbol, document.getDocURI()))
86+
.toList();
87+
}
88+
89+
private static WorkspaceSymbol createWorkspaceSymbol(DocumentSymbol documentSymbol, String docURI) {
90+
WorkspaceSymbol workspaceSymbol = new WorkspaceSymbol();
91+
92+
workspaceSymbol.setName(documentSymbol.getName());
93+
workspaceSymbol.setKind(documentSymbol.getKind());
94+
workspaceSymbol.setTags(documentSymbol.getTags());
95+
96+
Location location = new Location(docURI, documentSymbol.getRange());
97+
workspaceSymbol.setLocation(Either.forLeft(location));
98+
99+
return workspaceSymbol;
100+
}
61101

62102
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.util.ArrayDeque;
1414
import java.util.ArrayList;
1515
import java.util.Collection;
16+
import java.util.Collections;
1617
import java.util.HashMap;
1718
import java.util.List;
1819
import java.util.Map;
@@ -58,6 +59,10 @@ public void removeElements(String projectName, String docURI) {
5859
public void removeProject(String projectName) {
5960
projectRootElements.remove(projectName);
6061
}
62+
63+
public Collection<ProjectElement> getProjects() {
64+
return Collections.unmodifiableCollection(this.projectRootElements.values());
65+
}
6166

6267
public DocumentElement getDocument(String docURI) {
6368
List<SpringIndexElement> rootNodes = new ArrayList<SpringIndexElement>(this.projectRootElements.values());

vscode-extensions/vscode-spring-boot/package.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,12 @@
366366
"boot-java.java.beans-structure-tree": {
367367
"type": "boolean",
368368
"default": false,
369-
"description": "Beans structure tree in the outline view"
369+
"description": "Beans structure tree in the outline view (experimental)"
370+
},
371+
"boot-java.java.symbols-from-new-index": {
372+
"type": "boolean",
373+
"default": false,
374+
"description": "Generate workspace symbols from index (experimental)"
370375
},
371376
"boot-java.remote-apps": {
372377
"type": "array",

0 commit comments

Comments
 (0)