diff --git a/eclipse-language-servers/org.springframework.tooling.boot.java.ls/src/org/springframework/tooling/boot/java/ls/SpringBootJavaLanguageServer.java b/eclipse-language-servers/org.springframework.tooling.boot.java.ls/src/org/springframework/tooling/boot/java/ls/SpringBootJavaLanguageServer.java
index 07984d9b3..f464c68e6 100644
--- a/eclipse-language-servers/org.springframework.tooling.boot.java.ls/src/org/springframework/tooling/boot/java/ls/SpringBootJavaLanguageServer.java
+++ b/eclipse-language-servers/org.springframework.tooling.boot.java.ls/src/org/springframework/tooling/boot/java/ls/SpringBootJavaLanguageServer.java
@@ -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);
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.classpath b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.classpath
new file mode 100644
index 000000000..eca7bdba8
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.project b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.project
new file mode 100644
index 000000000..1f5f63896
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.project
@@ -0,0 +1,28 @@
+
+
+ org.springframework.tooling.ls.eclipse.gotosymbol
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.settings/org.eclipse.jdt.core.prefs b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..71c295fb2
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/.settings/org.eclipse.jdt.core.prefs
@@ -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
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..56cb4edc9
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF
@@ -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
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/build.properties b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/build.properties
new file mode 100644
index 000000000..0d3d3a745
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = plugin.xml,\
+ META-INF/,\
+ .,\
+ icons/
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/icons/sample.png b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/icons/sample.png
new file mode 100644
index 000000000..02c4b79e1
Binary files /dev/null and b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/icons/sample.png differ
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/icons/sample@2x.png b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/icons/sample@2x.png
new file mode 100644
index 000000000..c1224d1fc
Binary files /dev/null and b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/icons/sample@2x.png differ
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/plugin.xml b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/plugin.xml
new file mode 100644
index 000000000..cd8f82e9b
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/plugin.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java
new file mode 100644
index 000000000..9362fcc1f
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java
@@ -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 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));
+ }
+ }
+
+}
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialogModel.java b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialogModel.java
new file mode 100644
index 000000000..721ac1045
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialogModel.java
@@ -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 status = new LiveVariable<>();
+ private final LiveVariable symbolsProvider = new LiveVariable<>(null);
+ private final LiveVariable searchBox = new LiveVariable<>("");
+ private final ObservableSet unfilteredSymbols = new ObservableSet(ImmutableSet.of(), AsyncMode.ASYNC, AsyncMode.SYNC) {
+ //Note: fetching is 'slow' so is done asynchronously
+ {
+ dependsOn(searchBox);
+ dependsOn(symbolsProvider);
+ }
+
+ @Override
+ protected ImmutableSet 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 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 filteredSymbols = new ObservableSet() {
+ //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 compute() {
+ char[] query = searchBox.getValue().toCharArray();
+ ImmutableSet.Builder 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 summary(ImmutableSet values) {
+ return values.stream().map(SymbolInformation::getName).collect(Collectors.toList());
+ }
+
+ public ObservableSet getSymbols() {
+ return filteredSymbols;
+ }
+
+ public LiveVariable getSearchBox() {
+ return searchBox;
+ }
+
+ public LiveExpression getStatus() {
+ return status;
+ }
+
+}
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InFileSymbolsProvider.java b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InFileSymbolsProvider.java
new file mode 100644
index 000000000..94c846fbc
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/InFileSymbolsProvider.java
@@ -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 fetchFor(String query) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/SymbolsProvider.java b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/SymbolsProvider.java
new file mode 100644
index 000000000..31abba0e5
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/SymbolsProvider.java
@@ -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 fetchFor(String query);
+}
\ No newline at end of file
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/handlers/GotoSymbolHandler.java b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/handlers/GotoSymbolHandler.java
new file mode 100644
index 000000000..d472d74ca
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/handlers/GotoSymbolHandler.java
@@ -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 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> symbols = info.getLanguageClient()
+ .getTextDocumentService().documentSymbol(params);
+
+ symbols.thenAccept((List extends SymbolInformation> t) -> {
+ shell.getDisplay().asyncExec(() -> {
+ List 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 infos = LanguageServiceAccessor.getLSPDocumentInfosFor(
+ LSPEclipseUtils.getDocument((ITextEditor) part),
+ (capabilities) -> Boolean.TRUE.equals(capabilities.getDocumentSymbolProvider()));
+ return !infos.isEmpty();
+ }
+ return false;
+ }
+}
diff --git a/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/util/SwtConnect.java b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/util/SwtConnect.java
new file mode 100644
index 000000000..a35551fc0
--- /dev/null
+++ b/eclipse-plugins/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/util/SwtConnect.java
@@ -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 model) {
+ ModifyListener widgetListener = (ModifyEvent e) -> {
+ model.setValue(widget.getText());
+ };
+ ValueListener modelListener = new UIValueListener() {
+ @Override
+ protected void uiGotValue(LiveExpression 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 model) {
+ ValueListener modelListener = new UIValueListener() {
+ @Override
+ protected void uiGotValue(LiveExpression exp, String value) {
+ String newText = model.getValue();
+ if (newText==null) {
+ newText = "";
+ }
+ widget.setText(newText);
+ }
+ };
+ model.addListener(modelListener);
+ widget.addDisposeListener(xx -> model.removeListener(modelListener));
+ }
+
+}
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java
index 7b45e9e2b..70808a8c3 100644
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java
+++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java
@@ -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
*/
diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java
index 57f545b95..0a8d64eb5 100644
--- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java
+++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java
@@ -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);