001 /** 002 * jline - Java console input library 003 * Copyright (c) 2002,2003 Marc Prud'hommeaux marc@apocalypse.org 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 * @author <a href="mailto:marc@apocalypse.org">Marc Prud'hommeaux</a> 043 */ 044 public class FileNameCompletor 045 implements Completor 046 { 047 public int complete (String buffer, int cursor, List candidates) 048 { 049 if (buffer == null) 050 buffer = ""; 051 052 String translated = buffer; 053 054 // special character: ~ maps to the user's home directory 055 if (translated.startsWith ("~" + File.separator)) 056 { 057 translated = System.getProperty ("user.home") 058 + translated.substring (1); 059 } 060 else if (translated.startsWith ("~")) 061 { 062 translated = new File (System.getProperty ("user.home")) 063 .getParentFile ().getAbsolutePath (); 064 } 065 else if (!(translated.startsWith (File.separator))) 066 { 067 translated = new File ("").getAbsolutePath () 068 + File.separator + translated; 069 } 070 071 File f = new File (translated); 072 073 final File dir; 074 075 if (translated.endsWith (File.separator)) 076 dir = f; 077 else 078 dir = f.getParentFile (); 079 080 final File [] entries = dir == null ? new File [0] : dir.listFiles (); 081 082 try 083 { 084 return matchFiles (buffer, translated, entries, candidates); 085 } 086 finally 087 { 088 // we want to output a sorted list of files 089 sortFileNames (candidates); 090 } 091 } 092 093 094 protected void sortFileNames (List fileNames) 095 { 096 Collections.sort (fileNames); 097 } 098 099 100 /** 101 * Match the specified <i>buffer</i> to the array of <i>entries</i> 102 * and enter the matches into the list of <i>candidates</i>. This method 103 * can be overridden in a subclass that wants to do more 104 * sophisticated file name completion. 105 * 106 * @param buffer the untranslated buffer 107 * @param translated the buffer with common characters replaced 108 * @param entries the list of files to match 109 * @param candidates the list of candidates to populate 110 * 111 * @return the offset of the match 112 */ 113 public int matchFiles (String buffer, String translated, 114 File [] entries, List candidates) 115 { 116 if (entries == null) 117 return -1; 118 119 int matches = 0; 120 121 // first pass: just count the matches 122 for (int i = 0; i < entries.length; i++) 123 { 124 if (entries [i].getAbsolutePath ().startsWith (translated)) 125 { 126 matches++; 127 } 128 } 129 130 // green - executable 131 // blue - directory 132 // red - compressed 133 // cyan - symlink 134 for (int i = 0; i < entries.length; i++) 135 { 136 if (entries [i].getAbsolutePath ().startsWith (translated)) 137 { 138 String name = entries [i].getName () 139 + (matches == 1 && entries [i].isDirectory () 140 ? File.separator : " "); 141 142 /* 143 if (entries [i].isDirectory ()) 144 { 145 name = new ANSIBuffer ().blue (name).toString (); 146 } 147 */ 148 149 candidates.add (name); 150 } 151 } 152 153 154 final int index = buffer.lastIndexOf (File.separator); 155 return index + File.separator.length (); 156 } 157 } 158