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