io.micronaut.starter.cli.InteractiveShell Maven / Gradle / Ivy
/*
* Copyright 2017-2022 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.starter.cli;
import org.fusesource.jansi.AnsiConsole;
import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.MaskingCallback;
import org.jline.reader.ParsedLine;
import org.jline.reader.UserInterruptException;
import org.jline.reader.impl.DefaultParser;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import picocli.CommandLine;
import picocli.shell.jline3.PicocliJLineCompleter;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import static picocli.CommandLine.Help.Ansi.AUTO;
public class InteractiveShell {
private static final String DEFAULT_PROMPT = "@|blue mn>|@ ";
private final CommandLine commandLine;
private final Consumer executor;
private final BiFunction onError;
private final String prompt;
public InteractiveShell(CommandLine commandLine,
Consumer executor,
BiFunction onError) {
this(commandLine, executor, onError, DEFAULT_PROMPT);
}
public InteractiveShell(CommandLine commandLine,
Consumer executor,
BiFunction onError,
String prompt) {
this.commandLine = commandLine;
this.executor = executor;
this.onError = onError;
this.prompt = prompt;
}
public void start() {
AnsiConsole.systemInstall();
try {
PicocliJLineCompleter picocliCommands = new PicocliJLineCompleter(commandLine.getCommandSpec());
Terminal terminal = TerminalBuilder.terminal();
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(picocliCommands)
.parser(new DefaultParser())
.variable(LineReader.LIST_MAX, 50) // max tab completion candidates
.build();
String ansiPrompt = AUTO.string(prompt);
String rightPrompt = null;
// start the shell and process input until the user quits with Ctl-D
String line;
while (true) {
try {
line = reader.readLine(ansiPrompt, rightPrompt, (MaskingCallback) null, null);
if (line.matches("^\\s*#.*")) {
continue;
}
if (line.equals("exit")) {
return;
}
ParsedLine pl = reader.getParser().parse(line, 0);
String[] arguments = pl.words().toArray(new String[0]);
executor.accept(arguments);
} catch (UserInterruptException | EndOfFileException e) {
return;
}
}
} catch (Throwable t) {
onError.apply(t, commandLine);
} finally {
AnsiConsole.systemUninstall();
}
}
}