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

@@ -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());