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: * A file name completor takes the buffer and issues a list of
014: * potential completions.
015: *
016: * <p>
017: * This completor tries to behave as similar as possible to
018: * <i>bash</i>'s file name completion (using GNU readline)
019: * with the following exceptions:
020: *
021: * <ul>
022: * <li>Candidates that are directories will end with "/"</li>
023: * <li>Wildcard regular expressions are not evaluated or replaced</li>
024: * <li>The "~" character can be used to represent the user's home,
025: * but it cannot complete to other users' homes, since java does
026: * not provide any way of determining that easily</li>
027: * </ul>
028: *
029: * <p>TODO</p>
030: * <ul>
031: * <li>Handle files with spaces in them</li>
032: * <li>Have an option for file type color highlighting</li>
033: * </ul>
034: *
035: * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
036: */
037: public class FileNameCompletor implements Completor {
038: public int complete(final String buf, final int cursor,
039: final List candidates) {
040: String buffer = (buf == null) ? "" : buf;
041:
042: String translated = buffer;
043:
044: // special character: ~ maps to the user's home directory
045: if (translated.startsWith("~" + File.separator)) {
046: translated = System.getProperty("user.home")
047: + translated.substring(1);
048: } else if (translated.startsWith("~")) {
049: translated = new File(System.getProperty("user.home"))
050: .getParentFile().getAbsolutePath();
051: } else if (!(translated.startsWith(File.separator))) {
052: translated = new File("").getAbsolutePath()
053: + File.separator + translated;
054: }
055:
056: File f = new File(translated);
057:
058: final File dir;
059:
060: if (translated.endsWith(File.separator)) {
061: dir = f;
062: } else {
063: dir = f.getParentFile();
064: }
065:
066: final File[] entries = (dir == null) ? new File[0] : dir
067: .listFiles();
068:
069: try {
070: return matchFiles(buffer, translated, entries, candidates);
071: } finally {
072: // we want to output a sorted list of files
073: sortFileNames(candidates);
074: }
075: }
076:
077: protected void sortFileNames(final List fileNames) {
078: Collections.sort(fileNames);
079: }
080:
081: /**
082: * Match the specified <i>buffer</i> to the array of <i>entries</i>
083: * and enter the matches into the list of <i>candidates</i>. This method
084: * can be overridden in a subclass that wants to do more
085: * sophisticated file name completion.
086: *
087: * @param buffer the untranslated buffer
088: * @param translated the buffer with common characters replaced
089: * @param entries the list of files to match
090: * @param candidates the list of candidates to populate
091: *
092: * @return the offset of the match
093: */
094: public int matchFiles(String buffer, String translated,
095: File[] entries, List candidates) {
096: if (entries == null) {
097: return -1;
098: }
099:
100: int matches = 0;
101:
102: // first pass: just count the matches
103: for (int i = 0; i < entries.length; i++) {
104: if (entries[i].getAbsolutePath().startsWith(translated)) {
105: matches++;
106: }
107: }
108:
109: // green - executable
110: // blue - directory
111: // red - compressed
112: // cyan - symlink
113: for (int i = 0; i < entries.length; i++) {
114: if (entries[i].getAbsolutePath().startsWith(translated)) {
115: String name = entries[i].getName()
116: + (((matches == 1) && entries[i].isDirectory()) ? File.separator
117: : " ");
118:
119: /*
120: if (entries [i].isDirectory ())
121: {
122: name = new ANSIBuffer ().blue (name).toString ();
123: }
124: */
125: candidates.add(name);
126: }
127: }
128:
129: final int index = buffer.lastIndexOf(File.separator);
130:
131: return index + File.separator.length();
132: }
133: }
|