PT 173744629 - Fix for file scope for symbols view
This commit is contained in:
@@ -22,7 +22,10 @@ Require-Bundle: org.eclipse.ui,
|
||||
org.reactivestreams.reactive-streams;bundle-version="1.0.0",
|
||||
org.springframework.ide.eclipse.boot.dash,
|
||||
org.springsource.ide.eclipse.commons.frameworks.core,
|
||||
org.springframework.ide.eclipse.boot
|
||||
org.springframework.ide.eclipse.boot,
|
||||
org.eclipse.ui.workbench,
|
||||
org.eclipse.ui.ide,
|
||||
org.eclipse.ui.editors
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-Activator: org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin
|
||||
Bundle-ActivationPolicy: lazy
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.lsp4e.LSPEclipseUtils;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor;
|
||||
@@ -25,7 +24,9 @@ import org.eclipse.lsp4j.DocumentSymbolParams;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.eclipse.lsp4j.services.LanguageServer;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.SelectionTracker.DocumentData;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -40,18 +41,20 @@ public class InFileSymbolsProvider implements SymbolsProvider {
|
||||
|
||||
private Supplier<LSPDocumentInfo> info;
|
||||
|
||||
public InFileSymbolsProvider(Supplier<LSPDocumentInfo> target) {
|
||||
public InFileSymbolsProvider(Supplier<LSPDocumentInfo> info) {
|
||||
super();
|
||||
this.info = target;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Either<SymbolInformation, DocumentSymbol>> fetchFor(String query) throws Exception {
|
||||
LSPDocumentInfo info = this.info.get();
|
||||
if (info!=null) {
|
||||
CompletableFuture<LanguageServer> server = getServer();
|
||||
String uri = getUri();
|
||||
if (server != null && uri != null) {
|
||||
DocumentSymbolParams params = new DocumentSymbolParams(
|
||||
new TextDocumentIdentifier(info.getFileUri().toString()));
|
||||
CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> symbolsFuture = info.getLanguageClient()
|
||||
new TextDocumentIdentifier(uri));
|
||||
CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> symbolsFuture = server
|
||||
.get()
|
||||
.getTextDocumentService().documentSymbol(params);
|
||||
List<Either<SymbolInformation, DocumentSymbol>> symbols = symbolsFuture.get();
|
||||
return symbols == null ? ImmutableList.of() : ImmutableList.copyOf(symbols);
|
||||
@@ -59,21 +62,39 @@ public class InFileSymbolsProvider implements SymbolsProvider {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
public static SymbolsProvider createFor(LiveExpression<IResource> rsrc) {
|
||||
LiveExpression<LSPDocumentInfo> target = rsrc.apply(r -> {
|
||||
// Get the existing document rather than request a document that may result
|
||||
// in a connection to the associated file buffer. The reason for this is
|
||||
// described in https://www.pivotaltracker.com/story/show/173267278
|
||||
IDocument document = LSPEclipseUtils.getExistingDocument(r);
|
||||
return getLSPDocumentInfo(document);
|
||||
});
|
||||
return new InFileSymbolsProvider(target::getValue);
|
||||
private String getUri() {
|
||||
if (this.info != null) {
|
||||
LSPDocumentInfo info = this.info.get();
|
||||
if (info != null) {
|
||||
return info.getFileUri().toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CompletableFuture<LanguageServer> getServer() throws Exception {
|
||||
if (this.info != null && this.info.get() != null) {
|
||||
return this.info.get().getInitializedLanguageClient();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static SymbolsProvider createFor(LiveExpression<DocumentData> documentData) {
|
||||
Supplier<LSPDocumentInfo> inf = () -> {
|
||||
DocumentData data = documentData.getValue();
|
||||
if (data != null) {
|
||||
IDocument document = data.getDocument();
|
||||
return getLSPDocumentInfo(document);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
return new InFileSymbolsProvider(inf);
|
||||
}
|
||||
|
||||
public static SymbolsProvider createFor(ITextEditor textEditor) {
|
||||
IDocument document = LSPEclipseUtils.getDocument(textEditor);
|
||||
LSPDocumentInfo info = getLSPDocumentInfo(document);
|
||||
if (info!=null) {
|
||||
if (info != null) {
|
||||
return new InFileSymbolsProvider(() -> info);
|
||||
}
|
||||
return null;
|
||||
@@ -100,10 +121,12 @@ public class InFileSymbolsProvider implements SymbolsProvider {
|
||||
|
||||
@Override
|
||||
public boolean fromFile(SymbolInformation symbol) {
|
||||
LSPDocumentInfo info = this.info.get();
|
||||
if (info!=null && symbol != null && symbol.getLocation() != null) {
|
||||
if (symbol != null && symbol.getLocation() != null) {
|
||||
String symbolUri = symbol.getLocation().getUri();
|
||||
return info.getFileUri().toString().equals(symbolUri);
|
||||
String uri = getUri();
|
||||
if (uri != null) {
|
||||
return uri.toString().equals(symbolUri);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -13,27 +13,33 @@ package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.ITextSelection;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor;
|
||||
import org.eclipse.ui.IEditorInput;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IEditorReference;
|
||||
import org.eclipse.ui.IFileEditorInput;
|
||||
import org.eclipse.ui.ISelectionListener;
|
||||
import org.eclipse.ui.ISelectionService;
|
||||
import org.eclipse.ui.IViewPart;
|
||||
import org.eclipse.ui.IViewReference;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.part.FileEditorInput;
|
||||
import org.eclipse.ui.texteditor.DocumentProviderRegistry;
|
||||
import org.eclipse.ui.texteditor.IDocumentProvider;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.AbstractDisposable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.Log;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.OldValueDisposer;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class SelectionTracker extends AbstractDisposable {
|
||||
|
||||
private static Map<IWorkbenchWindow, SelectionTracker> INSTANCES = new HashMap<>();
|
||||
@@ -51,9 +57,69 @@ public class SelectionTracker extends AbstractDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
private final LiveVariable<IResource> currentResource = new LiveVariable<>();
|
||||
public final LiveExpression<IProject> currentProject = currentResource.apply(r -> r==null ? null : r.getProject());
|
||||
// In order for the symbols view to correctly fetching information for a selection, it needs to find an active language
|
||||
// server for the given selection via LSP4E API (see the symbols view model), and document is required to find that active language server
|
||||
// Typically this document will be available if an editor is open.
|
||||
// However, symbols view also supports the case of showing information on a selection that does not have an open editor.
|
||||
// In this case, a document needs to be available for that selection, which can be accomplished my performing part of the behaviour
|
||||
// that would occur when an actual editor opens: namely connecting to that document via a document provider. This is what the document
|
||||
// data does: it simulates "opening" an editor when there is a selection,and "closing" an editor for an old selection when
|
||||
// there is a selection change
|
||||
static class DocumentData implements Disposable {
|
||||
|
||||
public final IFileEditorInput input;
|
||||
private final IDocumentProvider documentProvider;
|
||||
|
||||
public DocumentData(IFile file) {
|
||||
super();
|
||||
this.input = new FileEditorInput(file);
|
||||
this.documentProvider = DocumentProviderRegistry.getDefault().getDocumentProvider(input);
|
||||
if (this.documentProvider != null) {
|
||||
try {
|
||||
this.documentProvider.connect(input);
|
||||
IDocument document = this.documentProvider.getDocument(input);
|
||||
// This step appears to be necessary to avoid having the current language server shutdown when disconnecting
|
||||
// a document (see dispose()) and a new one start up again every time a user changes selection and no editor is open
|
||||
LanguageServiceAccessor.getLanguageServers(document, capabilities -> capabilities.getDocumentSymbolProvider()).get();
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (input != null && documentProvider != null) {
|
||||
documentProvider.disconnect(input);
|
||||
}
|
||||
}
|
||||
|
||||
public IDocument getDocument() {
|
||||
return this.documentProvider != null ? this.documentProvider.getDocument(input) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DocumentData [file=" + input.getFile() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final LiveVariable<DocumentData> documentData = new OldValueDisposer<DocumentData>(this).getVar();
|
||||
private final LiveVariable<IResource> currentResource = new LiveVariable<>();
|
||||
{
|
||||
currentResource.onChange(this, (e, v) -> {
|
||||
IResource value = currentResource.getValue();
|
||||
if (value instanceof IFile) {
|
||||
documentData.setValue(new DocumentData((IFile) value));
|
||||
} else {
|
||||
documentData.setValue(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final LiveExpression<IProject> currentProject = currentResource.apply(r -> r==null ? null : r.getProject());
|
||||
|
||||
private SelectionTracker(IWorkbenchWindow wbw) {
|
||||
ISelectionService selectionService = wbw.getSelectionService();
|
||||
ISelectionListener selectionListener = new ISelectionListener() {
|
||||
@@ -110,4 +176,8 @@ public class SelectionTracker extends AbstractDisposable {
|
||||
public LiveExpression<IResource> currentResource() {
|
||||
return currentResource;
|
||||
}
|
||||
|
||||
public LiveExpression<DocumentData> getDocumentData() {
|
||||
return documentData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class SpringSymbolsViewModel {
|
||||
gotoSymbols = new GotoSymbolDialogModel(null,
|
||||
InWorkspaceSymbolsProvider.createFor(currentProject::getValue),
|
||||
InProjectSymbolsProvider.createFor(currentProject),
|
||||
InFileSymbolsProvider.createFor(currentResource)
|
||||
InFileSymbolsProvider.createFor(currentSelection.getDocumentData())
|
||||
)
|
||||
.setFavourites(FavouritesPreference.INSTANCE);
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user