option added to generate workspace symbols from spring index on demand

This commit is contained in:
Martin Lippert
2025-04-08 09:58:18 +02:00
parent 4e0ec923dd
commit e7e2015ac4
10 changed files with 119 additions and 15 deletions

View File

@@ -54,4 +54,6 @@ public class Constants {
public static final String PREF_BEANS_STRUCTURE_TREE = "boot-java.java.beans-structure-tree";
public static final String PREF_SYMBOLS_FROM_NEW_INDEX = "boot-java.java.symbols-from-new-index";
}

View File

@@ -201,6 +201,7 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi
javaCompletionSettings.put("inject-bean", preferenceStore.getBoolean(Constants.PREF_COMPLETION_JAVA_INJECT_BEAN));
javaSettings.put("beans-structure-tree", preferenceStore.getBoolean(Constants.PREF_BEANS_STRUCTURE_TREE));
javaSettings.put("symbols-from-new-index", preferenceStore.getBoolean(Constants.PREF_SYMBOLS_FROM_NEW_INDEX));
javaSettings.put("completions", javaCompletionSettings);
javaSettings.put("reconcilers", preferenceStore.getBoolean(Constants.PREF_JAVA_RECONCILE));

View File

@@ -57,7 +57,10 @@ public class BootJavaPreferencesPage extends FieldEditorPreferencePage implement
addField(new BooleanFieldEditor(Constants.PREF_COMPLETION_JAVA_INJECT_BEAN, "Inject Bean completion proposals in Java editor", fieldEditorParent));
// Experimental Beans tree
addField(new BooleanFieldEditor(Constants.PREF_BEANS_STRUCTURE_TREE, "Beans structure tree in the outline view", fieldEditorParent));
addField(new BooleanFieldEditor(Constants.PREF_BEANS_STRUCTURE_TREE, "Beans structure tree in the outline view (experimental)", fieldEditorParent));
// Experimental symbols from new index
addField(new BooleanFieldEditor(Constants.PREF_SYMBOLS_FROM_NEW_INDEX, "Generate workspace symbols from index (experimental)", fieldEditorParent));
Composite c = new Composite(fieldEditorParent, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).applyTo(c);

View File

@@ -59,18 +59,13 @@ public class PrefsInitializer extends AbstractPreferenceInitializer {
}));
preferenceStore.setDefault(Constants.PREF_MODULITH, true);
preferenceStore.setDefault(Constants.PREF_LIVE_INFORMATION_ALL_JVM_PROCESSES, false);
preferenceStore.setDefault(Constants.PREF_JPQL, true);
preferenceStore.setDefault(Constants.PREF_PROPS_COMPLETIONS_ELIDE_PREFIX, false);
preferenceStore.setDefault(Constants.PREF_CRON_INLAY_HINTS, true);
preferenceStore.setDefault(Constants.PREF_COMPLETION_JAVA_INJECT_BEAN, true);
preferenceStore.setDefault(Constants.PREF_BEANS_STRUCTURE_TREE, false);
preferenceStore.setDefault(Constants.PREF_SYMBOLS_FROM_NEW_INDEX, false);
}
}

View File

@@ -12,7 +12,7 @@ package org.springframework.ide.vscode.commons.protocol.spring;
import org.eclipse.lsp4j.DocumentSymbol;
public interface SymbolElement {
public interface SymbolElement extends SpringIndexElement {
public DocumentSymbol getDocumentSymbol();

View File

@@ -219,6 +219,11 @@ public class BootJavaConfig implements InitializingBean {
return Boolean.TRUE.equals(b);
}
public boolean isSymbolsFromNewIndexEnabled() {
Boolean b = settings.getBoolean("boot-java", "java", "symbols-from-new-index");
return Boolean.TRUE.equals(b);
}
public Settings getRawSettings() {
return settings;
}

View File

@@ -40,6 +40,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -86,6 +87,7 @@ import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.BeansParams;
import org.springframework.ide.vscode.commons.protocol.spring.DocumentElement;
import org.springframework.ide.vscode.commons.protocol.spring.MatchingBeansParams;
import org.springframework.ide.vscode.commons.protocol.spring.ProjectElement;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndex;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
import org.springframework.ide.vscode.commons.util.Futures;
@@ -103,7 +105,6 @@ import com.google.common.collect.ImmutableList;
public class SpringSymbolIndex implements InitializingBean, SpringIndex {
private static final String QUERY_PARAM_LOCATION_PREFIX = "locationPrefix:";
private static final String OUTLINE_SYMBOLS_FROM_INDEX_PROPERTY = "outlineSymbolsFromIndex";
@Autowired SimpleLanguageServer server;
@Autowired BootJavaConfig config;
@@ -681,6 +682,23 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
}
public List<WorkspaceSymbol> getAllSymbols(String query) {
long start = System.currentTimeMillis();
try {
if (config.isSymbolsFromNewIndexEnabled()) {
return getAllSymbolsFromMetamodelIndex(query);
}
else {
return getAllSymbolsFromSymbolsIndex(query);
}
}
finally {
long end = System.currentTimeMillis();
log.info("workspace symbols computation took " + (end - start) + "ms");
}
}
private List<WorkspaceSymbol> getAllSymbolsFromSymbolsIndex(String query) {
if (query != null && query.length() > 0) {
synchronized(this.symbols) {
return searchMatchingSymbols(this.symbols, query);
@@ -692,6 +710,37 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
}
}
private List<WorkspaceSymbol> getAllSymbolsFromMetamodelIndex(String query) {
Collection<ProjectElement> projects = springIndex.getProjects();
String locationPrefix = "";
if (query.startsWith(QUERY_PARAM_LOCATION_PREFIX)) {
int separatorIndex = query.indexOf("?");
if (separatorIndex > 0) {
locationPrefix = query.substring(QUERY_PARAM_LOCATION_PREFIX.length(), separatorIndex);
query = query.substring(separatorIndex + 1);
}
else {
locationPrefix = query.substring(QUERY_PARAM_LOCATION_PREFIX.length());
query = query.substring(QUERY_PARAM_LOCATION_PREFIX.length() + locationPrefix.length());
}
}
if (query.startsWith("*")) {
query = query.substring(1);
}
final String finalQuery = query;
final String finalLocationPrefix = locationPrefix;
Predicate<DocumentElement> locationPredicate = (document) -> document.getDocURI().startsWith(finalLocationPrefix);
Predicate<DocumentSymbol> symbolPredicate = query != null && query.length() > 0 ? (symbol) -> StringUtil.containsCharactersCaseInsensitive(symbol.getName(), finalQuery) : (symbol) -> true;
List<WorkspaceSymbol> workspaceSymbols = SpringIndexToSymbolsConverter.createWorkspaceSymbols(projects, locationPredicate, symbolPredicate);
return workspaceSymbols;
}
synchronized private CompletableFuture<IJavaProject> projectInitializedFuture(IJavaProject project) {
if (project == null) {
return CompletableFuture.completedFuture(null);
@@ -702,7 +751,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
}
public List<? extends WorkspaceSymbol> getSymbols(String docURI) {
if (System.getProperty(OUTLINE_SYMBOLS_FROM_INDEX_PROPERTY) != null) {
if (config.isBeanStructureTreeEnabled()) {
return getWorkspaceSymbolsFromMetamodelIndex(docURI);
}
else {
@@ -711,8 +760,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
}
public List<? extends DocumentSymbol> getDocumentSymbols(String docURI) {
if (System.getProperty(OUTLINE_SYMBOLS_FROM_INDEX_PROPERTY) != null
|| config.isBeanStructureTreeEnabled()) {
if (config.isBeanStructureTreeEnabled()) {
return getDocumentSymbolsFromMetamodelIndex(docURI);
}
else {
@@ -1095,9 +1143,9 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
List<WorkspaceSymbol> oldSymbols = symbolsByDoc.remove(docURI);
if (oldSymbols != null) {
List<WorkspaceSymbol> copy = null;
Set<WorkspaceSymbol> copy = null;
synchronized(oldSymbols) {
copy = new ArrayList<>(oldSymbols);
copy = new HashSet<>(oldSymbols); // use HashSet here in order to speed up removal of symbols from global list
}
synchronized(this.symbols) {

View File

@@ -11,9 +11,16 @@
package org.springframework.ide.vscode.boot.index;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import org.eclipse.lsp4j.DocumentSymbol;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.WorkspaceSymbol;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.springframework.ide.vscode.commons.protocol.spring.DocumentElement;
import org.springframework.ide.vscode.commons.protocol.spring.ProjectElement;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
import org.springframework.ide.vscode.commons.protocol.spring.SymbolElement;
@@ -28,7 +35,19 @@ public class SpringIndexToSymbolsConverter {
return result;
}
public static List<WorkspaceSymbol> createWorkspaceSymbols(Collection<ProjectElement> projects,
Predicate<DocumentElement> documentPredicate, Predicate<DocumentSymbol> symbolPredicate) {
return projects.stream()
.flatMap(project -> project.getChildren().stream())
.filter(node -> node instanceof DocumentElement)
.map(node -> (DocumentElement) node)
.filter(documentPredicate)
.flatMap(document -> createWorkspaceSymbols(document, symbolPredicate).stream())
.toList();
}
private static List<DocumentSymbol> createSymbol(SpringIndexElement indexElement) {
List<DocumentSymbol> subTreeSymbols = new ArrayList<>();
@@ -58,5 +77,26 @@ public class SpringIndexToSymbolsConverter {
return subTreeSymbols;
}
}
private static List<WorkspaceSymbol> createWorkspaceSymbols(DocumentElement document, Predicate<DocumentSymbol> symbolPredicate) {
return SpringMetamodelIndex.getNodesOfType(SymbolElement.class, List.of(document)).stream()
.map(symbolElement -> symbolElement.getDocumentSymbol())
.filter(symbolPredicate)
.map(documentSymbol -> createWorkspaceSymbol(documentSymbol, document.getDocURI()))
.toList();
}
private static WorkspaceSymbol createWorkspaceSymbol(DocumentSymbol documentSymbol, String docURI) {
WorkspaceSymbol workspaceSymbol = new WorkspaceSymbol();
workspaceSymbol.setName(documentSymbol.getName());
workspaceSymbol.setKind(documentSymbol.getKind());
workspaceSymbol.setTags(documentSymbol.getTags());
Location location = new Location(docURI, documentSymbol.getRange());
workspaceSymbol.setLocation(Either.forLeft(location));
return workspaceSymbol;
}
}

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.index;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -58,6 +59,10 @@ public class SpringMetamodelIndex {
public void removeProject(String projectName) {
projectRootElements.remove(projectName);
}
public Collection<ProjectElement> getProjects() {
return Collections.unmodifiableCollection(this.projectRootElements.values());
}
public DocumentElement getDocument(String docURI) {
List<SpringIndexElement> rootNodes = new ArrayList<SpringIndexElement>(this.projectRootElements.values());

View File

@@ -366,7 +366,12 @@
"boot-java.java.beans-structure-tree": {
"type": "boolean",
"default": false,
"description": "Beans structure tree in the outline view"
"description": "Beans structure tree in the outline view (experimental)"
},
"boot-java.java.symbols-from-new-index": {
"type": "boolean",
"default": false,
"description": "Generate workspace symbols from index (experimental)"
},
"boot-java.remote-apps": {
"type": "array",