001: /*
002: * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
003: *
004: * This software is distributable under the BSD license. See the terms of the
005: * BSD license in the documentation provided with this software.
006: */
007: package jline;
008:
009: import java.io.*;
010: import java.util.*;
011:
012: /**
013: * <p>
014: * A simple {@link Completor} implementation that handles a pre-defined
015: * list of completion words.
016: * </p>
017: *
018: * <p>
019: * Example usage:
020: * </p>
021: * <pre>
022: * myConsoleReader.addCompletor (new SimpleCompletor (new String [] { "now", "yesterday", "tomorrow" }));
023: * </pre>
024: *
025: * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
026: */
027: public class SimpleCompletor implements Completor, Cloneable {
028: /**
029: * The list of candidates that will be completed.
030: */
031: SortedSet candidates;
032:
033: /**
034: * A delimiter to use to qualify completions.
035: */
036: String delimiter;
037: final SimpleCompletorFilter filter;
038:
039: /**
040: * Create a new SimpleCompletor with a single possible completion
041: * values.
042: */
043: public SimpleCompletor(final String candidateString) {
044: this (new String[] { candidateString });
045: }
046:
047: /**
048: * Create a new SimpleCompletor with a list of possible completion
049: * values.
050: */
051: public SimpleCompletor(final String[] candidateStrings) {
052: this (candidateStrings, null);
053: }
054:
055: public SimpleCompletor(final String[] strings,
056: final SimpleCompletorFilter filter) {
057: this .filter = filter;
058: setCandidateStrings(strings);
059: }
060:
061: /**
062: * Complete candidates using the contents of the specified Reader.
063: */
064: public SimpleCompletor(final Reader reader) throws IOException {
065: this (getStrings(reader));
066: }
067:
068: /**
069: * Complete candidates using the whitespearated values in
070: * read from the specified Reader.
071: */
072: public SimpleCompletor(final InputStream in) throws IOException {
073: this (getStrings(new InputStreamReader(in)));
074: }
075:
076: private static String[] getStrings(final Reader in)
077: throws IOException {
078: final Reader reader = (in instanceof BufferedReader) ? in
079: : new BufferedReader(in);
080:
081: List words = new LinkedList();
082: String line;
083:
084: while ((line = ((BufferedReader) reader).readLine()) != null) {
085: for (StringTokenizer tok = new StringTokenizer(line); tok
086: .hasMoreTokens(); words.add(tok.nextToken())) {
087: ;
088: }
089: }
090:
091: return (String[]) words.toArray(new String[words.size()]);
092: }
093:
094: public int complete(final String buffer, final int cursor,
095: final List clist) {
096: String start = (buffer == null) ? "" : buffer;
097:
098: SortedSet matches = candidates.tailSet(start);
099:
100: for (Iterator i = matches.iterator(); i.hasNext();) {
101: String can = (String) i.next();
102:
103: if (!(can.startsWith(start))) {
104: break;
105: }
106:
107: if (delimiter != null) {
108: int index = can.indexOf(delimiter, cursor);
109:
110: if (index != -1) {
111: can = can.substring(0, index + 1);
112: }
113: }
114:
115: clist.add(can);
116: }
117:
118: if (clist.size() == 1) {
119: clist.set(0, ((String) clist.get(0)) + " ");
120: }
121:
122: // the index of the completion is always from the beginning of
123: // the buffer.
124: return (clist.size() == 0) ? (-1) : 0;
125: }
126:
127: public void setDelimiter(final String delimiter) {
128: this .delimiter = delimiter;
129: }
130:
131: public String getDelimiter() {
132: return this .delimiter;
133: }
134:
135: public void setCandidates(final SortedSet candidates) {
136: if (filter != null) {
137: TreeSet filtered = new TreeSet();
138:
139: for (Iterator i = candidates.iterator(); i.hasNext();) {
140: String element = (String) i.next();
141: element = filter.filter(element);
142:
143: if (element != null) {
144: filtered.add(element);
145: }
146: }
147:
148: this .candidates = filtered;
149: } else {
150: this .candidates = candidates;
151: }
152: }
153:
154: public SortedSet getCandidates() {
155: return Collections.unmodifiableSortedSet(this .candidates);
156: }
157:
158: public void setCandidateStrings(final String[] strings) {
159: setCandidates(new TreeSet(Arrays.asList(strings)));
160: }
161:
162: public void addCandidateString(final String candidateString) {
163: final String string = (filter == null) ? candidateString
164: : filter.filter(candidateString);
165:
166: if (string != null) {
167: candidates.add(string);
168: }
169: }
170:
171: public Object clone() throws CloneNotSupportedException {
172: return super .clone();
173: }
174:
175: /**
176: * Filter for elements in the completor.
177: *
178: * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
179: */
180: public static interface SimpleCompletorFilter {
181: /**
182: * Filter the specified String. To not filter it, return the
183: * same String as the parameter. To exclude it, return null.
184: */
185: public String filter(String element);
186: }
187:
188: public static class NoOpFilter implements SimpleCompletorFilter {
189: public String filter(final String element) {
190: return element;
191: }
192: }
193: }
|