Skip to content

Commit

Permalink
Merge branch 'option-completer'
Browse files Browse the repository at this point in the history
  • Loading branch information
mattirn committed Nov 19, 2019
2 parents e02d511 + 21d177a commit cb6593a
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 8 deletions.
76 changes: 69 additions & 7 deletions builtins/src/main/java/org/jline/builtins/Builtins.java
Expand Up @@ -26,6 +26,7 @@

import org.jline.builtins.Commands;
import org.jline.builtins.Completers.FilesCompleter;
import org.jline.builtins.Completers.OptionCompleter;
import org.jline.builtins.Completers.SystemCompleter;
import org.jline.builtins.TTop;
import org.jline.builtins.Options.HelpException;
Expand Down Expand Up @@ -223,7 +224,43 @@ public CmdDesc commandDescription(String command) {
main.add(HelpException.highlightSyntax(s.trim(), HelpException.defaultStyle()));
}
}
out = new CmdDesc(main, ArgDesc.doArgNames(Arrays.asList("[pN...]")), options);
out = new CmdDesc(main, ArgDesc.doArgNames(Arrays.asList("")), options);
} catch (Exception e) {

}
return out;
}

private Map<String,String> commandOptions(String command) {
Map<String,String> out = new HashMap<>();
List<String> args = Arrays.asList("--help");
try {
execute(command, args);
} catch (HelpException e) {
String[] msg = e.getMessage().replaceAll("\r\n", "\n").replaceAll("\r", "\n").split("\n");
boolean start = false;
for (String s: msg) {
if (!start) {
if (s.trim().startsWith("Usage: ")) {
s = s.split("Usage:")[1];
start = true;
} else {
continue;
}
}
if (s.matches("^\\s+-.*$")) {
int ind = s.lastIndexOf(" ");
if (ind > 0) {
String op = s.substring(0, ind).trim();
String d = s.substring(ind).trim();
if (op.length() > 0) {
for (String o: op.split("\\s+")) {
out.put(o, d);
}
}
}
}
}
} catch (Exception e) {

}
Expand Down Expand Up @@ -331,26 +368,43 @@ private Set<String> allWidgets() {

private List<Completer> nanoCompleter(String name) {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(new StringsCompleter(name), new FilesCompleter(workDir.get(), true)));
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new OptionCompleter(new FilesCompleter(workDir.get(), true)
, this::commandOptions
, 1)
));
return completers;
}

private List<Completer> lessCompleter(String name) {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(new StringsCompleter(name), new FilesCompleter(workDir.get(), true)));
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new OptionCompleter(new FilesCompleter(workDir.get(), true)
, this::commandOptions
, 1)
));
return completers;
}

private List<Completer> historyCompleter(String name) {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(new StringsCompleter(name), new NullCompleter()));
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new StringsCompleter(Arrays.asList("-A", "-W", "-R")), new FilesCompleter(workDir.get(), true), new NullCompleter()));
, new OptionCompleter(new NullCompleter()
, this::commandOptions
, 1)
));
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new StringsCompleter(Arrays.asList("-A", "-W", "-R", "-AI", "-RI", "-WI")), new FilesCompleter(workDir.get(), true), new NullCompleter()));
return completers;
}

private List<Completer> widgetCompleter(String name) {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new OptionCompleter(new NullCompleter()
, this::commandOptions
, 1)
));
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new StringsCompleter("-A"), new StringsCompleter(() -> allWidgets())
, new StringsCompleter(() -> reader.getWidgets().keySet()), new NullCompleter()));
Expand All @@ -361,7 +415,11 @@ private List<Completer> widgetCompleter(String name) {

private List<Completer> keymapCompleter(String name) {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(new StringsCompleter(name), new NullCompleter()));
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new OptionCompleter(new NullCompleter()
, this::commandOptions
, 1)
));
return completers;
}

Expand All @@ -388,7 +446,11 @@ private List<Completer> unsetoptCompleter(String name) {

private List<Completer> ttopCompleter(String name) {
List<Completer> completers = new ArrayList<>();
completers.add(new ArgumentCompleter(new StringsCompleter(name), new NullCompleter()));
completers.add(new ArgumentCompleter(new StringsCompleter(name)
, new OptionCompleter(new NullCompleter()
, this::commandOptions
, 1)
));
return completers;
}

Expand Down
121 changes: 121 additions & 0 deletions builtins/src/main/java/org/jline/builtins/Completers.java
Expand Up @@ -678,4 +678,125 @@ public Map<String,List<org.jline.reader.Completer>> getCompleters() {
}
}

public static class OptionCompleter implements org.jline.reader.Completer {
private Map<String,List<String>> optionValues = new HashMap<>();
private List<String> options = new ArrayList<String>();
private Function<String,Map<String,String>> commandOptions;
private List<org.jline.reader.Completer> argsCompleters = new ArrayList<>();
private int startPos;

public OptionCompleter(org.jline.reader.Completer completer, Function<String,Map<String,String>> commandOptions, int startPos) {
this.startPos = startPos;
this.commandOptions = commandOptions;
this.argsCompleters.add(completer);
}

public OptionCompleter(List<org.jline.reader.Completer> completers, Function<String,Map<String,String>> commandOptions, int startPos) {
this.startPos = startPos;
this.commandOptions = commandOptions;
this.argsCompleters = new ArrayList<>(completers);
}

public OptionCompleter(List<org.jline.reader.Completer> completers, Map<String,List<String>> optionValues, Collection<String> options, int startPos) {
this(optionValues, options, startPos);
this.argsCompleters = new ArrayList<>(completers);
}

public OptionCompleter(org.jline.reader.Completer completer, Map<String,List<String>> optionValues, Collection<String> options, int startPos) {
this(optionValues, options, startPos);
this.argsCompleters.add(completer);
}

private OptionCompleter(Map<String,List<String>> optionValues, Collection<String> options, int startPos) {
this.optionValues = new HashMap<>(optionValues);
this.options.addAll(options);
this.startPos = startPos;
}

@Override
public void complete(LineReader reader, final ParsedLine commandLine, List<Candidate> candidates) {
assert commandLine != null;
assert candidates != null;
List<String> words = commandLine.words();
String buffer = commandLine.word().substring(0, commandLine.wordCursor());
if (buffer.startsWith("-")) {
boolean addbuff = true;
boolean valueCandidates = false;
if (commandOptions != null) {
boolean longOption = buffer.startsWith("--");
for (Map.Entry<String,String> entry: commandOptions.apply(words.get(0)).entrySet()) {
if (entry.getKey().startsWith(buffer)) {
addbuff = false;
}
if ((!longOption && !entry.getKey().startsWith("--")) || longOption) {
candidates.add(new Candidate(entry.getKey(), entry.getKey(), null, entry.getValue(), null, null, true));
}
}
} else {
int eq = buffer.indexOf('=');
if (eq < 0) {
List<String> usedOptions = new ArrayList<>();
for (int i = startPos; i < words.size(); i++) {
if (words.get(i).startsWith("-")) {
String w = words.get(i);
int ind = w.indexOf('=');
if (ind < 0) {
usedOptions.add(w);
} else {
usedOptions.add(w.substring(0,ind));
}
}
}
for (String o: optionValues.keySet()) {
if (usedOptions.contains(o)) {
continue;
}
if (o.startsWith(buffer)) {
addbuff = false;
}
candidates.add(new Candidate(o+"=", o, null, null, null, null, false));
}
for (String o: options) {
if (usedOptions.contains(o)) {
continue;
}
if (o.startsWith(buffer)) {
addbuff = false;
}
candidates.add(new Candidate(o, o, null, null, null, null, true));
}
} else {
String value = buffer.substring(eq + 1);
String curBuf = buffer.substring(0, eq + 1);
String opt = buffer.substring(0, eq);
if (optionValues.containsKey(opt) && !optionValues.get(opt).isEmpty()) {
for (String v: optionValues.get(opt)) {
if (v.startsWith(value)) {
valueCandidates = true;
addbuff = false;
}
candidates.add(new Candidate(curBuf+v, v, null, null, null, null, true));
}
}
}
}
if ((buffer.contains("=") && !buffer.endsWith("=") && !valueCandidates) || addbuff) {
candidates.add(new Candidate(buffer, buffer, null, null, null, null, true));
}
} else if (argsCompleters.size() > 1) {
int args = 0;
for (int i = startPos; i < words.size(); i++) {
if (!words.get(i).startsWith("-")) {
args++;
}
}
if (args < argsCompleters.size()) {
argsCompleters.get(args).complete(reader, commandLine, candidates);
}
} else {
argsCompleters.get(0).complete(reader, commandLine, candidates);
}
}
}

}
13 changes: 12 additions & 1 deletion builtins/src/main/java/org/jline/builtins/Widgets.java
Expand Up @@ -816,9 +816,14 @@ private void doCommandTailTip(String widget, CmdDesc cmdDesc, List<String> args)
}
}
String lastArg = !prevChar().equals(" ") ? args.get(args.size() - 1) : "";
if (lastArg.startsWith("-")) {
}
int bpsize = argnum;
boolean doTailTip = true;
boolean noCompleters = false;
if (widget.endsWith(LineReader.BACKWARD_DELETE_CHAR)) {
setSuggestionType(SuggestionType.TAIL_TIP);
noCompleters = true;
if (!lastArg.startsWith("-")) {
bpsize--;
}
Expand All @@ -831,10 +836,16 @@ private void doCommandTailTip(String widget, CmdDesc cmdDesc, List<String> args)
if (cmdDesc != null) {
if (lastArg.startsWith("-")) {
doDescription(cmdDesc.getOptionDescription(lastArg, descriptionSize));
setSuggestionType(SuggestionType.TAIL_TIP);
noCompleters = true;
} else if (!widget.endsWith(LineReader.BACKWARD_DELETE_CHAR)){
setTipType(tipType);
}
if (bpsize > 0 && doTailTip) {
List<ArgDesc> params = cmdDesc.getArgsDesc();
setSuggestionType(tipType == TipType.COMPLETER ? SuggestionType.COMPLETER : SuggestionType.TAIL_TIP);
if (!noCompleters) {
setSuggestionType(tipType == TipType.COMPLETER ? SuggestionType.COMPLETER : SuggestionType.TAIL_TIP);
}
if (bpsize - 1 < params.size()) {
if (!lastArg.startsWith("-")) {
List<AttributedString> d = params.get(bpsize - 1)
Expand Down

0 comments on commit cb6593a

Please sign in to comment.