Make ls.eclipse.gotosymbol plugin part of boot.java.ls.feature

This commit is contained in:
Kris De Volder
2017-10-03 10:12:41 -07:00
parent ec5a47b669
commit 8bb96887fd
22 changed files with 35 additions and 4 deletions

View File

@@ -1,7 +0,0 @@
<?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>

View File

@@ -1,28 +0,0 @@
<?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>

View File

@@ -1,106 +0,0 @@
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

View File

@@ -1,24 +0,0 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Goto Symbol Popup
Bundle-SymbolicName: org.springframework.tooling.ls.eclipse.gotosymbol;singleton:=true
Bundle-Version: 0.0.10.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,
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
Bundle-Activator: org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin
Bundle-ActivationPolicy: lazy
Bundle-Vendor: Pivotal, Inc.

View File

@@ -1,6 +0,0 @@
source.. = src/
output.. = bin/
bin.includes = plugin.xml,\
META-INF/,\
.,\
icons/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 B

View File

@@ -1,66 +0,0 @@
<?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.dialogAndWindow"
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>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot.ide</groupId>
<artifactId>org.springframework.boot.ide</artifactId>
<version>4.0.0-SNAPSHOT</version>
<relativePath>../../eclipse-distribution/pom.xml</relativePath>
</parent>
<artifactId>org.springframework.tooling.ls.eclipse.gotosymbol</artifactId>
<packaging>eclipse-plugin</packaging>
<version>0.0.10-SNAPSHOT</version>
</project>

View File

@@ -1,31 +0,0 @@
/*******************************************************************************
* 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;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
public class GotoSymbolPlugin extends AbstractUIPlugin {
private static GotoSymbolPlugin instance;
public GotoSymbolPlugin() {
}
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
this.instance = this;
}
public static GotoSymbolPlugin getInstance() {
return instance;
}
}

View File

@@ -1,335 +0,0 @@
/*******************************************************************************
* 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.IDialogSettings;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.util.Geometry;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
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.custom.StyledText;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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.ide.eclipse.boot.util.Log;
import org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin;
import org.springframework.tooling.ls.eclipse.gotosymbol.util.SwtConnect;
import org.springsource.ide.eclipse.commons.livexp.core.UIValueListener;
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;
/**
* If true, align the dialog so it looks like its attached right side of the editor. Otherwise, dialog is centered on the editor instead.
*/
private boolean alignRight;
private IDialogSettings dlgSettings;
public GotoSymbolDialog(Shell parentShell, ITextEditor textEditor, GotoSymbolDialogModel model, boolean alignRight) {
super(parentShell, PopupDialog.INFOPOPUPRESIZE_SHELLSTYLE,
/*focus*/true, /*persistSize*/true, /*persistLoc*/true,
/*menu*/false, /*showPersistActions*/false, null, null
);
//Note: because of the way shell is initialized, the options to persist size / location do not work.
// If we want this to work, it will have to be debugged.
//For the time being I've simply disabled the menu that makes it appear like this should work.
this.fTextEditor = textEditor;
this.model = model;
this.alignRight = alignRight;
create();
}
@Override
protected IDialogSettings getDialogSettings() {
if (dlgSettings==null) {
this.dlgSettings = GotoSymbolPlugin.getInstance().getDialogSettings();
}
return dlgSettings;
}
/**
* Determine the 'target' for the dialog's action.
*/
private SymbolInformation getTarget(TreeViewer list) {
ISelection sel = list.getSelection();
if (sel instanceof IStructuredSelection) {
IStructuredSelection ss = (IStructuredSelection) sel;
Object selected = ss.getFirstElement();
if (selected!=null) {
return (SymbolInformation) selected;
}
}
//No element selected, target the first element in the list instead.
//This allows user to execute the action without explicitly selecting an element.
return getFirstElement(list);
}
private void installWidgetListeners(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());
}
}
} else if (e.character == '\r') {
performOk(list);
}
}
});
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());
}
}
} else if (e.character == '\r') {
performOk(list);
}
// if (e.keyCode == SWT.ARROW_DOWN
// && (e.stateMask & SWT.SHIFT) != 0
// && (e.stateMask & SWT.CTRL) != 0) {
//
// list.getTree().notifyListeners(SWT.Selection, new Event());
// }
}
});
list.addDoubleClickListener(e -> performOk(list));
}
private void performOk(TreeViewer list) {
if (model.performOk(getTarget(list))) {
close();
}
}
private SymbolInformation getFirstElement(TreeViewer list) {
TreeItem[] items = list.getTree().getItems();
if (items!=null && items.length>0) {
TreeItem item = items[0];
return (SymbolInformation) 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, SWT.SINGLE);
GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getControl());
viewer.setContentProvider(new SymbolsContentProvider());
viewer.setLabelProvider(new SymbolsLabelProvider());
viewer.setUseHashlookup(true);
disposables.add(model.getSymbols().onChange(UIValueListener.from((e, v) -> {
viewer.refresh();
})));
//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);
// }
// }
// });
installWidgetListeners(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);
Control control = fTextEditor.getAdapter(Control.class);
if (control != null) {
//Set size relative to editor's size.
Point size = new Point(control.getBounds().width/3, control.getBounds().height/2);
shell.setSize(size);
if (alignRight) {
shell.setLocation(control.toDisplay(control.getBounds().width - shell.getSize().x, control.getLocation().y));
} else {
//centered on the editor
shell.setLocation(control.toDisplay(control.getBounds().width/3, control.getBounds().height/4));
}
} else {
// fallback
shell.setSize(280, 300);
}
}
// /**
// * Determines the graphical area covered by the given text region.
// *
// * @param region the region whose graphical extend must be computed
// * @return the graphical extend of the given region
// */
// private Rectangle computeArea(IRegion region) {
//
// int start= 0;
// int end= 0;
//
// IRegion widgetRegion= modelRange2WidgetRange(region);
// if (widgetRegion != null) {
// start= widgetRegion.getOffset();
// end= widgetRegion.getOffset() + widgetRegion.getLength();
// }
//
// StyledText styledText= fTextEditor.getTextWidget();
// Rectangle bounds;
// if (end > 0 && start < end)
// bounds= styledText.getTextBounds(start, end - 1);
// else {
// Point loc= styledText.getLocationAtOffset(start);
// bounds= new Rectangle(loc.x, loc.y, 0, styledText.getLineHeight(start));
// }
//
// Rectangle clientArea= styledText.getClientArea();
// Geometry.moveInside(bounds, clientArea);
// return bounds;
// }
}

View File

@@ -1,184 +0,0 @@
/*******************************************************************************
* 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.Optional;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.lsp4j.SymbolInformation;
import org.springframework.ide.eclipse.boot.util.Log;
import org.springsource.ide.eclipse.commons.livexp.core.AsyncLiveExpression.AsyncMode;
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.livexp.util.ExceptionUtil;
import com.google.common.collect.ImmutableSet;
public class GotoSymbolDialogModel {
private static final boolean DEBUG = (""+Platform.getLocation()).contains("kdvolder");
private static void debug(String string) {
if (DEBUG) {
System.out.println(string);
}
}
@FunctionalInterface
public interface OKHandler {
/**
* Called by the ui to perform the dialog's action. The dialog will be
* closed by the ui this returns true, otherwise it remains open.
*/
boolean performOk(SymbolInformation selection);
}
private static final OKHandler DEFAULT_OK_HANDLER = (selection) -> true;
private SymbolsProvider[] symbolsProviders;
private final LiveVariable<String> status = new LiveVariable<>();
private int currentSymbolsProviderIndex;
private final LiveVariable<SymbolsProvider> currentSymbolsProvider = 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
{
setRefreshDelay(100);
dependsOn(searchBox);
dependsOn(currentSymbolsProvider);
}
@Override
protected ImmutableSet<SymbolInformation> compute() {
status.setValue("Fetching symbols...");
try {
SymbolsProvider sp = currentSymbolsProvider.getValue();
if (sp!=null) {
debug("Fetching "+sp.getName());
String query = searchBox.getValue();
debug("Fetching symbols... from symbol provider, for '"+query+"'");
Collection<SymbolInformation> fetched = sp.fetchFor(query);
if (keyBindings==null) {
status.setValue(sp.getName());
} else {
status.setValue("Press ["+keyBindings+"] for "+nextSymbolsProvider().getName());
}
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 SymbolsProvider nextSymbolsProvider() {
int nextIndex = (currentSymbolsProviderIndex + 1)%symbolsProviders.length;
return symbolsProviders[nextIndex];
}
};
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();
}
};
private String keyBindings;
private OKHandler okHandler = DEFAULT_OK_HANDLER;
public GotoSymbolDialogModel(String keyBindings, SymbolsProvider... symbolsProviders) {
this.keyBindings = keyBindings;
Assert.isLegal(symbolsProviders.length>0);
this.symbolsProviders = symbolsProviders;
this.currentSymbolsProviderIndex = 0;
this.currentSymbolsProvider.setValue(symbolsProviders[0]);
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;
}
public synchronized void toggleSymbolsProvider() {
currentSymbolsProviderIndex = (currentSymbolsProviderIndex+1)%symbolsProviders.length;
currentSymbolsProvider.setValue(symbolsProviders[currentSymbolsProviderIndex]);
}
/**
* Set an ok handler. The handler is meant to be called by the UI when user request to
* execute the dialogs action on its current selection. For example, by pressing 'ENTER'
* key, or by double-clicking an element.
* <p>
* If 'okHandler' returns 'true' then the dialog is closed. Otherwise it remains open.
*/
public GotoSymbolDialogModel setOkHandler(OKHandler okHandler) {
this.okHandler = okHandler == null ? DEFAULT_OK_HANDLER : okHandler;
return this;
}
public boolean performOk(SymbolInformation selection) {
return this.okHandler.performOk(selection);
}
}

View File

@@ -1,76 +0,0 @@
/*******************************************************************************
* 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.concurrent.CompletableFuture;
import org.eclipse.core.commands.ExecutionEvent;
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.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.ITextEditor;
import com.google.common.collect.ImmutableList;
/**
* SymbolsProvider that only looks for symbols in current file using the LSP 'document/symbols' api.
*
* @author Kris De Volder
*/
@SuppressWarnings("restriction")
public class InFileSymbolsProvider implements SymbolsProvider {
private LSPDocumentInfo info;
public InFileSymbolsProvider(LSPDocumentInfo target) {
super();
this.info = target;
}
@Override
public Collection<SymbolInformation> fetchFor(String query) throws Exception {
DocumentSymbolParams params = new DocumentSymbolParams(
new TextDocumentIdentifier(info.getFileUri().toString()));
CompletableFuture<List<? extends SymbolInformation>> symbolsFuture = info.getLanguageClient()
.getTextDocumentService().documentSymbol(params);
List<? extends SymbolInformation> symbols = symbolsFuture.get();
Thread.sleep(2000);
return symbols == null ? ImmutableList.of() : ImmutableList.copyOf(symbols);
}
public static SymbolsProvider createFor(ITextEditor textEditor) {
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();
if (info!=null) {
return new InFileSymbolsProvider(info);
}
return null;
}
@Override
public String getName() {
return "Symbols in File";
}
}

View File

@@ -1,103 +0,0 @@
/*******************************************************************************
* 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.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.lsp4e.LanguageServiceAccessor;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.WorkspaceSymbolParams;
import org.eclipse.lsp4j.services.LanguageServer;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.handlers.HandlerUtil;
import org.springframework.ide.eclipse.boot.util.Log;
import com.google.common.collect.ImmutableList;
@SuppressWarnings("restriction")
public class InWorkspaceSymbolsProvider implements SymbolsProvider {
private static final Duration TIMEOUT = Duration.ofSeconds(2);
private List<LanguageServer> languageServers;
public InWorkspaceSymbolsProvider(List<LanguageServer> languageServers) {
this.languageServers = languageServers;
}
@Override
public String getName() {
return "Symbols in Workspace";
}
@Override
public Collection<SymbolInformation> fetchFor(String query) throws Exception {
//TODO: if we want decent support for multiple language servers...
// consider changing SymbolsProvider api and turning the stuff in here into something producing a
// Flux<Collection<SymbolInformation>>
// This will help in
// - supporting cancelation
// - executing multiple requests to different servers in parallel.
// - producing results per server so don't have to wait for one slow server to see the rest.
//However it will also add complexity to the code that consumes this and at this time we only
// really use this with a single language server anyways.
ImmutableList.Builder<SymbolInformation> allSymbols = ImmutableList.builder();
for (LanguageServer server : this.languageServers) {
try {
WorkspaceSymbolParams params = new WorkspaceSymbolParams(query);
List<? extends SymbolInformation> symbolsFuture =
server.getWorkspaceService().symbol(params)
.get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
allSymbols.addAll(symbolsFuture);
} catch (Exception e) {
Log.log(e);
}
}
return allSymbols.build();
}
public static InWorkspaceSymbolsProvider createFor(ExecutionEvent event) {
IEditorPart part = HandlerUtil.getActiveEditor(event);
IResource resource = null;
if (part != null && part.getEditorInput() != null) {
resource = part.getEditorInput().getAdapter(IResource.class);
} else {
IStructuredSelection selection = HandlerUtil.getCurrentStructuredSelection(event);
if (selection.isEmpty() || !(selection.getFirstElement() instanceof IAdaptable)) {
return null;
}
IAdaptable adaptable = (IAdaptable) selection.getFirstElement();
resource = adaptable.getAdapter(IResource.class);
}
if (resource!=null) {
return createFor(resource.getProject());
}
return null;
}
public static InWorkspaceSymbolsProvider createFor(IProject project) {
List<LanguageServer> languageServers = LanguageServiceAccessor.getLanguageServers(project,
capabilities -> Boolean.TRUE.equals(capabilities.getWorkspaceSymbolProvider()));
if (!languageServers.isEmpty()) {
return new InWorkspaceSymbolsProvider(languageServers);
}
return null;
}
}

View File

@@ -1,25 +0,0 @@
/*******************************************************************************
* 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 {
String getName();
Collection<SymbolInformation> fetchFor(String query) throws Exception;
}

View File

@@ -1,117 +0,0 @@
/*******************************************************************************
* 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.List;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.lsp4e.LSPEclipseUtils;
import org.eclipse.lsp4e.LanguageServiceAccessor;
import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
import org.eclipse.lsp4j.Location;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.keys.IBindingService;
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 org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.InFileSymbolsProvider;
import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.InWorkspaceSymbolsProvider;
@SuppressWarnings("restriction")
public class GotoSymbolHandler extends AbstractHandler {
private static final boolean DEBUG = (""+Platform.getLocation()).contains("kdvolder");
private static void debug(String string) {
if (DEBUG) {
System.out.println(string);
}
}
private static GotoSymbolDialogModel currentDialog = null;
public GotoSymbolHandler() {
debug("Creating GotoSymbolHandler");
}
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
debug(">>>GotoSymbolHandler.execute");
if (currentDialog!=null) {
debug("GotoSymbolDialog already open: send 'toggle' signal");
currentDialog.toggleSymbolsProvider();
} else {
IEditorPart part = HandlerUtil.getActiveEditor(event);
if (part instanceof ITextEditor) {
final Shell shell = HandlerUtil.getActiveShell(event);
final ITextEditor textEditor = (ITextEditor) part;
GotoSymbolDialogModel model = new GotoSymbolDialogModel(getKeybindings(event), InFileSymbolsProvider.createFor(textEditor), InWorkspaceSymbolsProvider.createFor(event))
.setOkHandler(symbolInformation -> {
if (symbolInformation!=null) {
Location location = symbolInformation.getLocation();
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
LSPEclipseUtils.openInEditor(location, page);
}
return true;
});
GotoSymbolDialog dialog = new GotoSymbolDialog(shell, textEditor, model, /*alignRight*/ false);
currentDialog = model;
dialog.open();
debug("GotoSymbolDialog opened");
dialog.getShell().addDisposeListener(de -> {
debug("GotoSymbolDialog closed!");
currentDialog = null;
});
}
debug("<<<GotoSymbolHandler.execute");
}
return null;
}
private String getKeybindings(ExecutionEvent event) {
Command invokingCommand = event.getCommand();
IBindingService service = PlatformUI.getWorkbench().getService(IBindingService.class);
TriggerSequence[] bindings = service.getActiveBindingsFor(invokingCommand.getId());
if (bindings!=null && bindings.length>0) {
return bindings[0].toString();
}
return null;
}
@Override
public boolean isEnabled() {
boolean r = _isEnabled();
return r;
}
public boolean _isEnabled() {
IWorkbenchPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
if (part instanceof ITextEditor) {
debug("activePart instanceof ITextEditor");
List<LSPDocumentInfo> infos = LanguageServiceAccessor.getLSPDocumentInfosFor(
LSPEclipseUtils.getDocument((ITextEditor) part),
(capabilities) -> Boolean.TRUE.equals(capabilities.getDocumentSymbolProvider()));
return !infos.isEmpty();
}
debug("activePart not ITextEditor: "+part);
return false;
}
}

View File

@@ -1,68 +0,0 @@
/*******************************************************************************
* 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));
}
}