Home | History | Annotate | Download | only in jline
      1 /*
      2  * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
      3  *
      4  * This software is distributable under the BSD license. See the terms of the
      5  * BSD license in the documentation provided with this software.
      6  */
      7 package jline;
      8 
      9 import java.io.*;
     10 import java.util.*;
     11 
     12 /**
     13  *  <p>
     14  *  A simple {@link Completor} implementation that handles a pre-defined
     15  *  list of completion words.
     16  *  </p>
     17  *
     18  *  <p>
     19  *  Example usage:
     20  *  </p>
     21  *  <pre>
     22  *  myConsoleReader.addCompletor (new SimpleCompletor (new String [] { "now", "yesterday", "tomorrow" }));
     23  *  </pre>
     24  *
     25  *  @author  <a href="mailto:mwp1 (at) cornell.edu">Marc Prud'hommeaux</a>
     26  */
     27 public class SimpleCompletor implements Completor, Cloneable {
     28     /**
     29      *  The list of candidates that will be completed.
     30      */
     31     SortedSet candidates;
     32 
     33     /**
     34      *  A delimiter to use to qualify completions.
     35      */
     36     String delimiter;
     37     final SimpleCompletorFilter filter;
     38 
     39     /**
     40      *  Create a new SimpleCompletor with a single possible completion
     41      *  values.
     42      */
     43     public SimpleCompletor(final String candidateString) {
     44         this(new String[] {
     45                  candidateString
     46              });
     47     }
     48 
     49     /**
     50      *  Create a new SimpleCompletor with a list of possible completion
     51      *  values.
     52      */
     53     public SimpleCompletor(final String[] candidateStrings) {
     54         this(candidateStrings, null);
     55     }
     56 
     57     public SimpleCompletor(final String[] strings,
     58                            final SimpleCompletorFilter filter) {
     59         this.filter = filter;
     60         setCandidateStrings(strings);
     61     }
     62 
     63     /**
     64      *  Complete candidates using the contents of the specified Reader.
     65      */
     66     public SimpleCompletor(final Reader reader) throws IOException {
     67         this(getStrings(reader));
     68     }
     69 
     70     /**
     71      *  Complete candidates using the whitespearated values in
     72      *  read from the specified Reader.
     73      */
     74     public SimpleCompletor(final InputStream in) throws IOException {
     75         this(getStrings(new InputStreamReader(in)));
     76     }
     77 
     78     private static String[] getStrings(final Reader in)
     79                                 throws IOException {
     80         final Reader reader =
     81             (in instanceof BufferedReader) ? in : new BufferedReader(in);
     82 
     83         List words = new LinkedList();
     84         String line;
     85 
     86         while ((line = ((BufferedReader) reader).readLine()) != null) {
     87             for (StringTokenizer tok = new StringTokenizer(line);
     88                      tok.hasMoreTokens(); words.add(tok.nextToken())) {
     89                 ;
     90             }
     91         }
     92 
     93         return (String[]) words.toArray(new String[words.size()]);
     94     }
     95 
     96     public int complete(final String buffer, final int cursor, final List clist) {
     97         String start = (buffer == null) ? "" : buffer;
     98 
     99         SortedSet matches = candidates.tailSet(start);
    100 
    101         for (Iterator i = matches.iterator(); i.hasNext();) {
    102             String can = (String) i.next();
    103 
    104             if (!(can.startsWith(start))) {
    105                 break;
    106             }
    107 
    108             if (delimiter != null) {
    109                 int index = can.indexOf(delimiter, cursor);
    110 
    111                 if (index != -1) {
    112                     can = can.substring(0, index + 1);
    113                 }
    114             }
    115 
    116             clist.add(can);
    117         }
    118 
    119         if (clist.size() == 1) {
    120             clist.set(0, ((String) clist.get(0)) + " ");
    121         }
    122 
    123         // the index of the completion is always from the beginning of
    124         // the buffer.
    125         return (clist.size() == 0) ? (-1) : 0;
    126     }
    127 
    128     public void setDelimiter(final String delimiter) {
    129         this.delimiter = delimiter;
    130     }
    131 
    132     public String getDelimiter() {
    133         return this.delimiter;
    134     }
    135 
    136     public void setCandidates(final SortedSet candidates) {
    137         if (filter != null) {
    138             TreeSet filtered = new TreeSet();
    139 
    140             for (Iterator i = candidates.iterator(); i.hasNext();) {
    141                 String element = (String) i.next();
    142                 element = filter.filter(element);
    143 
    144                 if (element != null) {
    145                     filtered.add(element);
    146                 }
    147             }
    148 
    149             this.candidates = filtered;
    150         } else {
    151             this.candidates = candidates;
    152         }
    153     }
    154 
    155     public SortedSet getCandidates() {
    156         return Collections.unmodifiableSortedSet(this.candidates);
    157     }
    158 
    159     public void setCandidateStrings(final String[] strings) {
    160         setCandidates(new TreeSet(Arrays.asList(strings)));
    161     }
    162 
    163     public void addCandidateString(final String candidateString) {
    164         final String string =
    165             (filter == null) ? candidateString : filter.filter(candidateString);
    166 
    167         if (string != null) {
    168             candidates.add(string);
    169         }
    170     }
    171 
    172     public Object clone() throws CloneNotSupportedException {
    173         return super.clone();
    174     }
    175 
    176     /**
    177      *  Filter for elements in the completor.
    178      *
    179      *  @author  <a href="mailto:mwp1 (at) cornell.edu">Marc Prud'hommeaux</a>
    180      */
    181     public static interface SimpleCompletorFilter {
    182         /**
    183          *  Filter the specified String. To not filter it, return the
    184          *  same String as the parameter. To exclude it, return null.
    185          */
    186         public String filter(String element);
    187     }
    188 
    189     public static class NoOpFilter implements SimpleCompletorFilter {
    190         public String filter(final String element) {
    191             return element;
    192         }
    193     }
    194 }
    195