001/* 002 * (C) Copyright 2006-2010 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * bstefanescu 016 */ 017package org.nuxeo.shell.fs; 018 019import java.io.File; 020import java.util.Collections; 021import java.util.List; 022 023import jline.Completor; 024import jline.FileNameCompletor; 025 026import org.nuxeo.shell.Shell; 027 028/** 029 * This is a modified {@link FileNameCompletor} to take into account the current working directory 030 * 031 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 032 */ 033public class FolderCompletor implements Completor { 034 @SuppressWarnings("rawtypes") 035 public int complete(final String buf, final int cursor, final List candidates) { 036 String buffer = (buf == null) ? "" : buf; 037 038 String translated = buffer; 039 040 // special character: ~ maps to the user's home directory 041 if (translated.startsWith("~" + File.separator)) { 042 translated = System.getProperty("user.home") + translated.substring(1); 043 } else if (translated.startsWith("~")) { 044 translated = new File(System.getProperty("user.home")).getParentFile().getAbsolutePath(); 045 } else if (!(translated.startsWith(File.separator))) { 046 File wd = Shell.get().getContextObject(FileSystem.class).pwd(); 047 translated = wd.getAbsolutePath() + File.separator + translated; 048 } 049 050 File f = new File(translated); 051 052 final File dir; 053 054 if (translated.endsWith(File.separator)) { 055 dir = f; 056 } else { 057 dir = f.getParentFile(); 058 } 059 060 final File[] entries = (dir == null) ? new File[0] : dir.listFiles(); 061 062 try { 063 return matchFiles(buffer, translated, entries, candidates); 064 } finally { 065 // we want to output a sorted list of files 066 sortFileNames(candidates); 067 } 068 } 069 070 @SuppressWarnings({ "rawtypes", "unchecked" }) 071 protected void sortFileNames(final List fileNames) { 072 Collections.sort(fileNames); 073 } 074 075 /** 076 * Match the specified <i>buffer</i> to the array of <i>entries</i> and enter the matches into the list of 077 * <i>candidates</i>. This method can be overridden in a subclass that wants to do more sophisticated file name 078 * completion. 079 * 080 * @param buffer the untranslated buffer 081 * @param translated the buffer with common characters replaced 082 * @param entries the list of files to match 083 * @param candidates the list of candidates to populate 084 * @return the offset of the match 085 */ 086 @SuppressWarnings({ "rawtypes", "unchecked" }) 087 public int matchFiles(String buffer, String translated, File[] entries, List candidates) { 088 if (entries == null) { 089 return -1; 090 } 091 092 int matches = 0; 093 094 // first pass: just count the matches 095 for (int i = 0; i < entries.length; i++) { 096 if (entries[i].getAbsolutePath().startsWith(translated)) { 097 matches++; 098 } 099 } 100 101 // green - executable 102 // blue - directory 103 // red - compressed 104 // cyan - symlink 105 for (int i = 0; i < entries.length; i++) { 106 if (!entries[i].isDirectory()) { 107 continue; 108 } 109 if (entries[i].getAbsolutePath().startsWith(translated)) { 110 String name = entries[i].getName() 111 + (((matches == 1) && entries[i].isDirectory()) ? File.separator : " "); 112 113 /* 114 * if (entries [i].isDirectory ()) { name = new ANSIBuffer ().blue (name).toString (); } 115 */ 116 candidates.add(name); 117 } 118 } 119 120 final int index = buffer.lastIndexOf(File.separator); 121 122 return index + File.separator.length(); 123 } 124}