001 /**
002 * jline - Java console input library
003 * Copyright (c) 2002,2003 Marc Prud'hommeaux mwp1@cornell.edu
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either
008 * version 2.1 of the License, or (at your option) any later version.
009 *
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013 * Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public
016 * License along with this library; if not, write to the Free Software
017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018 */
019 package jline;
020
021 import java.io.*;
022 import java.util.*;
023
024
025 /**
026 * A file name completor takes the buffer and issues a list of
027 * potential completions.
028 *
029 * <p>
030 * This completor tries to behave as similar as possible to
031 * <i>bash</i>'s file name completion (using GNU readline)
032 * with the following exceptions:
033 *
034 * <ul>
035 * <li>Candidates that are directories will end with "/"</li>
036 * <li>Wildcard regular expressions are not evaluated or replaced</li>
037 * <li>The "~" character can be used to represent the user's home,
038 * but it cannot complete to other users' homes, since java does
039 * not provide any way of determining that easily</li>
040 * </ul>
041 *
042 * <p>TODO</p>
043 * <ul>
044 * <li>Handle files with spaces in them</li>
045 * <li>Have an option for file type color highlighting</li>
046 * </ul>
047 *
048 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
049 */
050 public class FileNameCompletor
051 implements Completor
052 {
053 public int complete (final String buf, final int cursor,
054 final List candidates)
055 {
056 String buffer = buf == null ? "" : buf;
057
058 String translated = buffer;
059
060 // special character: ~ maps to the user's home directory
061 if (translated.startsWith ("~" + File.separator))
062 {
063 translated = System.getProperty ("user.home")
064 + translated.substring (1);
065 }
066 else if (translated.startsWith ("~"))
067 {
068 translated = new File (System.getProperty ("user.home"))
069 .getParentFile ().getAbsolutePath ();
070 }
071 else if (!(translated.startsWith (File.separator)))
072 {
073 translated = new File ("").getAbsolutePath ()
074 + File.separator + translated;
075 }
076
077 File f = new File (translated);
078
079 final File dir;
080
081 if (translated.endsWith (File.separator))
082 dir = f;
083 else
084 dir = f.getParentFile ();
085
086 final File [] entries = dir == null ? new File [0] : dir.listFiles ();
087
088 try
089 {
090 return matchFiles (buffer, translated, entries, candidates);
091 }
092 finally
093 {
094 // we want to output a sorted list of files
095 sortFileNames (candidates);
096 }
097 }
098
099
100 protected void sortFileNames (final List fileNames)
101 {
102 Collections.sort (fileNames);
103 }
104
105
106 /**
107 * Match the specified <i>buffer</i> to the array of <i>entries</i>
108 * and enter the matches into the list of <i>candidates</i>. This method
109 * can be overridden in a subclass that wants to do more
110 * sophisticated file name completion.
111 *
112 * @param buffer the untranslated buffer
113 * @param translated the buffer with common characters replaced
114 * @param entries the list of files to match
115 * @param candidates the list of candidates to populate
116 *
117 * @return the offset of the match
118 */
119 public int matchFiles (String buffer, String translated,
120 File [] entries, List candidates)
121 {
122 if (entries == null)
123 return -1;
124
125 int matches = 0;
126
127 // first pass: just count the matches
128 for (int i = 0; i < entries.length; i++)
129 {
130 if (entries [i].getAbsolutePath ().startsWith (translated))
131 {
132 matches++;
133 }
134 }
135
136 // green - executable
137 // blue - directory
138 // red - compressed
139 // cyan - symlink
140 for (int i = 0; i < entries.length; i++)
141 {
142 if (entries [i].getAbsolutePath ().startsWith (translated))
143 {
144 String name = entries [i].getName ()
145 + (matches == 1 && entries [i].isDirectory ()
146 ? File.separator : " ");
147
148 /*
149 if (entries [i].isDirectory ())
150 {
151 name = new ANSIBuffer ().blue (name).toString ();
152 }
153 */
154
155 candidates.add (name);
156 }
157 }
158
159
160 final int index = buffer.lastIndexOf (File.separator);
161 return index + File.separator.length ();
162 }
163 }
164