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   *  A file name completor takes the buffer and issues a list of
44   *  potential completions.
45   *
46   *	<p>
47   *	This completor tries to behave as similar as possible to
48   *	<i>bash</i>'s file name completion (using GNU readline)
49   *	with the following exceptions:
50   *
51   *	<ul>
52   *	<li>Candidates that are directories will end with "/"</li>
53   *	<li>Wildcard regular expressions are not evaluated or replaced</li>
54   *	<li>The "~" character can be used to represent the user's home,
55   *		but it cannot complete to other users' homes, since java does
56   *		not provide any way of determining that easily</li>
57   *	</ul>
58   *
59   *	<p>TODO</p>
60   *	<ul>
61   *	<li>Handle files with spaces in them</li>
62   *	<li>Have an option for file type color highlighting</li>
63   *	</ul>
64   *
65   *  @author  <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
66   */
67  public class FileNameCompletor
68  	implements Completor
69  {
70  	public int complete (final String buf, final int cursor,
71  		final List candidates)
72  	{
73  		String buffer = buf == null ? "" : buf;
74  
75  		String translated = buffer;
76  
77  		// special character: ~ maps to the user's home directory
78  		if (translated.startsWith ("~" + File.separator))
79  		{
80  			translated = System.getProperty ("user.home")
81  				+ translated.substring (1);
82  		}
83  		else if (translated.startsWith ("~"))
84  		{
85  			translated = new File (System.getProperty ("user.home"))
86  				.getParentFile ().getAbsolutePath ();
87  		}
88  		else if (!(translated.startsWith (File.separator)))
89  		{
90  			translated = new File ("").getAbsolutePath ()
91  				+ File.separator + translated;
92  		}
93  
94  		File f = new File (translated);
95  
96  		final File dir;
97  		
98  		if (translated.endsWith (File.separator))
99  			dir = f;
100 		else
101 			dir = f.getParentFile ();
102 		
103 		final File [] entries = dir == null ? new File [0] : dir.listFiles ();
104 
105 		try
106 		{
107 			return matchFiles (buffer, translated, entries, candidates);
108 		}
109 		finally
110 		{
111 			// we want to output a sorted list of files
112 			sortFileNames (candidates);
113 		}
114 	}
115 
116 
117 	protected void sortFileNames (final List fileNames)
118 	{
119 		Collections.sort (fileNames);
120 	}
121 
122 
123 	/**
124 	 *  Match the specified <i>buffer</i> to the array of <i>entries</i>
125 	 *  and enter the matches into the list of <i>candidates</i>. This method
126 	 *  can be overridden in a subclass that wants to do more
127 	 *  sophisticated file name completion.
128 	 *
129 	 *  @param	buffer		the untranslated buffer	
130 	 *  @param	translated	the buffer with common characters replaced	
131 	 *  @param	entries		the list of files to match	
132 	 *  @param	candidates	the list of candidates to populate	
133 	 *
134 	 *  @return  the offset of the match
135 	 */
136 	public int matchFiles (String buffer, String translated,
137 		File [] entries, List candidates)
138 	{
139 		if (entries == null)
140 			return -1;
141 
142 		int matches = 0;
143 
144 		// first pass: just count the matches
145 		for (int i = 0; i < entries.length; i++)
146 		{
147 			if (entries [i].getAbsolutePath ().startsWith (translated))
148 			{
149 				matches++;
150 			}
151 		}
152 
153 		// green - executable
154 		// blue - directory
155 		// red - compressed
156 		// cyan - symlink
157 		for (int i = 0; i < entries.length; i++)
158 		{
159 			if (entries [i].getAbsolutePath ().startsWith (translated))
160 			{
161 				String name = entries [i].getName ()
162 					+ (matches == 1 && entries [i].isDirectory ()
163 						? File.separator : " ");
164 
165 				/*
166 				if (entries [i].isDirectory ())
167 				{
168 					name = new ANSIBuffer ().blue (name).toString ();
169 				}
170 				*/
171 
172 				candidates.add (name);
173 			}
174 		}
175 
176 
177 		final int index = buffer.lastIndexOf (File.separator);
178 		return index + File.separator.length ();
179 	}
180 }
181