package org.rascalmpl.repl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.rascalmpl.interpreter.utils.StringUtils;
import org.rascalmpl.interpreter.utils.StringUtils.OffsetLengthTerm;
public class RascalCommandCompletion {
private static final TreeSet<String> COMMAND_KEYWORDS;
static {
COMMAND_KEYWORDS = new TreeSet<>();
COMMAND_KEYWORDS.add("set");
COMMAND_KEYWORDS.add("undeclare");
COMMAND_KEYWORDS.add("help");
COMMAND_KEYWORDS.add("edit");
COMMAND_KEYWORDS.add("unimport");
COMMAND_KEYWORDS.add("declarations");
COMMAND_KEYWORDS.add("quit");
COMMAND_KEYWORDS.add("history");
COMMAND_KEYWORDS.add("test");
COMMAND_KEYWORDS.add("modules");
COMMAND_KEYWORDS.add("clear");
}
private static final Pattern splitCommand = Pattern.compile("^[\\t ]*:(?<command>[a-z]*)([\\t ]|$)");
public static CompletionResult complete(String line, int cursor, SortedSet<String> commandOptions, CompletionFunction completeIdentifier, CompletionFunction completeModule) {
assert line.trim().startsWith(":");
Matcher m = splitCommand.matcher(line);
if (m.find()) {
String currentCommand = m.group("command");
switch(currentCommand) {
case "set": {
OffsetLengthTerm identifier = StringUtils.findRascalIdentifierAtOffset(line, cursor);
if (identifier != null && identifier.offset > m.end("command")) {
Collection<String> suggestions = commandOptions.stream()
.filter(s -> s.startsWith(identifier.term))
.sorted()
.collect(Collectors.toList());
if (suggestions != null && ! suggestions.isEmpty()) {
return new CompletionResult(identifier.offset, suggestions);
}
}
else if (line.trim().equals(":set")) {
return new CompletionResult(line.length(), commandOptions);
}
return null;
}
case "undeclare": return completeIdentifier.complete(line, cursor);
case "edit":
case "unimport": return completeModule.complete(line, line.length());
default: {
if (COMMAND_KEYWORDS.contains(currentCommand)) {
return null; // nothing to complete after a full command
}
List<String> result = null;
if (currentCommand.isEmpty()) {
result = new ArrayList<>(COMMAND_KEYWORDS);
}
else {
result = COMMAND_KEYWORDS.stream()
.filter(s -> s.startsWith(currentCommand))
.collect(Collectors.toList());
}
if (!result.isEmpty()) {
return new CompletionResult(m.start("command"), result);
}
}
}
}
return null;
}
}