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}