View Javadoc

1   /**
2    *	jline - Java console input library
3    *	Copyright (c) 2002, 2003, 2004, 2005, Marc Prud'hommeaux <mwp1@cornell.edu>
4    *	All rights reserved.
5    *
6    *	Redistribution and use in source and binary forms, with or
7    *	without modification, are permitted provided that the following
8    *	conditions are met:
9    *
10   *	Redistributions of source code must retain the above copyright
11   *	notice, this list of conditions and the following disclaimer.
12   *
13   *	Redistributions in binary form must reproduce the above copyright
14   *	notice, this list of conditions and the following disclaimer
15   *	in the documentation and/or other materials provided with
16   *	the distribution.
17   *
18   *	Neither the name of JLine nor the names of its contributors
19   *	may be used to endorse or promote products derived from this
20   *	software without specific prior written permission.
21   *
22   *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23   *	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24   *	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25   *	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
26   *	EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
27   *	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
28   *	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29   *	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30   *	DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31   *	AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32   *	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33   *	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34   *	OF THE POSSIBILITY OF SUCH DAMAGE.
35   */
36  package jline;
37  
38  import java.io.*;
39  import java.util.*;
40  
41  
42  /**
43   *	<p>
44   *  A simple {@link Completor} implementation that handles a pre-defined
45   *  list of completion words.
46   *  </p>
47   *
48   *	<p>
49   *  Example usage:
50   *  </p>
51   *  <pre>
52   *  myConsoleReader.addCompletor (new SimpleCompletor (new String [] { "now", "yesterday", "tomorrow" }));
53   *  </pre>
54   *
55   *  @author  <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
56   */
57  public class SimpleCompletor
58  	implements Completor, Cloneable
59  {
60  	/**
61  	 *  The list of candidates that will be completed.
62  	 */
63  	SortedSet candidates;
64  
65  
66  	/**
67  	 *  A delimiter to use to qualify completions.
68  	 */
69  	String delimiter;
70  
71  	final SimpleCompletorFilter filter;
72  
73  
74  	/**
75  	 *  Create a new SimpleCompletor with a single possible completion
76  	 *  values.
77  	 */
78  	public SimpleCompletor (final String candidateString)
79  	{
80  		this (new String [] { candidateString });
81  	}
82  
83  
84  	/**
85  	 *  Create a new SimpleCompletor with a list of possible completion
86  	 *  values.
87  	 */
88  	public SimpleCompletor (final String [] candidateStrings)
89  	{
90  		this (candidateStrings, null);
91  	}
92  
93  
94  	public SimpleCompletor (final String[] strings,
95  		final SimpleCompletorFilter filter)
96  	{
97  		this.filter = filter;
98  		setCandidateStrings (strings);
99  	}
100 
101 
102 	/**
103 	 *  Complete candidates using the contents of the specified Reader.
104 	 */
105 	public SimpleCompletor (final Reader reader)
106 		throws IOException
107 	{
108 		this (getStrings (reader));
109 	}
110 
111 
112 	/**
113 	 *  Complete candidates using the whitespearated values in
114 	 *  read from the specified Reader.
115 	 */
116 	public SimpleCompletor (final InputStream in)
117 		throws IOException
118 	{
119 		this (getStrings (new InputStreamReader (in)));
120 	}
121 
122 
123 	private static String [] getStrings (final Reader in)
124 		throws IOException
125 	{
126 		final Reader reader = in instanceof BufferedReader
127 			? in
128 			: new BufferedReader (in);
129 
130 		List words = new LinkedList ();
131 		String line;
132 		while ((line = ((BufferedReader)reader).readLine ()) != null)
133 		{
134 			for (StringTokenizer tok = new StringTokenizer (line);
135 				tok.hasMoreTokens (); words.add (tok.nextToken ()));
136 		}
137 
138 		return (String [])words.toArray (new String [words.size ()]);
139 	}
140 
141 
142 	public int complete (final String buffer, final int cursor,
143 		final List clist)
144 	{
145 		String start = buffer == null ? "" : buffer;
146 
147 		SortedSet matches = candidates.tailSet (start);
148 		for (Iterator i = matches.iterator (); i.hasNext (); )
149 		{
150 			String can = (String)i.next ();
151 			if (!(can.startsWith (start)))
152 				break;
153 
154 			if (delimiter != null)
155 			{
156 				int index = can.indexOf (delimiter, cursor);
157 				if (index != -1)
158 					can = can.substring (0, index + 1);
159 			}
160 			clist.add (can);
161 		}
162 
163 		if (clist.size () == 1)
164 			clist.set (0, ((String)clist.get (0)) + " ");
165 
166 		// the index of the completion is always from the beginning of
167 		// the buffer.
168 		return clist.size () == 0 ? -1 : 0;
169 	}
170 
171 
172 	public void setDelimiter (final String delimiter)
173 	{
174 		this.delimiter = delimiter;
175 	}
176 
177 
178 	public String getDelimiter ()
179 	{
180 		return this.delimiter;
181 	}
182 
183 
184 
185 	public void setCandidates (final SortedSet candidates)
186 	{
187 		if (filter != null)
188 		{
189 			TreeSet filtered = new TreeSet ();
190 			for (Iterator i = candidates.iterator (); i.hasNext (); )
191 			{
192 				String element = (String)i.next ();
193 				element = filter.filter (element);
194 				if (element != null)
195 					filtered.add (element);
196 			}
197 
198 			this.candidates = filtered;
199 		}
200 		else
201 		{
202 			this.candidates = candidates;
203 		}
204 	}
205 
206 
207 	public SortedSet getCandidates ()
208 	{
209 		return Collections.unmodifiableSortedSet (this.candidates);
210 	}
211 
212 
213 	public void setCandidateStrings (final String[] strings)
214 	{
215 		setCandidates (new TreeSet (Arrays.asList (strings)));
216 	}
217 
218 
219 	public void addCandidateString (final String candidateString)
220 	{
221 		final String string = filter == null
222 			? candidateString
223 			: filter.filter (candidateString);
224 
225 		if (string != null)
226 			candidates.add (string);
227 	}
228 
229 
230 	public Object clone ()
231 		throws CloneNotSupportedException
232 	{
233 		return super.clone ();
234 	}
235 
236 
237 	/**
238 	 *  Filter for elements in the completor.
239 	 *
240 	 *  @author  <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
241 	 */
242 	public static interface SimpleCompletorFilter
243 	{
244 		/**
245 		 *  Filter the specified String. To not filter it, return the
246 		 *  same String as the parameter. To exclude it, return null.
247 		 */
248 		public String filter (String element);
249 	}
250 
251 
252 	public static class NoOpFilter
253 		implements SimpleCompletorFilter
254 	{
255 		public String filter (final String element)
256 		{
257 			return element;
258 		}
259 	}
260 }