git clone http://danamlund/git/eclipse-quick-launch/.git
Log | Files | Refs | LICENSE

commit afbb28668b721ae50dc2f12861f5de6d89ed2783
parent e56af8b3a6992ce1b2dffe40f170ffd09327d6ac
Author: Dan Amlund <dan@danamlund.dk>
Date:   Wed,  8 Nov 2017 21:07:24 +0100

v1.3: Move better matching entries to the top. Better matching is when pattern letters are neighbors

Diffstat:
Mdk.danamlund.quicklaunch/META-INF/MANIFEST.MF | 2+-
Mdk.danamlund.quicklaunch/src/dk/danamlund/quicklaunch/QuickLaunchConfigurationDialog.java | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mdk.danamlund.quicklaunch/src/dk/danamlund/quicklaunch/QuickLauncher.java | 2+-
3 files changed, 122 insertions(+), 22 deletions(-)

diff --git a/dk.danamlund.quicklaunch/META-INF/MANIFEST.MF b/dk.danamlund.quicklaunch/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Quick Launch Configuration Bundle-SymbolicName: dk.danamlund.quicklaunch;singleton:=true -Bundle-Version: 1.2 +Bundle-Version: 1.3 Require-Bundle: org.eclipse.ui, org.eclipse.debug.core;bundle-version="3.10.100", org.eclipse.equinox.common;bundle-version="3.8.0", diff --git a/dk.danamlund.quicklaunch/src/dk/danamlund/quicklaunch/QuickLaunchConfigurationDialog.java b/dk.danamlund.quicklaunch/src/dk/danamlund/quicklaunch/QuickLaunchConfigurationDialog.java @@ -1,14 +1,22 @@ package dk.danamlund.quicklaunch; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.IDebugModelPresentation; import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; import org.eclipse.ui.dialogs.ElementListSelectionDialog; import org.eclipse.ui.dialogs.FilteredList; import org.eclipse.ui.dialogs.FilteredList.FilterMatcher; @@ -16,12 +24,28 @@ import org.eclipse.ui.dialogs.FilteredList.FilterMatcher; public class QuickLaunchConfigurationDialog extends ElementListSelectionDialog { private final String runMode; private Object previousSelection = null; + private List<ILaunchConfiguration> launchConfigurations; public QuickLaunchConfigurationDialog(String runMode) { super(null, new QuickLaunchConfigurationLabelProvider()); this.runMode = runMode; setBlockOnOpen(false); + + setTitle(capitalize(runMode) + " Launch Configuration"); + setMessage("Enter fuzzy pattern:"); + } + + private static String capitalize(String s) { + if (s.isEmpty()) { + return ""; + } + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + + public void setLaunchConfigurations(List<ILaunchConfiguration> launchConfigurations) { + this.launchConfigurations = launchConfigurations; + setElements(this.launchConfigurations.toArray()); } @Override @@ -46,11 +70,47 @@ public class QuickLaunchConfigurationDialog extends ElementListSelectionDialog { @Override protected FilteredList createFilteredList(Composite parent) { FilteredList list = super.createFilteredList(parent); - list.setFilterMatcher(new FuzzyFilterMatcher()); + // Set dummy filters and comparators, do everything in doFilter + list.setFilterMatcher(new TrueFilterMatcher()); + list.setComparator(new AllEqualComparator()); return list; } @Override + protected Text createFilterText(Composite parent) { + Text text = super.createFilterText(parent); + + // Dont trigger FilterList filter + for (Listener listener : text.getListeners(SWT.Modify)) { + text.removeListener(SWT.Modify, listener); + } + + text.addListener(SWT.Modify, new Listener() { + @Override + public void handleEvent(Event e) { + doFilter(text.getText()); + } + }); + + return text; + } + + private void doFilter(String pattern) { + pattern = pattern.toLowerCase(); + + List<ILaunchConfiguration> filtered = new ArrayList<>(); + for (ILaunchConfiguration launchConfig : launchConfigurations) { + if (fuzzyMatch(launchConfig.toString(), pattern)) { + filtered.add(launchConfig); + } + } + filtered.sort(new FuzzyScoreComparator(pattern)); + + // Naively update list with filtered elements. + fFilteredList.setElements(filtered.toArray()); + } + + @Override protected void okPressed() { super.okPressed(); Object[] results = getResult(); @@ -77,32 +137,72 @@ public class QuickLaunchConfigurationDialog extends ElementListSelectionDialog { /** * fuzzy 'foo' is same as regular '*f*o*o*'. */ - private static class FuzzyFilterMatcher implements FilterMatcher { - private String pattern = ""; + private static boolean fuzzyMatch(String element, String pattern) { + if (pattern.isEmpty()) { + return true; + } + String s = element.toLowerCase().trim(); + int sIndex = 0; + for (int i = 0; i < pattern.length(); i++) { + if (sIndex >= s.length()) { + return false; + } + sIndex = s.indexOf(pattern.charAt(i), sIndex); + if (sIndex < 0) { + return false; + } + sIndex++; + } + return true; + } + + private static int getFuzzyScore(String name, String filter) { + int score = 0; + int nameI = 0; + for (int filterI = 0; filterI < filter.length(); filterI++) { + int newNameI = name.indexOf(filter.charAt(filterI), nameI); + if (newNameI == nameI) { + score++; + } + nameI = newNameI + 1; + } + return score; + } + + private static class TrueFilterMatcher implements FilterMatcher { + @Override + public boolean match(Object element) { + return true; + } @Override public void setFilter(String pattern, boolean ignoreCase, boolean ignoreWildCards) { - this.pattern = pattern.toLowerCase().trim(); } + } + private static class AllEqualComparator implements Comparator<Object> { @Override - public boolean match(Object element) { - if (pattern.isEmpty()) { - return true; - } - String s = element.toString().toLowerCase().trim(); - int sIndex = 0; - for (int i = 0; i < pattern.length(); i++) { - if (sIndex >= s.length()) { - return false; - } - sIndex = s.indexOf(pattern.charAt(i), sIndex); - if (sIndex < 0) { - return false; - } - sIndex++; + public int compare(Object o1, Object o2) { + return 0; + } + } + + private static class FuzzyScoreComparator implements Comparator<Object> { + private final String pattern; + + public FuzzyScoreComparator(String pattern) { + this.pattern = pattern; + } + + @Override + public int compare(Object aObject, Object bObject) { + String a = aObject.toString().toLowerCase(); + String b = bObject.toString().toLowerCase(); + int comparison = Integer.compare(getFuzzyScore(a, pattern), getFuzzyScore(b, pattern)); + if (comparison != 0) { + return comparison; } - return true; + return a.compareTo(b); } } } diff --git a/dk.danamlund.quicklaunch/src/dk/danamlund/quicklaunch/QuickLauncher.java b/dk.danamlund.quicklaunch/src/dk/danamlund/quicklaunch/QuickLauncher.java @@ -39,7 +39,7 @@ public class QuickLauncher { launchConfigurations.add(launchConfiguration); } } - dialog.setElements(launchConfigurations.toArray()); + dialog.setLaunchConfigurations(launchConfigurations); } catch (CoreException e) { throw new IllegalStateException(e); }