Используйте 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;
   }
Другие вопросы по тегам