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:bs@nuxeo.com">Bogdan Stefanescu</a>
034 */
035public class FileCompletor 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].getAbsolutePath().startsWith(translated)) {
109                String name = entries[i].getName()
110                        + (((matches == 1) && entries[i].isDirectory()) ? File.separator : " ");
111
112                /*
113                 * if (entries [i].isDirectory ()) { name = new ANSIBuffer ().blue (name).toString (); }
114                 */
115                candidates.add(name);
116            }
117        }
118
119        final int index = buffer.lastIndexOf(File.separator);
120
121        return index + File.separator.length();
122    }
123}