001/* 002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 */ 019package org.nuxeo.shell.fs; 020 021import java.io.File; 022import java.util.Collections; 023import java.util.List; 024 025import jline.Completor; 026import jline.FileNameCompletor; 027 028import org.nuxeo.shell.Shell; 029 030/** 031 * This is a modified {@link FileNameCompletor} to take into account the current working directory 032 * 033 * @author <a href="mailto:[email protected]">Bogdan Stefanescu</a> 034 */ 035public class FolderCompletor implements Completor { 036 @SuppressWarnings("rawtypes") 037 public int complete(final String buf, final int cursor, final List candidates) { 038 String buffer = (buf == null) ? "" : buf; 039 040 String translated = buffer; 041 042 // special character: ~ maps to the user's home directory 043 if (translated.startsWith("~" + File.separator)) { 044 translated = System.getProperty("user.home") + translated.substring(1); 045 } else if (translated.startsWith("~")) { 046 translated = new File(System.getProperty("user.home")).getParentFile().getAbsolutePath(); 047 } else if (!(translated.startsWith(File.separator))) { 048 File wd = Shell.get().getContextObject(FileSystem.class).pwd(); 049 translated = wd.getAbsolutePath() + File.separator + translated; 050 } 051 052 File f = new File(translated); 053 054 final File dir; 055 056 if (translated.endsWith(File.separator)) { 057 dir = f; 058 } else { 059 dir = f.getParentFile(); 060 } 061 062 final File[] entries = (dir == null) ? new File[0] : dir.listFiles(); 063 064 try { 065 return matchFiles(buffer, translated, entries, candidates); 066 } finally { 067 // we want to output a sorted list of files 068 sortFileNames(candidates); 069 } 070 } 071 072 @SuppressWarnings({ "rawtypes", "unchecked" }) 073 protected void sortFileNames(final List fileNames) { 074 Collections.sort(fileNames); 075 } 076 077 /** 078 * Match the specified <i>buffer</i> to the array of <i>entries</i> and enter the matches into the list of 079 * <i>candidates</i>. This method can be overridden in a subclass that wants to do more sophisticated file name 080 * completion. 081 * 082 * @param buffer the untranslated buffer 083 * @param translated the buffer with common characters replaced 084 * @param entries the list of files to match 085 * @param candidates the list of candidates to populate 086 * @return the offset of the match 087 */ 088 @SuppressWarnings({ "rawtypes", "unchecked" }) 089 public int matchFiles(String buffer, String translated, File[] entries, List candidates) { 090 if (entries == null) { 091 return -1; 092 } 093 094 int matches = 0; 095 096 // first pass: just count the matches 097 for (int i = 0; i < entries.length; i++) { 098 if (entries[i].getAbsolutePath().startsWith(translated)) { 099 matches++; 100 } 101 } 102 103 // green - executable 104 // blue - directory 105 // red - compressed 106 // cyan - symlink 107 for (int i = 0; i < entries.length; i++) { 108 if (!entries[i].isDirectory()) { 109 continue; 110 } 111 if (entries[i].getAbsolutePath().startsWith(translated)) { 112 String name = entries[i].getName() 113 + (((matches == 1) && entries[i].isDirectory()) ? File.separator : " "); 114 115 /* 116 * if (entries [i].isDirectory ()) { name = new ANSIBuffer ().blue (name).toString (); } 117 */ 118 candidates.add(name); 119 } 120 } 121 122 final int index = buffer.lastIndexOf(File.separator); 123 124 return index + File.separator.length(); 125 } 126}