Skip to content

Commit f92a7a5

Browse files
committed
GH-1431: compute document symbols directly instead of going through workspace symbols
1 parent eb99148 commit f92a7a5

File tree

11 files changed

+133
-92
lines changed

11 files changed

+133
-92
lines changed

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/composable/CompositeLanguageServerComponents.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018, 2024 Pivotal, Inc.
2+
* Copyright (c) 2018, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -27,14 +27,14 @@
2727
import org.eclipse.lsp4j.CodeLens;
2828
import org.eclipse.lsp4j.CodeLensParams;
2929
import org.eclipse.lsp4j.Command;
30+
import org.eclipse.lsp4j.DocumentSymbol;
3031
import org.eclipse.lsp4j.DocumentSymbolParams;
3132
import org.eclipse.lsp4j.Hover;
3233
import org.eclipse.lsp4j.HoverParams;
3334
import org.eclipse.lsp4j.InlayHint;
3435
import org.eclipse.lsp4j.Range;
3536
import org.eclipse.lsp4j.SemanticTokensLegend;
3637
import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
37-
import org.eclipse.lsp4j.WorkspaceSymbol;
3838
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
3939
import org.eclipse.lsp4j.jsonrpc.messages.Either;
4040
import org.springframework.context.ApplicationContext;
@@ -192,7 +192,7 @@ public List<InlayHint> handle(TextDocument doc, Range r, CancelChecker token) {
192192
this.docSymbolHandler = new DocumentSymbolHandler() {
193193

194194
@Override
195-
public List<? extends WorkspaceSymbol> handle(DocumentSymbolParams params) {
195+
public List<? extends DocumentSymbol> handle(DocumentSymbolParams params) {
196196
TextDocument doc = getDoc(appContext, params.getTextDocument().getUri());
197197
LanguageId language = doc.getLanguageId();
198198
List<LanguageServerComponents> subComponents = componentsByLanguageId.get(language);

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/DocumentSymbolHandler.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017 Pivotal, Inc.
2+
* Copyright (c) 2017, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -12,8 +12,8 @@
1212

1313
import java.util.List;
1414

15+
import org.eclipse.lsp4j.DocumentSymbol;
1516
import org.eclipse.lsp4j.DocumentSymbolParams;
16-
import org.eclipse.lsp4j.WorkspaceSymbol;
1717

1818
import com.google.common.collect.ImmutableList;
1919

@@ -22,6 +22,6 @@ public interface DocumentSymbolHandler {
2222

2323
DocumentSymbolHandler NO_SYMBOLS = (params) -> ImmutableList.of();
2424

25-
List<? extends WorkspaceSymbol> handle(DocumentSymbolParams params);
25+
List<? extends DocumentSymbol> handle(DocumentSymbolParams params);
2626

2727
}

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/HierarchicalDocumentSymbolHandler.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2016, 2024 VMware Inc.
2+
* Copyright (c) 2016, 2025 VMware Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -74,7 +74,6 @@
7474
import org.eclipse.lsp4j.TextEdit;
7575
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
7676
import org.eclipse.lsp4j.WorkspaceEdit;
77-
import org.eclipse.lsp4j.WorkspaceSymbol;
7877
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
7978
import org.eclipse.lsp4j.jsonrpc.CompletableFutures;
8079
import org.eclipse.lsp4j.jsonrpc.messages.Either;
@@ -433,21 +432,12 @@ public CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> docume
433432
//
434433
// cancelToken.checkCanceled();
435434
//
436-
if (server.hasHierarchicalDocumentSymbolSupport() && h instanceof HierarchicalDocumentSymbolHandler) {
437-
List<? extends DocumentSymbol> r = ((HierarchicalDocumentSymbolHandler)h).handleHierarchic(params);
435+
List<? extends DocumentSymbol> r = h.handle(params);
438436
//handle it when symbolHandler is sloppy and returns null instead of empty list.
439437
return r == null
440438
? ImmutableList.of()
441-
: r.stream().map(symbolInfo -> Either.<SymbolInformation, DocumentSymbol>forRight(symbolInfo))
442-
.collect(Collectors.toList());
443-
} else {
444-
List<? extends WorkspaceSymbol> r = h.handle(params);
445-
//handle it when symbolHandler is sloppy and returns null instead of empty list.
446-
return r == null
447-
? ImmutableList.of()
448-
: r.stream().map(symbolInfo -> Either.<SymbolInformation, DocumentSymbol>forLeft(new SymbolInformation(symbolInfo.getName(), symbolInfo.getKind(), symbolInfo.getLocation().getLeft(), symbolInfo.getContainerName())))
449-
.collect(Collectors.toList());
450-
}
439+
: r.stream().map(symbol -> Either.<SymbolInformation, DocumentSymbol>forRight(symbol))
440+
.collect(Collectors.toList());
451441
});
452442
}
453443
else {

headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/TypeBasedYamlHierarchicalSymbolHandler.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2019 Pivotal, Inc.
2+
* Copyright (c) 2019, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -19,10 +19,9 @@
1919
import org.eclipse.lsp4j.DocumentSymbol;
2020
import org.eclipse.lsp4j.DocumentSymbolParams;
2121
import org.eclipse.lsp4j.SymbolKind;
22-
import org.eclipse.lsp4j.WorkspaceSymbol;
2322
import org.slf4j.Logger;
2423
import org.slf4j.LoggerFactory;
25-
import org.springframework.ide.vscode.commons.languageserver.util.HierarchicalDocumentSymbolHandler;
24+
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
2625
import org.springframework.ide.vscode.commons.util.Assert;
2726
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
2827
import org.springframework.ide.vscode.commons.util.text.IDocument;
@@ -40,7 +39,7 @@
4039
import com.google.common.collect.ImmutableMap;
4140
import com.google.common.collect.ImmutableMap.Builder;
4241

43-
public class TypeBasedYamlHierarchicalSymbolHandler implements HierarchicalDocumentSymbolHandler, ITypeCollector {
42+
public class TypeBasedYamlHierarchicalSymbolHandler implements DocumentSymbolHandler, ITypeCollector {
4443

4544
private static final Logger log = LoggerFactory.getLogger(TypeBasedYamlHierarchicalSymbolHandler.class);
4645

@@ -153,12 +152,7 @@ public TypeBasedYamlHierarchicalSymbolHandler(TypeBasedYamlSymbolHandler baseHan
153152
}
154153

155154
@Override
156-
public List<? extends WorkspaceSymbol> handle(DocumentSymbolParams params) {
157-
return baseHandler.handle(params);
158-
}
159-
160-
@Override
161-
public List<? extends DocumentSymbol> handleHierarchic(DocumentSymbolParams params) {
155+
public List<? extends DocumentSymbol> handle(DocumentSymbolParams params) {
162156
return outlineByUri.get(params.getTextDocument().getUri());
163157
}
164158

headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/reconcile/TypeBasedYamlSymbolHandler.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017, 2021 Pivotal, Inc.
2+
* Copyright (c) 2017, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -15,11 +15,10 @@
1515
import java.util.Map.Entry;
1616
import java.util.Set;
1717

18+
import org.eclipse.lsp4j.DocumentSymbol;
1819
import org.eclipse.lsp4j.DocumentSymbolParams;
19-
import org.eclipse.lsp4j.Location;
20+
import org.eclipse.lsp4j.Range;
2021
import org.eclipse.lsp4j.SymbolKind;
21-
import org.eclipse.lsp4j.WorkspaceSymbol;
22-
import org.eclipse.lsp4j.jsonrpc.messages.Either;
2322
import org.slf4j.Logger;
2423
import org.slf4j.LoggerFactory;
2524
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
@@ -63,8 +62,8 @@ public TypeBasedYamlSymbolHandler(SimpleTextDocumentService documents, ASTTypeCa
6362
}
6463

6564
@Override
66-
public List<? extends WorkspaceSymbol> handle(DocumentSymbolParams params) {
67-
Builder<WorkspaceSymbol> builder = ImmutableList.builder();
65+
public List<? extends DocumentSymbol> handle(DocumentSymbolParams params) {
66+
Builder<DocumentSymbol> builder = ImmutableList.builder();
6867

6968
TextDocument doc = documents.getLatestSnapshot(params.getTextDocument().getUri());
7069
if (doc != null) {
@@ -81,14 +80,17 @@ public List<? extends WorkspaceSymbol> handle(DocumentSymbolParams params) {
8180
return builder.build();
8281
}
8382

84-
protected WorkspaceSymbol createSymbol(TextDocument doc, Node node, YType type) throws BadLocationException {
83+
protected DocumentSymbol createSymbol(TextDocument doc, Node node, YType type) throws BadLocationException {
8584
DocumentRegion region = NodeUtil.region(doc, node);
86-
Location location = new Location(doc.getUri(), doc.toRange(region.getStart(), region.getLength()));
87-
WorkspaceSymbol symbol = new WorkspaceSymbol();
85+
86+
Range range = doc.toRange(region.getStart(), region.getLength());
87+
88+
DocumentSymbol symbol = new DocumentSymbol();
8889
symbol.setName(region.toString());
8990
symbol.setKind(symbolKind(type));
90-
symbol.setLocation(Either.forLeft(location));
91-
symbol.setContainerName(containerName(type));
91+
symbol.setRange(range);
92+
symbol.setSelectionRange(range);
93+
9294
return symbol;
9395
}
9496

headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerBootApp.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018, 2019 Pivotal, Inc.
2+
* Copyright (c) 2018, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -14,7 +14,7 @@
1414
import org.springframework.boot.autoconfigure.SpringBootApplication;
1515
import org.springframework.context.annotation.Bean;
1616
import org.springframework.ide.vscode.commons.languageserver.LanguageServerRunner;
17-
import org.springframework.ide.vscode.commons.languageserver.util.HierarchicalDocumentSymbolHandler;
17+
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
1818
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
1919
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
2020
import org.springframework.ide.vscode.commons.util.LogRedirect;
@@ -48,7 +48,7 @@ public static void main(String[] args) throws Exception {
4848
return new ASTTypeCache();
4949
}
5050

51-
@Bean HierarchicalDocumentSymbolHandler documentSymbolHandler(SimpleTextDocumentService documents, ASTTypeCache astTypeCache, PipelineYmlSchema schema) {
51+
@Bean DocumentSymbolHandler documentSymbolHandler(SimpleTextDocumentService documents, ASTTypeCache astTypeCache, PipelineYmlSchema schema) {
5252
TypeBasedYamlSymbolHandler baseHandler = new TypeBasedYamlSymbolHandler(documents, astTypeCache, schema.getDefinitionTypes());
5353
return new TypeBasedYamlHierarchicalSymbolHandler(baseHandler, schema.getHierarchicalDefinitionTypes());
5454
}

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

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
import java.net.URISyntaxException;
1717
import java.nio.file.Files;
1818
import java.nio.file.Path;
19+
import java.util.ArrayDeque;
1920
import java.util.ArrayList;
2021
import java.util.Arrays;
2122
import java.util.Collection;
2223
import java.util.Collections;
24+
import java.util.Deque;
2325
import java.util.HashMap;
2426
import java.util.HashSet;
2527
import java.util.Iterator;
@@ -42,6 +44,7 @@
4244
import java.util.stream.Stream;
4345

4446
import org.eclipse.lsp4j.Diagnostic;
47+
import org.eclipse.lsp4j.DocumentSymbol;
4548
import org.eclipse.lsp4j.Location;
4649
import org.eclipse.lsp4j.TextDocumentIdentifier;
4750
import org.eclipse.lsp4j.WorkspaceSymbol;
@@ -51,6 +54,7 @@
5154
import org.slf4j.LoggerFactory;
5255
import org.springframework.beans.factory.InitializingBean;
5356
import org.springframework.beans.factory.annotation.Autowired;
57+
import org.springframework.ide.vscode.boot.index.SpringIndexToSymbolsConverter;
5458
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
5559
import org.springframework.ide.vscode.boot.index.cache.IndexCache;
5660
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
@@ -80,6 +84,7 @@
8084
import org.springframework.ide.vscode.commons.languageserver.util.SimpleWorkspaceService;
8185
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
8286
import org.springframework.ide.vscode.commons.protocol.spring.BeansParams;
87+
import org.springframework.ide.vscode.commons.protocol.spring.DocumentElement;
8388
import org.springframework.ide.vscode.commons.protocol.spring.MatchingBeansParams;
8489
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndex;
8590
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
@@ -732,7 +737,99 @@ public List<? extends WorkspaceSymbol> getSymbols(String docURI) {
732737
return Collections.emptyList();
733738
}
734739
}
740+
741+
public List<? extends DocumentSymbol> getDocumentSymbols(String docURI) {
742+
List<DocumentSymbol> result = new ArrayList<>();
743+
744+
List<? extends WorkspaceSymbol> symbols = getSymbols(docURI);
745+
for (WorkspaceSymbol symbol : symbols) {
746+
DocumentSymbol docSymbol = new DocumentSymbol();
747+
docSymbol.setName(symbol.getName());
748+
docSymbol.setKind(symbol.getKind());
749+
docSymbol.setRange(symbol.getLocation().getLeft().getRange());
750+
docSymbol.setSelectionRange(symbol.getLocation().getLeft().getRange());
751+
docSymbol.setTags(symbol.getTags());
752+
753+
result.add(docSymbol);
754+
}
755+
756+
return result;
757+
}
758+
759+
/*
760+
public List<? extends WorkspaceSymbol> getSymbols(String docURI) {
761+
List<WorkspaceSymbol> result = new ArrayList<>();
762+
763+
Deque<DocumentSymbol> remainingSymbols = new ArrayDeque<>();
764+
List<? extends DocumentSymbol> documentSymbols = getDocumentSymbols(docURI);
765+
766+
remainingSymbols.addAll(documentSymbols);
767+
768+
while (!remainingSymbols.isEmpty()) {
769+
DocumentSymbol documentSymbol = remainingSymbols.poll();
770+
771+
WorkspaceSymbol workspaceSymbol = new WorkspaceSymbol();
772+
workspaceSymbol.setName(documentSymbol.getName());
773+
workspaceSymbol.setKind(documentSymbol.getKind());
774+
workspaceSymbol.setTags(documentSymbol.getTags());
775+
776+
Location location = new Location(docURI, documentSymbol.getRange());
777+
workspaceSymbol.setLocation(Either.forLeft(location));
778+
779+
result.add(workspaceSymbol);
780+
781+
if (documentSymbol.getChildren() != null) {
782+
remainingSymbols.addAll(documentSymbol.getChildren());
783+
}
784+
}
785+
786+
return result;
787+
}
788+
789+
public List<? extends DocumentSymbol> getDocumentSymbols(String docURI) {
790+
try {
791+
TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docURI);
792+
URI uri = URI.create(docURI);
793+
794+
CompletableFuture<IJavaProject> projectInitialized = futureProjectFinder.findFuture(uri).thenCompose(project -> projectInitializedFuture(project));
795+
IJavaProject project = projectInitialized.get(15, TimeUnit.SECONDS);
735796
797+
ImmutableList.Builder<DocumentSymbol> builder = ImmutableList.builder();
798+
799+
if (project != null && doc != null) {
800+
801+
// Collect symbols from the opened document
802+
synchronized(this) {
803+
for (SpringIndexer indexer : this.indexers) {
804+
if (indexer.isInterestedIn(docURI)) {
805+
try {
806+
List<DocumentSymbol> adhocDocumentSymbols = indexer.computeDocumentSymbols(project, docURI, doc.get());
807+
builder.addAll(adhocDocumentSymbols);
808+
} catch (Exception e) {
809+
log.error("{}", e);
810+
}
811+
}
812+
}
813+
}
814+
815+
} else {
816+
817+
// Take symbols from the index if there is no opened document.
818+
DocumentElement document = springIndex.getDocument(docURI);
819+
if (document != null) {
820+
List<SpringIndexElement> children = document.getChildren();
821+
builder.addAll(SpringIndexToSymbolsConverter.createDocumentSymbols(children));
822+
}
823+
824+
}
825+
return builder.build();
826+
} catch (Exception e) {
827+
log.warn("", e);
828+
return Collections.emptyList();
829+
}
830+
}
831+
*/
832+
736833
@Override
737834
public CompletableFuture<List<Bean>> beans(BeansParams params) {
738835
String projectName = params.getProjectName();

0 commit comments

Comments
 (0)