From 1c09e8e59472fb2fd02c5eb2b97e198af0a42b6b Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Tue, 9 Jun 2020 15:22:36 -0700 Subject: [PATCH] Minimal UI to manage goto symbol 'Favourites' --- .../META-INF/MANIFEST.MF | 4 +- .../eclipse/gotosymbol/GotoSymbolPlugin.java | 2 + .../gotosymbol/dialogs/GotoSymbolDialog.java | 2 - .../dialogs/GotoSymbolDialogModel.java | 7 +- .../gotosymbol/dialogs/GotoSymbolSection.java | 59 ++++++++++- .../favourites/FavouritesPreference.java | 99 +++++++++++++++++++ .../view/SpringSymbolsViewModel.java | 8 +- 7 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/favourites/FavouritesPreference.java diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF index 99d1b69df..2cec87c83 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF @@ -20,7 +20,9 @@ Require-Bundle: org.eclipse.ui, org.springsource.ide.eclipse.commons.core;bundle-version="3.9.2", io.projectreactor.reactor-core;bundle-version="3.0.7", org.reactivestreams.reactive-streams;bundle-version="1.0.0", - org.springframework.ide.eclipse.boot.dash + org.springframework.ide.eclipse.boot.dash, + org.springsource.ide.eclipse.commons.frameworks.core, + org.springframework.ide.eclipse.boot Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-Activator: org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin Bundle-ActivationPolicy: lazy diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/GotoSymbolPlugin.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/GotoSymbolPlugin.java index faf6bc170..1754221ab 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/GotoSymbolPlugin.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/GotoSymbolPlugin.java @@ -15,6 +15,8 @@ import org.osgi.framework.BundleContext; public class GotoSymbolPlugin extends AbstractUIPlugin { + public static final String ID = "org.springframework.tooling.ls.eclipse.gotosymbol"; + private static GotoSymbolPlugin instance; public GotoSymbolPlugin() { diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java index b95884d8f..df4c4ce4e 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java @@ -30,7 +30,6 @@ public class GotoSymbolDialog extends PopupDialog implements IPageWithSections { private static final Point DEFAULT_SIZE = new Point(280, 300); - private GotoSymbolDialogModel model; private final GotoSymbolSection content; private ITextEditor fTextEditor; @@ -49,7 +48,6 @@ public class GotoSymbolDialog extends PopupDialog implements IPageWithSections { // 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.content = new GotoSymbolSection(this, model); this.alignRight = alignRight; create(); diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialogModel.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialogModel.java index a3588d2c9..f5095410f 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialogModel.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialogModel.java @@ -26,6 +26,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; import org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin; +import org.springframework.tooling.ls.eclipse.gotosymbol.favourites.FavouritesPreference; import org.springsource.ide.eclipse.commons.core.util.FuzzyMatcher; import org.springsource.ide.eclipse.commons.core.util.StringUtil; import org.springsource.ide.eclipse.commons.livexp.core.AsyncLiveExpression.AsyncMode; @@ -196,7 +197,7 @@ public class GotoSymbolDialogModel { private String keyBindings; private OKHandler okHandler = DEFAULT_OK_HANDLER; - private Favourite[] favourites = null; + private FavouritesPreference favourites = null; public GotoSymbolDialogModel(String keyBindings, SymbolsProvider... symbolsProviders) { this.keyBindings = keyBindings; @@ -213,12 +214,12 @@ public class GotoSymbolDialogModel { } } - public GotoSymbolDialogModel setFavourites(Favourite... favourites) { + public GotoSymbolDialogModel setFavourites(FavouritesPreference favourites) { this.favourites = favourites; return this; } - public Favourite[] getFavourites() { + public FavouritesPreference getFavourites() { return favourites; } diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolSection.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolSection.java index bbafd0a68..b0cc3b8ea 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolSection.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolSection.java @@ -14,12 +14,17 @@ package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.resource.JFaceColors; import org.eclipse.jface.text.BadLocationException; @@ -62,7 +67,9 @@ import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.TreeItem; import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.GotoSymbolDialogModel.Favourite; import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.GotoSymbolDialogModel.Match; +import org.springframework.tooling.ls.eclipse.gotosymbol.favourites.FavouritesPreference; import org.springsource.ide.eclipse.commons.core.util.FuzzyMatcher; +import org.springsource.ide.eclipse.commons.core.util.StringUtil; 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.ui.Disposable; @@ -295,13 +302,16 @@ public class GotoSymbolSection extends WizardPageSection { viewer.setInput(model); } - private void createFavouritesPulldown(Composite parent, Favourite[] favourites, LiveVariable searchBox) { + private void createFavouritesPulldown(Composite parent, FavouritesPreference favouritePrefs, LiveVariable searchBox) { Button btn = new Button(parent, SWT.ARROW | SWT.DOWN); btn.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { super.widgetSelected(e); Menu menu = new Menu(btn); + // create item for each of the known favourites + Favourite[] favourites = favouritePrefs.getFavourites(); + Set existingFavs = new HashSet<>(); for (Favourite f : favourites) { MenuItem item = new MenuItem(menu, SWT.PUSH); item.setText(f.toString()); @@ -310,7 +320,40 @@ public class GotoSymbolSection extends WizardPageSection { searchBox.setValue(f.query); } }); + existingFavs.add(f.query); } + //separator + new MenuItem(menu, SWT.SEPARATOR); + + String currentSearch = searchBox.getValue(); + + if (StringUtil.hasText(currentSearch)) { + if (!existingFavs.contains(currentSearch)) { + //create a 'add favourite' menu item + MenuItem item = new MenuItem(menu, SWT.PUSH); + item.setText("Add Favourite..."); + item.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + String name = inputDialog("Add '"+currentSearch+"' as a favourite", "Name:", ""); + if (StringUtil.hasText(name)) { + favouritePrefs.add(name, currentSearch); + } + } + }); + } else { // the currentSearch is already a favourite + //create a 'remove favourite' menu item + MenuItem item = new MenuItem(menu, SWT.PUSH); + item.setText("Remove '"+currentSearch+"' Favourite"); + item.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + favouritePrefs.remove(currentSearch); + } + }); + } + } + Point loc = btn.getLocation(); Rectangle rect = btn.getBounds(); Point mLoc = new Point(loc.x-1, loc.y+rect.height); @@ -320,6 +363,20 @@ public class GotoSymbolSection extends WizardPageSection { }); } + private String inputDialog(String dialogTitle, String prompt, String defaultValue) { + AtomicReference result = new AtomicReference<>(); + owner.getShell().getDisplay().syncExec(new Runnable() { + public void run() { + InputDialog dlg = new InputDialog(owner.getShell(), dialogTitle, prompt, defaultValue, null); + int code = dlg.open(); + if (code==IDialogConstants.OK_ID) { + result.set(dlg.getValue()); + } + } + }); + return result.get(); + } + private void installWidgetListeners(Text pattern, TreeViewer list) { pattern.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/favourites/FavouritesPreference.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/favourites/FavouritesPreference.java new file mode 100644 index 000000000..3d22ef8b3 --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/favourites/FavouritesPreference.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2020 Pivotal Software, 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal Software, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.tooling.ls.eclipse.gotosymbol.favourites; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.MenuItem; +import org.springframework.ide.eclipse.boot.pstore.IPropertyStore; +import org.springframework.ide.eclipse.boot.pstore.PropertyStoreApi; +import org.springframework.ide.eclipse.boot.pstore.PropertyStores; +import org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin; +import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.GotoSymbolDialogModel.Favourite; +import org.springsource.ide.eclipse.commons.core.util.StringUtil; +import org.springsource.ide.eclipse.commons.livexp.util.Log; + +public class FavouritesPreference { + + /** + * The singleton 'Production' instance of {@link FavouritesPreference}. This stores/reads favourites to/from + * the Eclipse preference store for {@link GotoSymbolPlugin}. + */ + public static final FavouritesPreference INSTANCE = new FavouritesPreference( + PropertyStores.backedBy(GotoSymbolPlugin.getInstance().getPreferenceStore()) + ); + + public static final Favourite[] DEFAULT = { + new Favourite("Request Mappings", "@/"), + new Favourite("Beans", "@+"), + new Favourite("All Spring Elements", "@") + }; + private static final String KEY = "favourites"; + private static final String[] NO_STRINGS = {}; + + private PropertyStoreApi prefs; + + public FavouritesPreference(IPropertyStore backingStore) { + this.prefs = new PropertyStoreApi(backingStore); + } + + public Favourite[] getFavourites() { + try { + String[] strings = prefs.get(KEY, NO_STRINGS); + if (strings!=null && strings.length>0) { + Favourite[] favs = new Favourite[strings.length/2]; + for (int i = 0; i < strings.length; i+=2) { + favs[i/2] = new Favourite(strings[i], strings[i+1]); + } + return favs; + } + } catch (Exception e) { + Log.log(e); + } + return DEFAULT; + } + + public void setFavourites(Favourite[] favourites) { + try { + String[] strings = new String[favourites.length*2]; + for (int i = 0; i < strings.length; i+=2) { + Favourite fav = favourites[i/2]; + strings[i] = fav.name; + strings[i+1] = fav.query; + } + prefs.put(KEY, strings); + } catch (Exception e) { + Log.log(e); + } + } + + public void add(String name, String currentSearch) { + Favourite[] oldFavs = getFavourites(); + Favourite[] newFavs = new Favourite[oldFavs.length+1]; + for (int i = 0; i < oldFavs.length; i++) { + newFavs[i] = oldFavs[i]; + } + newFavs[oldFavs.length] = new Favourite(name, currentSearch); + setFavourites(newFavs); + } + + public void remove(String currentSearch) { + List retain = new ArrayList<>(); + for (Favourite favourite : getFavourites()) { + if (!favourite.query.equals(currentSearch)) { + retain.add(favourite); + } + } + setFavourites(retain.toArray(new Favourite[retain.size()])); + } +} diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/view/SpringSymbolsViewModel.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/view/SpringSymbolsViewModel.java index 08f5bec84..a44be3389 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/view/SpringSymbolsViewModel.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/view/SpringSymbolsViewModel.java @@ -16,7 +16,7 @@ import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.GotoSymbolDialo import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.InFileSymbolsProvider; import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.InProjectSymbolsProvider; import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.InWorkspaceSymbolsProvider; -import org.springframework.tooling.ls.eclipse.gotosymbol.dialogs.GotoSymbolDialogModel.Favourite; +import org.springframework.tooling.ls.eclipse.gotosymbol.favourites.FavouritesPreference; import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression; import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable; @@ -29,11 +29,7 @@ public class SpringSymbolsViewModel { InProjectSymbolsProvider.createFor(currentProject), InFileSymbolsProvider.createFor(currentResource) ) - .setFavourites( - new Favourite("Request Mappings", "@/"), - new Favourite("Beans", "@+"), - new Favourite("All Spring Elements", "@") - ); + .setFavourites(FavouritesPreference.INSTANCE); { gotoSymbols.unfilteredSymbols.dependsOn(currentProject); }