001    package org.crsh.processor.jline;
002    
003    import jline.console.ConsoleReader;
004    import jline.console.completer.Completer;
005    import org.crsh.cmdline.CommandCompletion;
006    import org.crsh.cmdline.Delimiter;
007    import org.crsh.cmdline.spi.ValueCompletion;
008    import org.crsh.shell.Shell;
009    import org.crsh.shell.ShellProcess;
010    import org.crsh.shell.ShellResponse;
011    
012    import java.io.IOException;
013    import java.io.PrintWriter;
014    import java.util.List;
015    import java.util.Map;
016    import java.util.concurrent.atomic.AtomicReference;
017    
018    /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
019    public class JLineProcessor implements Runnable, Completer {
020    
021      /** . */
022      private final Shell shell;
023    
024      /** . */
025      final ConsoleReader reader;
026    
027      /** . */
028      final PrintWriter writer;
029    
030      /** . */
031      final AtomicReference<ShellProcess> current;
032    
033      public JLineProcessor(Shell shell, ConsoleReader reader, PrintWriter writer) {
034        this.shell = shell;
035        this.reader = reader;
036        this.writer = writer;
037        this.current = new AtomicReference<ShellProcess>();
038      }
039    
040      public void run() {
041    
042        //
043        String welcome = shell.getWelcome();
044        writer.println(welcome);
045        writer.flush();
046    
047        //
048        while (true) {
049          String prompt = getPrompt();
050          String line;
051          try {
052            writer.println();
053            writer.flush();
054            if ((line = reader.readLine(prompt)) == null) {
055              break;
056            }
057          }
058          catch (IOException e) {
059            // What should we do other than that ?
060            break;
061          }
062    
063          //
064          ShellProcess process = shell.createProcess(line);
065          JLineProcessContext context = new JLineProcessContext(this);
066          current.set(process);
067          try {
068            process.execute(context);
069            try {
070              context.latch.await();
071            }
072            catch (InterruptedException ignore) {
073              // At the moment
074            }
075          }
076          finally {
077            current.set(null);
078          }
079          ShellResponse response = context.resp.get();
080    
081          //
082          if (response instanceof ShellResponse.Cancelled) {
083            // Do nothing
084          } else if (response instanceof ShellResponse.Close) {
085            break;
086          } else {
087            response.getReader().writeAnsiTo(writer);
088            writer.flush();
089          }
090        }
091      }
092    
093      public int complete(String buffer, int cursor, List<CharSequence> candidates) {
094        String prefix = buffer.substring(0, cursor);
095        CommandCompletion completion = shell.complete(prefix);
096        ValueCompletion vc = completion.getValue();
097        if (vc.isEmpty()) {
098          return -1;
099        }
100        Delimiter delimiter = completion.getDelimiter();
101        for (Map.Entry<String, Boolean> entry : vc) {
102          StringBuilder sb = new StringBuilder();
103          sb.append(vc.getPrefix());
104          try {
105            delimiter.escape(entry.getKey(), sb);
106            if (entry.getValue()) {
107              sb.append(completion.getDelimiter().getValue());
108            }
109            candidates.add(sb.toString());
110          }
111          catch (IOException ignore) {
112          }
113        }
114        return cursor - vc.getPrefix().length();
115      }
116    
117      public void cancel() {
118        ShellProcess process = current.get();
119        if (process != null) {
120          process.cancel();
121        } else {
122          writer.println();
123          writer.print(getPrompt());
124          writer.flush();
125        }
126      }
127    
128      String getPrompt() {
129        String prompt = shell.getPrompt();
130        return prompt == null ? "% " : prompt;
131      }
132    }