blob: f84c8a9002af8c099bd8018882801974a1e4cff6 [file] [log] [blame]
/*
* Copyright (c) 2002-2019, the original author or authors.
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* https://opensource.org/licenses/BSD-3-Clause
*/
package jdk.internal.org.jline.reader.impl.completer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import jdk.internal.org.jline.reader.Candidate;
import jdk.internal.org.jline.reader.Completer;
import jdk.internal.org.jline.reader.LineReader;
import jdk.internal.org.jline.reader.ParsedLine;
/**
* A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator</i> argument.
* This can be used instead of the individual completers having to know about argument parsing semantics.
*
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
* @since 2.3
*/
public class ArgumentCompleter implements Completer
{
private final List<Completer> completers = new ArrayList<>();
private boolean strict = true;
private boolean strictCommand = true;
/**
* Create a new completer.
*
* @param completers The embedded completers
*/
public ArgumentCompleter(final Collection<Completer> completers) {
Objects.requireNonNull(completers);
this.completers.addAll(completers);
}
/**
* Create a new completer.
*
* @param completers The embedded completers
*/
public ArgumentCompleter(final Completer... completers) {
this(Arrays.asList(completers));
}
/**
* If true, a completion at argument index N will only succeed
* if all the completions from 0-(N-1) also succeed.
*
* @param strict the strict flag
*/
public void setStrict(final boolean strict) {
this.strict = strict;
}
/**
* If true, a completion at argument index N will only succeed
* if all the completions from 1-(N-1) also succeed.
*
* @param strictCommand the strictCommand flag
*/
public void setStrictCommand(final boolean strictCommand) {
this.strictCommand = strictCommand;
}
/**
* Returns whether a completion at argument index N will success
* if all the completions from arguments 0-(N-1) also succeed.
*
* @return True if strict.
* @since 2.3
*/
public boolean isStrict() {
return this.strict;
}
/**
* Returns the list of completers used inside this <code>ArgumentCompleter</code>.
* @return The list of completers.
* @since 2.3
*/
public List<Completer> getCompleters() {
return completers;
}
public void complete(LineReader reader, ParsedLine line, final List<Candidate> candidates) {
Objects.requireNonNull(line);
Objects.requireNonNull(candidates);
if (line.wordIndex() < 0) {
return;
}
List<Completer> completers = getCompleters();
Completer completer;
// if we are beyond the end of the completers, just use the last one
if (line.wordIndex() >= completers.size()) {
completer = completers.get(completers.size() - 1);
}
else {
completer = completers.get(line.wordIndex());
}
// ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
for (int i = strictCommand ? 0 : 1; isStrict() && (i < line.wordIndex()); i++) {
int idx = i >= completers.size() ? (completers.size() - 1) : i;
if (idx == 0 && !strictCommand) {
continue;
}
Completer sub = completers.get(idx);
List<? extends CharSequence> args = line.words();
String arg = (args == null || i >= args.size()) ? "" : args.get(i).toString();
List<Candidate> subCandidates = new LinkedList<>();
sub.complete(reader, new ArgumentLine(arg, arg.length()), subCandidates);
boolean found = false;
for (Candidate cand : subCandidates) {
if (cand.value().equals(arg)) {
found = true;
break;
}
}
if (!found) {
return;
}
}
completer.complete(reader, line, candidates);
}
public static class ArgumentLine implements ParsedLine {
private final String word;
private final int cursor;
public ArgumentLine(String word, int cursor) {
this.word = word;
this.cursor = cursor;
}
@Override
public String word() {
return word;
}
@Override
public int wordCursor() {
return cursor;
}
@Override
public int wordIndex() {
return 0;
}
@Override
public List<String> words() {
return Collections.singletonList(word);
}
@Override
public String line() {
return word;
}
@Override
public int cursor() {
return cursor;
}
}
}