Используйте JLine для выполнения нескольких команд в одной строке
Мне было интересно, как я мог бы реализовать ArgumentCompleter
такой, что если я выполню полную и действительную команду, то начнется заполнение табуляции для новой команды.
Я бы предположил, что это может быть построено, делая что-то вроде этого:
final ConsoleReader consoleReader = new ConsoleReader()
final ArgumentCompleter cyclicalArgument = new ArgumentCompleter();
cyclicalArgument.getCompleters().addAll(Arrays.asList(
new StringsCompleter("foo"),
new StringsCompleter("bar"),
cyclicalArgument));
consoleReader.addCompleter(cyclicalArgument);
consoleReader.readLine();
Однако сейчас это перестает работать после завершения первой вкладки foo bar
Кто-нибудь достаточно знаком с библиотекой, чтобы сказать мне, как я буду реализовывать это? Или есть известный способ сделать это, что мне не хватает? Также это использует JLine2.
1 ответ
Это было довольно сложно:-)
Он обрабатывается завершителем, который вы используете. complete()
Метод завершителя должен использовать для поиска только то, что следует за последним пробелом.
Если вы посмотрите, например, на FileNameCompleter
библиотеки: это не сделано вообще, поэтому вы не найдете завершения, потому что завершитель ищет <input1> <input2>
и не только для <input2>
:-)
Вы должны будете сделать свою собственную реализацию завершителя, который сможет найти input2.
Дополнительно CompletionHandler
должен добавить то, что вы нашли к тому, что вы уже набрали.
Вот базовая реализация, изменяющая значение по умолчанию FileNameCompleter
:
protected int matchFiles(final String buffer, final String translated, final File[] files,
final List<CharSequence> candidates) {
// THIS IS NEW
String[] allWords = translated.split(" ");
String lastWord = allWords[allWords.length - 1];
// the lastWord is used when searching the files now
// ---
if (files == null) {
return -1;
}
int matches = 0;
// first pass: just count the matches
for (File file : files) {
if (file.getAbsolutePath().startsWith(lastWord)) {
matches++;
}
}
for (File file : files) {
if (file.getAbsolutePath().startsWith(lastWord)) {
CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? this.separator() : " ");
candidates.add(this.render(file, name).toString());
}
}
final int index = buffer.lastIndexOf(this.separator());
return index + this.separator().length();
}
И здесь complete()
-Метод из CompletionHandler
изменение по умолчанию CandidateListCompletionHandler
:
@Override
public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos)
throws IOException {
CursorBuffer buf = reader.getCursorBuffer();
// THIS IS NEW
String[] allWords = buf.toString().split(" ");
String firstWords = "";
if (allWords.length > 1) {
for (int i = 0; i < allWords.length - 1; i++) {
firstWords += allWords[i] + " ";
}
}
//-----
// if there is only one completion, then fill in the buffer
if (candidates.size() == 1) {
String value = Ansi.stripAnsi(candidates.get(0).toString());
if (buf.cursor == buf.buffer.length() && this.printSpaceAfterFullCompletion && !value.endsWith(" ")) {
value += " ";
}
// fail if the only candidate is the same as the current buffer
if (value.equals(buf.toString())) {
return false;
}
CandidateListCompletionHandler.setBuffer(reader, firstWords + " " + value, pos);
return true;
} else if (candidates.size() > 1) {
String value = this.getUnambiguousCompletions(candidates);
CandidateListCompletionHandler.setBuffer(reader, value, pos);
}
CandidateListCompletionHandler.printCandidates(reader, candidates);
// redraw the current console buffer
reader.drawLine();
return true;
}