--- /dev/null 2015-04-26 06:51:08.003313989 -0700 +++ new/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java 2015-06-25 08:33:10.728369063 -0700 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2002-2012, the original author or authors. + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * http://www.opensource.org/licenses/bsd-license.php + */ +package jdk.internal.jline.console.completer; + +import jdk.internal.jline.internal.Configuration; + +import java.io.File; +import java.util.List; + +import static jdk.internal.jline.internal.Preconditions.checkNotNull; + +/** + * A file name completer takes the buffer and issues a list of + * potential completions. + *

+ * This completer tries to behave as similar as possible to + * bash's file name completion (using GNU readline) + * with the following exceptions: + *

+ *

+ * + * @author Marc Prud'hommeaux + * @author Jason Dillon + * @since 2.3 + */ +public class FileNameCompleter + implements Completer +{ + // TODO: Handle files with spaces in them + + private static final boolean OS_IS_WINDOWS; + + static { + String os = Configuration.getOsName(); + OS_IS_WINDOWS = os.contains("windows"); + } + + public int complete(String buffer, final int cursor, final List candidates) { + // buffer can be null + checkNotNull(candidates); + + if (buffer == null) { + buffer = ""; + } + + if (OS_IS_WINDOWS) { + buffer = buffer.replace('/', '\\'); + } + + String translated = buffer; + + File homeDir = getUserHome(); + + // Special character: ~ maps to the user's home directory + if (translated.startsWith("~" + separator())) { + translated = homeDir.getPath() + translated.substring(1); + } + else if (translated.startsWith("~")) { + translated = homeDir.getParentFile().getAbsolutePath(); + } + else if (!(new File(translated).isAbsolute())) { + String cwd = getUserDir().getAbsolutePath(); + translated = cwd + separator() + translated; + } + + File file = new File(translated); + final File dir; + + if (translated.endsWith(separator())) { + dir = file; + } + else { + dir = file.getParentFile(); + } + + File[] entries = dir == null ? new File[0] : dir.listFiles(); + + return matchFiles(buffer, translated, entries, candidates); + } + + protected String separator() { + return File.separator; + } + + protected File getUserHome() { + return Configuration.getUserHome(); + } + + protected File getUserDir() { + return new File("."); + } + + protected int matchFiles(final String buffer, final String translated, final File[] files, final List candidates) { + if (files == null) { + return -1; + } + + int matches = 0; + + // first pass: just count the matches + for (File file : files) { + if (file.getAbsolutePath().startsWith(translated)) { + matches++; + } + } + for (File file : files) { + if (file.getAbsolutePath().startsWith(translated)) { + CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " "); + candidates.add(render(file, name).toString()); + } + } + + final int index = buffer.lastIndexOf(separator()); + + return index + separator().length(); + } + + protected CharSequence render(final File file, final CharSequence name) { + return name; + } +}