2016-01-25 11 views
6

Mi chiedevo come avrei potuto implementare un ArgumentCompleter in modo tale che se avessi completato un comando completo e valido, avrebbe iniziato il completamento della scheda per un nuovo comando.Utilizzare JLine per completare più comandi su una riga

avrei pensato che potrebbe essere costruito facendo qualcosa di simile:

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(); 

Tuttavia in questo momento questo smette di funzionare dopo scheda completeing la prima foo bar

È chiunque abbastanza familiarità con la libreria per dirmi come andrei a implementare questo? O c'è un modo noto per fare questo che mi manca? Anche questo sta usando JLine2.

risposta

4

Questo è stato un compito :-)

E 'gestita dal completer che si sta utilizzando. Il metodo complete() del compilatore deve utilizzare per la ricerca solo ciò che viene dopo l'ultimo spazio vuoto.

Se si guarda ad esempio al FileNameCompleter della biblioteca: ciò non viene fatto a tutti, in modo da trovare senza il completamento, in quanto le ricerche Completer per <input1> <input2> e non solo per <input2> :-)

Avrete devi fare la tua implementazione di un completatore che è in grado di trovare input2.

Inoltre il CompletionHandler deve aggiungere ciò che hai trovato a ciò che hai già digitato.

Ecco un'implementazione di base che cambia il default 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(); 
    } 

E qui la complete() -Metodo del CompletionHandler cambiare il default 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; 
    } 
+0

Hmm ,. quindi questo cambierà più di quanto pensassi. Grazie per l'intuizione! – flakes

+0

Almeno sembra che non puoi attivarlo con qualche configurazione. Ma puoi realizzare un'implementazione standard e ereditarla per le tue prossime classi. –

Problemi correlati