001 /*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software 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 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019
020 package org.crsh.cli.completers;
021
022 import org.crsh.cli.descriptor.ParameterDescriptor;
023 import org.crsh.cli.spi.Completer;
024 import org.crsh.cli.spi.Completion;
025
026 import java.io.File;
027 import java.util.Collection;
028
029 public abstract class AbstractPathCompleter<P> implements Completer {
030
031 protected abstract String getCurrentPath() throws Exception;
032
033 protected abstract P getPath(String path) throws Exception;
034
035 protected abstract boolean exists(P path) throws Exception;
036
037 protected abstract boolean isDirectory(P path) throws Exception;
038
039 protected abstract boolean isFile(P path) throws Exception;
040
041 protected abstract Collection<P> getChilren(P path) throws Exception;
042
043 protected abstract String getName(P path) throws Exception;
044
045 public final Completion complete(ParameterDescriptor parameter, String prefix) throws Exception {
046
047 //
048 String sep = File.separator;
049
050 // Handle empty dir
051 if (!prefix.startsWith(sep)) {
052 String currentPath = getCurrentPath();
053
054 if (!currentPath.endsWith(sep)) {
055 currentPath += sep;
056 }
057 if (prefix.length() > 0) {
058 prefix = currentPath + prefix;
059 } else {
060 prefix = currentPath;
061 }
062 }
063
064 //
065 P f = getPath(prefix);
066
067 //
068 if (exists(f)) {
069 if (isDirectory(f)) {
070 if (prefix.endsWith(sep)) {
071 Collection<P> children = getChilren(f);
072 if (children != null) {
073 if (children.size() > 0) {
074 return listDir(f, "");
075 } else {
076 return Completion.create();
077 }
078 } else {
079 return Completion.create();
080 }
081 } else {
082 Collection<P> children = getChilren(f);
083 if (children == null) {
084 return Completion.create();
085 } else {
086 return Completion.create(sep, false);
087 }
088 }
089 } else if (isFile(f)) {
090 return Completion.create("", true);
091 }
092 return Completion.create();
093 } else {
094 int pos = prefix.lastIndexOf(sep);
095 if (pos != -1) {
096 String filter;
097 if (pos == 0) {
098 f = getPath(sep);
099 filter = prefix.substring(1);
100 } else {
101 f = getPath(prefix.substring(0, pos));
102 filter = prefix.substring(pos + 1);
103 }
104 if (exists(f)) {
105 if (isDirectory(f)) {
106 return listDir(f, filter);
107 } else {
108 return Completion.create();
109 }
110 } else {
111 return Completion.create();
112 }
113 } else {
114 return Completion.create();
115 }
116 }
117 }
118
119 private Completion listDir(P dir, final String filter) throws Exception {
120 Collection<P> children = getChilren(dir);
121 if (children != null) {
122 Completion.Builder builder = Completion.builder(filter);
123 for (P child : children) {
124 String name = getName(child);
125 if (name.startsWith(filter)) {
126 String suffix = name.substring(filter.length());
127 if (isDirectory(child)) {
128 Collection<P> grandChildren = getChilren(child);
129 if (grandChildren != null) {
130 builder.add(suffix + File.separator, false);
131 } else {
132 // Skip it
133 }
134 } else {
135 builder.add(suffix, true);
136 }
137 }
138 }
139 return builder.build();
140 } else {
141 return Completion.create();
142 }
143 }
144 }