/*
* Copyright (C) 2012 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.crsh.cli.impl.completion;
import org.crsh.cli.descriptor.ArgumentDescriptor;
import org.crsh.cli.descriptor.CommandDescriptor;
import org.crsh.cli.impl.Delimiter;
import org.crsh.cli.descriptor.OptionDescriptor;
import org.crsh.cli.completers.EmptyCompleter;
import org.crsh.cli.impl.tokenizer.Token;
import org.crsh.cli.impl.tokenizer.TokenizerImpl;
import org.crsh.cli.impl.parser.Event;
import org.crsh.cli.impl.parser.Mode;
import org.crsh.cli.impl.parser.Parser;
import org.crsh.cli.spi.Completer;
import java.util.List;
/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
public final class CompletionMatcher<T> {
/** . */
private final CommandDescriptor<T> descriptor;
public CompletionMatcher(CommandDescriptor<T> descriptor) {
this.descriptor = descriptor;
}
public final CompletionMatch match(String s) throws CompletionException {
return match(EmptyCompleter.getInstance(), s);
}
public CompletionMatch match(Completer completer, String s) throws CompletionException {
return getCompletion(completer, s).complete();
}
private Completion argument(CommandDescriptor<?> method, Completer completer, Delimiter delimiter) {
List<? extends ArgumentDescriptor> arguments = method.getArguments();
if (arguments.isEmpty()) {
return new EmptyCompletion();
} else {
ArgumentDescriptor argument = arguments.get(0);
return new ParameterCompletion("", delimiter, argument, completer);
}
}
private Completion getCompletion(Completer completer, String s) throws CompletionException {
// Find delimiter
CommandDescriptor<T> foo = this.descriptor;
TokenizerImpl tokenizer = new TokenizerImpl(s);
Delimiter delimiter = tokenizer.getEndingDelimiter();
Parser<T> parser = new Parser<T>(tokenizer, foo, Mode.COMPLETE);
// Last non separator event
Event last = null;
Event.Separator separator = null;
Event.Stop stop;
//
while (true) {
Event event = parser.next();
if (event instanceof Event.Separator) {
separator = (Event.Separator)event;
} else if (event instanceof Event.Stop) {
stop = (Event.Stop)event;
break;
} else if (event instanceof Event.Option) {
last = event;
separator = null;
} else if (event instanceof Event.Subordinate) {
// ABUSE!!! fixme
foo = (CommandDescriptor<T>)((Event.Subordinate)event).getDescriptor();
last = event;
separator = null;
} else if (event instanceof Event.Argument) {
last = event;
separator = null;
}
}
//
if (stop instanceof Event.Stop.Unresolved.NoSuchOption) {
Event.Stop.Unresolved.NoSuchOption nso = (Event.Stop.Unresolved.NoSuchOption)stop;
return new OptionCompletion<T>(foo, nso.getToken());
} else if (stop instanceof Event.Stop.Unresolved) {
if (stop instanceof Event.Stop.Unresolved.TooManyArguments) {
Event.Stop.Unresolved.TooManyArguments tma = (Event.Stop.Unresolved.TooManyArguments)stop;
return new CommandCompletion<T>(foo, s.substring(stop.getIndex()), delimiter);
} else {
return new EmptyCompletion();
}
} else if (stop instanceof Event.Stop.Done) {
// to use ?
}
if (last == null) {
if (foo.getSubordinates().size() > 0) {
return new CommandCompletion<T>(foo, s.substring(stop.getIndex()), Delimiter.EMPTY);
} else {
List<ArgumentDescriptor> args = foo.getArguments();
if (args.size() > 0) {
return new ParameterCompletion("", delimiter, args.get(0), completer);
} else {
return new EmptyCompletion();
}
}
} else if (last instanceof Event.Option) {
Event.Option optionEvent = (Event.Option)last;
List<Token.Literal.Word> values = optionEvent.getValues();
OptionDescriptor option = optionEvent.getParameter();
if (separator == null) {
if (values.size() == 0) {
return new SpaceCompletion();
} else if (values.size() <= option.getArity()) {
Token.Literal.Word word = optionEvent.peekLast();
return new ParameterCompletion(word.getValue(), delimiter, option, completer);
} else {
return new EmptyCompletion();
}
} else {
if (values.size() < option.getArity()) {
return new ParameterCompletion("", delimiter, option, completer);
} else {
return argument(foo, completer, delimiter);
}
}
} else if (last instanceof Event.Argument) {
Event.Argument eventArgument = (Event.Argument)last;
ArgumentDescriptor argument = eventArgument.getParameter();
if (separator != null) {
switch (argument.getMultiplicity()) {
case SINGLE:
List<? extends ArgumentDescriptor> arguments = eventArgument.getCommand().getArguments();
int index = arguments.indexOf(argument) + 1;
if (index < arguments.size()) {
ArgumentDescriptor nextArg = arguments.get(index);
return new ParameterCompletion("", delimiter, nextArg, completer);
} else {
return new EmptyCompletion();
}
case MULTI:
return new ParameterCompletion("", delimiter, argument, completer);
default:
throw new AssertionError();
}
} else {
Token.Literal value = eventArgument.peekLast();
return new ParameterCompletion(value.getValue(), delimiter, argument, completer);
}
} else if (last instanceof Event.Subordinate) {
if (separator != null) {
return argument(foo, completer, delimiter);
} else {
return new SpaceCompletion();
}
} else {
throw new AssertionError();
}
}
}