WIP: goto symbol in file dialog
This commit is contained in:
@@ -101,6 +101,10 @@ public class SpringBootJavaLanguageServer extends ProcessStreamConnectionProvide
|
||||
}
|
||||
|
||||
protected String getLanguageServerJARLocation() {
|
||||
String fromSysprop = System.getProperty("boot-java-ls-jar", null);
|
||||
if (fromSysprop!=null) {
|
||||
return fromSysprop;
|
||||
}
|
||||
String languageServer = "boot-java-language-server-" + Constants.LANGUAGE_SERVER_VERSION;
|
||||
|
||||
Bundle bundle = Platform.getBundle(Constants.PLUGIN_ID);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.springframework.tooling.ls.eclipse.gotosymbol</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,106 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
|
||||
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
|
||||
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
|
||||
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
|
||||
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.APILeak=warning
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
@@ -0,0 +1,22 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Gotosymbol
|
||||
Bundle-SymbolicName: org.springframework.tooling.ls.eclipse.gotosymbol;singleton:=true
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Require-Bundle: org.eclipse.ui,
|
||||
org.eclipse.ui.workbench.texteditor,
|
||||
org.eclipse.lsp4e,
|
||||
org.eclipse.lsp4j,
|
||||
org.eclipse.jface.text;bundle-version="3.12.0",
|
||||
org.eclipse.core.resources;bundle-version="3.12.0",
|
||||
org.eclipse.core.filebuffers,
|
||||
org.eclipse.ui.navigator,
|
||||
org.eclipse.equinox.registry,
|
||||
io.projectreactor.reactor-core,
|
||||
org.springsource.ide.eclipse.commons.livexp,
|
||||
com.google.guava,
|
||||
org.eclipse.core.jobs,
|
||||
org.eclipse.core.runtime;bundle-version="3.13.0",
|
||||
org.springframework.ide.eclipse.boot,
|
||||
org.springsource.ide.eclipse.commons.core
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
@@ -0,0 +1,6 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = plugin.xml,\
|
||||
META-INF/,\
|
||||
.,\
|
||||
icons/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 332 B |
Binary file not shown.
|
After Width: | Height: | Size: 526 B |
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?eclipse version="3.4"?>
|
||||
<plugin>
|
||||
<extension
|
||||
point="org.eclipse.ui.commands">
|
||||
<category
|
||||
name="STS4"
|
||||
id="org.springframework.tooling.ls.eclipse.gotosymbol.commands.category">
|
||||
</category>
|
||||
<command
|
||||
name="Goto Symbol"
|
||||
categoryId="org.springframework.tooling.ls.eclipse.gotosymbol.commands.category"
|
||||
defaultHandler="org.springframework.tooling.ls.eclipse.gotosymbol.handlers.GotoSymbolHandler"
|
||||
id="org.springframework.tooling.ls.eclipse.gotosymbol.command">
|
||||
</command>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.ui.handlers">
|
||||
<handler
|
||||
commandId="org.springframework.tooling.ls.eclipse.gotosymbol.command"
|
||||
class="org.springframework.tooling.ls.eclipse.gotosymbol.handlers.GotoSymbolHandler">
|
||||
</handler>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.ui.bindings">
|
||||
<key
|
||||
commandId="org.springframework.tooling.ls.eclipse.gotosymbol.command"
|
||||
contextId="org.eclipse.ui.contexts.window"
|
||||
sequence="M1+6"
|
||||
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration">
|
||||
</key>
|
||||
</extension>
|
||||
<!-- TODO: stuff below comes from 'Hello world Command' example generated by Eclipse
|
||||
Should figure out proper way to integrate into menus and toolbars etc. So commented out
|
||||
The command is currently accessible only via 'Quick Access' search box or keyboard shortcut
|
||||
<extension
|
||||
point="org.eclipse.ui.menus">
|
||||
<menuContribution
|
||||
locationURI="menu:org.eclipse.ui.main.menu?after=additions">
|
||||
<menu
|
||||
label="Sample Menu"
|
||||
mnemonic="M"
|
||||
id="org.springframework.tooling.ls.eclipse.gotosymbol.menus.sampleMenu">
|
||||
<command
|
||||
commandId="org.springframework.tooling.ls.eclipse.gotosymbol.command"
|
||||
mnemonic="G"
|
||||
id="org.springframework.tooling.ls.eclipse.gotosymbol.menus.sampleCommand">
|
||||
</command>
|
||||
</menu>
|
||||
</menuContribution>
|
||||
<menuContribution
|
||||
locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
|
||||
<toolbar
|
||||
id="org.springframework.tooling.ls.eclipse.gotosymbol.toolbars.sampleToolbar">
|
||||
<command
|
||||
commandId="org.springframework.tooling.ls.eclipse.gotosymbol.commands.sampleCommand"
|
||||
icon="icons/sample.png"
|
||||
tooltip="Say hello world"
|
||||
id="org.springframework.tooling.ls.eclipse.gotosymbol.toolbars.sampleCommand">
|
||||
</command>
|
||||
</toolbar>
|
||||
</menuContribution>
|
||||
</extension>
|
||||
-->
|
||||
|
||||
</plugin>
|
||||
@@ -0,0 +1,242 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michał Niewrzał (Rogue Wave Software Inc.) - initial implementation
|
||||
* Kris De Volder (Pivotal Inc) - Copied and adapted from
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.jface.dialogs.PopupDialog;
|
||||
import org.eclipse.jface.layout.GridDataFactory;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
import org.eclipse.jface.viewers.ITreeContentProvider;
|
||||
import org.eclipse.jface.viewers.StructuredSelection;
|
||||
import org.eclipse.jface.viewers.TreeViewer;
|
||||
import org.eclipse.lsp4e.outline.SymbolsLabelProvider;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.KeyAdapter;
|
||||
import org.eclipse.swt.events.KeyEvent;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.eclipse.swt.widgets.TreeItem;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
import org.springframework.tooling.ls.eclipse.gotosymbol.util.SwtConnect;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class GotoSymbolDialog extends PopupDialog {
|
||||
|
||||
private static final boolean DEBUG = (""+Platform.getLocation()).contains("kdvolder");
|
||||
|
||||
private static void debug(String string) {
|
||||
if (DEBUG) {
|
||||
System.out.println(string);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SymbolsContentProvider implements ITreeContentProvider {
|
||||
|
||||
@Override
|
||||
public Object[] getChildren(Object parentElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParent(Object element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChildren(Object element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getElements(Object inputElement) {
|
||||
if (inputElement instanceof GotoSymbolDialogModel) {
|
||||
GotoSymbolDialogModel model = (GotoSymbolDialogModel) inputElement;
|
||||
return model.getSymbols().getValues().toArray();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private GotoSymbolDialogModel model;
|
||||
private List<Disposable> disposables = new ArrayList<>();
|
||||
private ITextEditor fTextEditor;
|
||||
|
||||
public GotoSymbolDialog(Shell parentShell, ITextEditor textEditor, GotoSymbolDialogModel model) {
|
||||
super(parentShell, PopupDialog.INFOPOPUP_SHELLSTYLE, true, true, true, false, false, null, null);
|
||||
this.fTextEditor = textEditor;
|
||||
this.model = model;
|
||||
create();
|
||||
}
|
||||
|
||||
private void installKeyListeners(Text pattern, TreeViewer list) {
|
||||
pattern.addKeyListener(new KeyAdapter() {
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.keyCode == SWT.ARROW_DOWN) {
|
||||
if (list.getTree().getItemCount() > 0) {
|
||||
list.getTree().setFocus();
|
||||
TreeItem[] items = list.getTree().getItems();
|
||||
if (items!=null && items.length>0) {
|
||||
list.getTree().setSelection(items[0]);
|
||||
//programatic selection may not fire selection events so...
|
||||
list.getTree().notifyListeners(SWT.Selection,
|
||||
new Event());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
list.getTree().addKeyListener(new KeyAdapter() {
|
||||
public void keyPressed(KeyEvent e) {
|
||||
|
||||
if (e.keyCode == SWT.ARROW_UP && (e.stateMask & SWT.SHIFT) == 0
|
||||
&& (e.stateMask & SWT.CTRL) == 0) {
|
||||
StructuredSelection selection = (StructuredSelection) list
|
||||
.getSelection();
|
||||
|
||||
if (selection.size() == 1) {
|
||||
Object element = selection.getFirstElement();
|
||||
if (element.equals(getFirstElement(list))) {
|
||||
pattern.setFocus();
|
||||
list.setSelection(new StructuredSelection());
|
||||
list.getTree().notifyListeners(SWT.Selection,
|
||||
new Event());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// if (e.keyCode == SWT.ARROW_DOWN
|
||||
// && (e.stateMask & SWT.SHIFT) != 0
|
||||
// && (e.stateMask & SWT.CTRL) != 0) {
|
||||
//
|
||||
// list.getTree().notifyListeners(SWT.Selection, new Event());
|
||||
// }
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Object getFirstElement(TreeViewer list) {
|
||||
TreeItem[] items = list.getTree().getItems();
|
||||
if (items!=null && items.length>0) {
|
||||
TreeItem item = items[0];
|
||||
return item.getData();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Control createDialogArea(Composite parent) {
|
||||
Composite dialogArea = new Composite(parent, SWT.NONE);
|
||||
dialogArea.addDisposeListener(de -> {
|
||||
for (Disposable d : disposables) {
|
||||
d.dispose();
|
||||
}
|
||||
});
|
||||
if (parent.getLayout() instanceof GridLayout) {
|
||||
dialogArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
}
|
||||
|
||||
GridLayout layout = new GridLayout();
|
||||
layout.marginHeight = 0;
|
||||
layout.marginWidth = 0;
|
||||
dialogArea.setLayout(layout);
|
||||
|
||||
Text pattern = new Text(dialogArea, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
|
||||
// pattern.getAccessible().addAccessibleListener(new AccessibleAdapter() {
|
||||
// public void getName(AccessibleEvent e) {
|
||||
// e.result = LegacyActionTools.removeMnemonics(headerLabel)
|
||||
// .getText());
|
||||
// }
|
||||
// });
|
||||
pattern.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
SwtConnect.connect(pattern, model.getSearchBox());
|
||||
|
||||
TreeViewer viewer = new TreeViewer(dialogArea);
|
||||
GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getControl());
|
||||
viewer.setContentProvider(new SymbolsContentProvider());
|
||||
viewer.setLabelProvider(new SymbolsLabelProvider());
|
||||
viewer.setUseHashlookup(true);
|
||||
disposables.add(model.getSymbols().onChange((e, v) -> {
|
||||
viewer.refresh();
|
||||
}));
|
||||
if (DEBUG) {
|
||||
viewer.addSelectionChangedListener(event -> {
|
||||
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
|
||||
if (selection.isEmpty()) {
|
||||
debug("selected NONE");
|
||||
} else {
|
||||
SymbolInformation symbolInformation = (SymbolInformation) selection.getFirstElement();
|
||||
debug("selected = "+symbolInformation.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
//TODO: somehow show selection in local file, (but not in other file ?)
|
||||
// viewer.addSelectionChangedListener(event -> {
|
||||
// IStructuredSelection selection = (IStructuredSelection) event.getSelection();
|
||||
// if (selection.isEmpty()) {
|
||||
// return;
|
||||
// }
|
||||
// SymbolInformation symbolInformation = (SymbolInformation) selection.getFirstElement();
|
||||
// Location location = symbolInformation.getLocation();
|
||||
//
|
||||
// IResource targetResource = LSPEclipseUtils.findResourceFor(location.getUri());
|
||||
// if (targetResource == null) {
|
||||
// return;
|
||||
// }
|
||||
// IDocument targetDocument = FileBuffers.getTextFileBufferManager()
|
||||
// .getTextFileBuffer(targetResource.getFullPath(), LocationKind.IFILE).getDocument();
|
||||
// if (targetDocument != null) {
|
||||
// try {
|
||||
// int offset = LSPEclipseUtils.toOffset(location.getRange().getStart(), targetDocument);
|
||||
// int endOffset = LSPEclipseUtils.toOffset(location.getRange().getEnd(), targetDocument);
|
||||
// fTextEditor.selectAndReveal(offset, endOffset - offset);
|
||||
// } catch (BadLocationException e) {
|
||||
// LanguageServerPlugin.logError(e);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
installKeyListeners(pattern, viewer);
|
||||
|
||||
Label statusLabel = new Label(dialogArea, SWT.NONE);
|
||||
statusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
|
||||
SwtConnect.connect(statusLabel, model.getStatus());
|
||||
|
||||
viewer.setInput(model);
|
||||
return dialogArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureShell(Shell shell) {
|
||||
super.configureShell(shell);
|
||||
|
||||
shell.setSize(280, 300);
|
||||
Control control = fTextEditor.getAdapter(Control.class);
|
||||
if (control != null) {
|
||||
shell.setLocation(
|
||||
control.toDisplay(control.getBounds().width - shell.getSize().x, control.getLocation().y));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.AsyncLiveExpression.AsyncMode;
|
||||
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;
|
||||
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.core.ObservableSet;
|
||||
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import org.springframework.ide.eclipse.boot.util.Log;
|
||||
|
||||
public class GotoSymbolDialogModel {
|
||||
|
||||
private static final boolean DEBUG = (""+Platform.getLocation()).contains("kdvolder");
|
||||
|
||||
private static void debug(String string) {
|
||||
if (DEBUG) {
|
||||
System.out.println(string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO: support for switching between local/workspace symbols.
|
||||
|
||||
private final LiveVariable<String> status = new LiveVariable<>();
|
||||
private final LiveVariable<SymbolsProvider> symbolsProvider = new LiveVariable<>(null);
|
||||
private final LiveVariable<String> searchBox = new LiveVariable<>("");
|
||||
private final ObservableSet<SymbolInformation> unfilteredSymbols = new ObservableSet<SymbolInformation>(ImmutableSet.of(), AsyncMode.ASYNC, AsyncMode.SYNC) {
|
||||
//Note: fetching is 'slow' so is done asynchronously
|
||||
{
|
||||
dependsOn(searchBox);
|
||||
dependsOn(symbolsProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImmutableSet<SymbolInformation> compute() {
|
||||
status.setValue("Fetching symbols...");
|
||||
try {
|
||||
debug("Fetching symbols ");
|
||||
SymbolsProvider sp = symbolsProvider.getValue();
|
||||
if (sp!=null) {
|
||||
String query = searchBox.getValue();
|
||||
debug("Fetching symbols... from symbol provider, for '"+query+"'");
|
||||
Collection<SymbolInformation> fetched = sp.fetchFor(query);
|
||||
if (DEBUG) {
|
||||
fetched.stream().forEach(sym -> debug("symbol: "+sym.getName()));
|
||||
}
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append("Fetched ");
|
||||
msg.append(fetched.size());
|
||||
msg.append(" symbols");
|
||||
if (StringUtil.hasText(query)) {
|
||||
msg.append(" matching '");
|
||||
msg.append(query);
|
||||
msg.append("'");
|
||||
}
|
||||
debug(msg.toString());
|
||||
status.setValue(msg.toString());
|
||||
return ImmutableSet.copyOf(fetched);
|
||||
} else {
|
||||
status.setValue("No symbol provider");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
status.setValue(ExceptionUtil.getMessage(e));
|
||||
}
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
};
|
||||
private ObservableSet<SymbolInformation> filteredSymbols = new ObservableSet<SymbolInformation>() {
|
||||
//Note: filtering is 'fast' so is done synchronously
|
||||
{
|
||||
dependsOn(searchBox);
|
||||
dependsOn(unfilteredSymbols);
|
||||
}
|
||||
|
||||
private boolean containsCharacters(char[] symbolChars, char[] queryChars) {
|
||||
int symbolindex = 0;
|
||||
int queryindex = 0;
|
||||
|
||||
while (queryindex < queryChars.length && symbolindex < symbolChars.length) {
|
||||
if (symbolChars[symbolindex] == queryChars[queryindex]) {
|
||||
queryindex++;
|
||||
}
|
||||
symbolindex++;
|
||||
}
|
||||
|
||||
return queryindex == queryChars.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImmutableSet<SymbolInformation> compute() {
|
||||
char[] query = searchBox.getValue().toCharArray();
|
||||
ImmutableSet.Builder<SymbolInformation> builder = ImmutableSet.builder();
|
||||
unfilteredSymbols.getValues().stream().filter(sym -> containsCharacters(sym.getName().toCharArray(), query)).forEach(builder::add);
|
||||
return builder.build();
|
||||
}
|
||||
};
|
||||
|
||||
public GotoSymbolDialogModel(SymbolsProvider symbolsProvider) {
|
||||
this.symbolsProvider.setValue(symbolsProvider);
|
||||
if (DEBUG) {
|
||||
searchBox.addListener((e, v) -> {
|
||||
debug("searchBox = "+v);
|
||||
});
|
||||
unfilteredSymbols.addListener((e, v) -> debug("raw = "+summary(filteredSymbols.getValues())));
|
||||
filteredSymbols.addListener((e, v) -> debug("filtered = "+summary(filteredSymbols.getValues())));
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> summary(ImmutableSet<SymbolInformation> values) {
|
||||
return values.stream().map(SymbolInformation::getName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public ObservableSet<SymbolInformation> getSymbols() {
|
||||
return filteredSymbols;
|
||||
}
|
||||
|
||||
public LiveVariable<String> getSearchBox() {
|
||||
return searchBox;
|
||||
}
|
||||
|
||||
public LiveExpression<String> getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
|
||||
public class InFileSymbolsProvider implements SymbolsProvider {
|
||||
|
||||
private ITextEditor target;
|
||||
|
||||
public InFileSymbolsProvider(ITextEditor target) {
|
||||
super();
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> fetchFor(String query) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
|
||||
/**
|
||||
* An SymbolsProvider can fetch symbols from a service (typically, a language server
|
||||
* operation is used to fetch symbol data. This operation may be slow and should be
|
||||
* called only from a background job.
|
||||
*/
|
||||
public interface SymbolsProvider {
|
||||
Collection<SymbolInformation> fetchFor(String query);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Rogue Wave Software Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michał Niewrzał (Rogue Wave Software Inc.) - initial implementation
|
||||
* Kris De Volder (Pivotal) - copied and adapted from org.eclipse.lsp4e.operations.symbols.LSPSymbolInFileDialog
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.gotosymbol.handlers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.core.commands.AbstractHandler;
|
||||
import org.eclipse.core.commands.ExecutionEvent;
|
||||
import org.eclipse.core.commands.ExecutionException;
|
||||
import org.eclipse.lsp4e.LSPEclipseUtils;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor;
|
||||
import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
|
||||
import org.eclipse.lsp4j.DocumentSymbolParams;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.handlers.HandlerUtil;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.GotoSymbolDialog;
|
||||
import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.GotoSymbolDialogModel;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Our sample handler extends AbstractHandler, an IHandler base class.
|
||||
* @see org.eclipse.core.commands.IHandler
|
||||
* @see org.eclipse.core.commands.AbstractHandler
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public class GotoSymbolHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public Object execute(ExecutionEvent event) throws ExecutionException {
|
||||
System.out.println("GotoSymbolHandler.execute");
|
||||
IEditorPart part = HandlerUtil.getActiveEditor(event);
|
||||
if (part instanceof ITextEditor) {
|
||||
final ITextEditor textEditor = (ITextEditor) part;
|
||||
Collection<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(
|
||||
LSPEclipseUtils.getDocument(textEditor),
|
||||
capabilities -> Boolean.TRUE.equals(capabilities.getDocumentSymbolProvider()));
|
||||
if (infos.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// TODO maybe consider better strategy such as iterating on all LS until we have a good result
|
||||
LSPDocumentInfo info = infos.iterator().next();
|
||||
final Shell shell = HandlerUtil.getActiveShell(event);
|
||||
DocumentSymbolParams params = new DocumentSymbolParams(
|
||||
new TextDocumentIdentifier(info.getFileUri().toString()));
|
||||
CompletableFuture<List<? extends SymbolInformation>> symbols = info.getLanguageClient()
|
||||
.getTextDocumentService().documentSymbol(params);
|
||||
|
||||
symbols.thenAccept((List<? extends SymbolInformation> t) -> {
|
||||
shell.getDisplay().asyncExec(() -> {
|
||||
List<SymbolInformation> allSymbols = ImmutableList.copyOf(t);
|
||||
GotoSymbolDialogModel model = new GotoSymbolDialogModel(query -> allSymbols);
|
||||
GotoSymbolDialog dialog = new GotoSymbolDialog(shell, textEditor, model);
|
||||
dialog.open();
|
||||
});
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
boolean r = _isEnabled();
|
||||
System.out.println("isEnabled = "+r);
|
||||
return r;
|
||||
}
|
||||
public boolean _isEnabled() {
|
||||
|
||||
IWorkbenchPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
|
||||
if (part instanceof ITextEditor) {
|
||||
List<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(
|
||||
LSPEclipseUtils.getDocument((ITextEditor) part),
|
||||
(capabilities) -> Boolean.TRUE.equals(capabilities.getDocumentSymbolProvider()));
|
||||
return !infos.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.tooling.ls.eclipse.gotosymbol.util;
|
||||
|
||||
import org.eclipse.swt.events.ModifyEvent;
|
||||
import org.eclipse.swt.events.ModifyListener;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
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.core.UIValueListener;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.ValueListener;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;
|
||||
|
||||
/**
|
||||
* Static helper methods for attaching LiveExps to SWT widgets.
|
||||
*/
|
||||
public class SwtConnect {
|
||||
|
||||
public static void connect(Text widget, LiveVariable<String> model) {
|
||||
ModifyListener widgetListener = (ModifyEvent e) -> {
|
||||
model.setValue(widget.getText());
|
||||
};
|
||||
ValueListener<String> modelListener = new UIValueListener<String>() {
|
||||
@Override
|
||||
protected void uiGotValue(LiveExpression<String> exp, String value) {
|
||||
String newText = model.getValue();
|
||||
if (newText==null) {
|
||||
newText = "";
|
||||
}
|
||||
String oldText = widget.getText();
|
||||
if (!newText.equals(oldText)) {
|
||||
widget.setText(newText);
|
||||
}
|
||||
}
|
||||
};
|
||||
widget.addModifyListener(widgetListener);
|
||||
model.addListener(modelListener);
|
||||
widget.addDisposeListener(e -> {
|
||||
model.removeListener(modelListener);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void connect(Label widget, LiveExpression<String> model) {
|
||||
ValueListener<String> modelListener = new UIValueListener<String>() {
|
||||
@Override
|
||||
protected void uiGotValue(LiveExpression<String> exp, String value) {
|
||||
String newText = model.getValue();
|
||||
if (newText==null) {
|
||||
newText = "";
|
||||
}
|
||||
widget.setText(newText);
|
||||
}
|
||||
};
|
||||
model.addListener(modelListener);
|
||||
widget.addDisposeListener(xx -> model.removeListener(modelListener));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,6 +49,8 @@ import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguage
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
|
||||
@@ -310,7 +310,9 @@ public class SimpleTextDocumentService implements TextDocumentService {
|
||||
}
|
||||
return Mono.fromCallable(() -> {
|
||||
server.waitForReconcile();
|
||||
return documentSymbolHandler.handle(params);
|
||||
List<? extends SymbolInformation> r = documentSymbolHandler.handle(params);
|
||||
//handle it when symbolHandler is sloppy and returns null instead of empty list.
|
||||
return r == null ? ImmutableList.of() : r;
|
||||
})
|
||||
.toFuture()
|
||||
.thenApply(l -> (List<? extends SymbolInformation>)l);
|
||||
|
||||
Reference in New Issue
Block a user