package io.vertx.ext.shell.system.impl;
import io.vertx.core.Vertx;
import io.vertx.core.VertxException;
import io.vertx.ext.shell.cli.CliToken;
import io.vertx.ext.shell.cli.Completion;
import io.vertx.ext.shell.command.Command;
import io.vertx.ext.shell.command.CommandResolver;
import io.vertx.ext.shell.session.Session;
import io.vertx.ext.shell.system.Process;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.stream.Collectors;
public class InternalCommandManager {
private final List<CommandResolver> resolvers;
public InternalCommandManager(CommandResolver... resolvers) {
this.resolvers = Arrays.asList(resolvers);
}
public InternalCommandManager(List<CommandResolver> resolvers) {
this.resolvers = resolvers;
}
public List<CommandResolver> getResolvers() {
return resolvers;
}
public Process createProcess(String line) {
return createProcess(CliToken.tokenize(line));
}
public Process createProcess(List<CliToken> line) {
try {
return makeRequest(line);
} catch (Exception e) {
throw new VertxException(e);
}
}
private Process makeRequest(List<CliToken> s) {
ListIterator<CliToken> tokens = s.listIterator();
while (tokens.hasNext()) {
CliToken token = tokens.next();
if (token.isText()) {
for (CommandResolver resolver : resolvers) {
Command command = resolver.getCommand(token.value());
if (command != null) {
List<CliToken> remaining = new ArrayList<>();
while (tokens.hasNext()) {
remaining.add(tokens.next());
}
return command.createProcess(remaining);
}
}
throw new IllegalArgumentException(token.value() + ": command not found");
}
}
throw new IllegalArgumentException();
}
public void complete(Completion completion) {
LinkedList<CliToken> tokens = new LinkedList<>(completion.lineTokens());
while (tokens.size() > 0 && tokens.getFirst().isBlank()) {
tokens.removeFirst();
}
if (tokens.size() > 1) {
ListIterator<CliToken> it = tokens.listIterator();
while (it.hasNext()) {
CliToken ct = it.next();
it.remove();
if (ct.isText()) {
List<CliToken> newTokens = new ArrayList<>();
while (it.hasNext()) {
newTokens.add(it.next());
}
StringBuilder tmp = new StringBuilder();
newTokens.stream().forEach(token -> tmp.append(token.raw()));
String line = tmp.toString();
for (CommandResolver resolver : resolvers) {
Command command = resolver.getCommand(ct.value());
if (command != null) {
command.complete(new Completion() {
@Override
public Vertx vertx() {
return completion.vertx();
}
@Override
public Session session() {
return completion.session();
}
@Override
public String rawLine() {
return line;
}
@Override
public List<CliToken> lineTokens() {
return newTokens;
}
@Override
public void complete(List<String> candidates) {
completion.complete(candidates);
}
@Override
public void complete(String value, boolean terminal) {
completion.complete(value, terminal);
}
});
return;
}
}
completion.complete(Collections.emptyList());
}
}
} else {
String prefix = tokens.size() > 0 ? tokens.getFirst().value() : "";
List<String> names = resolvers.stream().
flatMap(res -> res.commands().stream()).
map(Command::name).
filter(name -> name.startsWith(prefix)).
distinct().
collect(Collectors.toList());
if (names.size() == 1) {
completion.complete(names.get(0).substring(prefix.length()), true);
} else {
String commonPrefix = Completion.findLongestCommonPrefix(names);
if (commonPrefix.length() > prefix.length()) {
completion.complete(commonPrefix.substring(prefix.length()), false);
} else {
completion.complete(names);
}
}
}
}
}