Skip to content

Commit 7102a2c

Browse files
committed
Completion list: Implement 'fuzzy search' with sorted hits
This is currently only applied to methods and fields, not imports
1 parent 9c3567b commit 7102a2c

1 file changed

Lines changed: 43 additions & 4 deletions

File tree

src/main/java/sc/fiji/jython/autocompletion/JythonAutoCompletions.java

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,23 @@
2828
import java.nio.file.Path;
2929
import java.util.ArrayList;
3030
import java.util.Collections;
31+
import java.util.Comparator;
3132
import java.util.List;
33+
import java.util.Optional;
3234
import java.util.function.Function;
3335
import java.util.jar.JarEntry;
3436
import java.util.jar.JarFile;
3537
import java.util.regex.Matcher;
3638
import java.util.regex.Pattern;
3739
import java.util.stream.Collectors;
3840

41+
import org.fife.ui.autocomplete.AbstractCompletion;
3942
import org.fife.ui.autocomplete.BasicCompletion;
4043
import org.fife.ui.autocomplete.Completion;
4144
import org.fife.ui.autocomplete.CompletionProvider;
4245
import org.python.indexer.types.NModuleType;
4346
import org.scijava.ui.swing.script.autocompletion.AutoCompletionListener;
47+
import org.scijava.ui.swing.script.autocompletion.ClassUtil;
4448
import org.scijava.ui.swing.script.autocompletion.JythonAutocompletionProvider;
4549

4650
public class JythonAutoCompletions implements AutoCompletionListener
@@ -252,12 +256,47 @@ public List<Completion> completionsFor(final CompletionProvider provider, String
252256
JythonScriptParser.print("codeWithoutLastLine:\n" + codeWithoutLastLine);
253257
}
254258
final DotAutocompletions da = JythonScriptParser.parseAST(code).getLast().find(varName, DotAutocompletions.EMPTY);
255-
return da.get().stream()
256-
.filter(s -> s.startsWith(seed))
257-
.map(s -> new BasicCompletion(provider, lastLine.substring(crop) + s.substring(seed.length()), null, da.getClassname()))
259+
final String lowerCaseSeed = seed.toLowerCase();
260+
List<Completion> list = da.get().stream()
261+
.filter(s -> s.getReplacementText().toLowerCase().contains(lowerCaseSeed))
262+
.map(s -> s.getCompletion(provider, lastLine.substring(crop) + s.getReplacementText().substring(seed.length())))
258263
.collect(Collectors.toList());
264+
sortCompletions(list, lowerCaseSeed);
265+
return list;
259266
}
260-
267+
261268
return Collections.emptyList();
262269
}
270+
271+
@SuppressWarnings("unused")
272+
private static String removeLastOptionalDot(final String s) {
273+
System.out.println("removeLastOptionalDot input: " + s);
274+
return (s != null && s.endsWith(".")) ? s.substring(0, s.length() - 1) : s;
275+
}
276+
277+
/**
278+
* NB: Case-insensitive sorting
279+
* @param completions The list of completions
280+
* @param pre the text just before the current caret position that could
281+
* be the start of something auto-completable.
282+
*/
283+
private void sortCompletions(final List<Completion> completions, final String pre) {
284+
Collections.sort(completions, new Comparator<Completion>() {
285+
int prefix1Index = Integer.MAX_VALUE;
286+
int prefix2Index = Integer.MAX_VALUE;
287+
@Override
288+
public int compare(final Completion o1, final Completion o2) {
289+
prefix1Index = Integer.MAX_VALUE;
290+
prefix2Index = Integer.MAX_VALUE;
291+
if (o1.getReplacementText().toLowerCase().startsWith(pre))
292+
prefix1Index = 0;
293+
if (o2.getReplacementText().toLowerCase().startsWith(pre))
294+
prefix2Index = 0;
295+
if (prefix1Index == prefix2Index)
296+
return o1.compareTo(o2);
297+
else
298+
return prefix1Index - prefix2Index;
299+
}
300+
});
301+
}
263302
}

0 commit comments

Comments
 (0)