diff --git a/src/javarepl/Main.java b/src/javarepl/Main.java index f4b8ba5..e863a41 100644 --- a/src/javarepl/Main.java +++ b/src/javarepl/Main.java @@ -1,16 +1,15 @@ package javarepl; -import com.googlecode.totallylazy.Exceptions; +import com.googlecode.totallylazy.Lists; import com.googlecode.totallylazy.Option; import com.googlecode.totallylazy.Sequence; import com.googlecode.totallylazy.Strings; import com.googlecode.totallylazy.functions.Function1; +import javarepl.client.EvaluationLog; import javarepl.client.EvaluationResult; import javarepl.client.JavaREPLClient; import javarepl.completion.CompletionCandidate; import javarepl.completion.CompletionResult; -import jline.Terminal; -import jline.TerminalFactory; import jline.console.ConsoleReader; import jline.console.CursorBuffer; import jline.console.completer.CandidateListCompletionHandler; @@ -24,8 +23,8 @@ import java.nio.file.Files; import java.util.*; -import static com.googlecode.totallylazy.Exceptions.captureException; import static com.googlecode.totallylazy.Files.fileOption; +import static com.googlecode.totallylazy.Lists.list; import static com.googlecode.totallylazy.Option.none; import static com.googlecode.totallylazy.Option.some; import static com.googlecode.totallylazy.Sequences.empty; @@ -38,11 +37,13 @@ import static com.googlecode.totallylazy.predicates.Not.not; import static java.lang.String.format; import static java.lang.System.getProperty; -import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static javarepl.Utils.applicationVersion; import static javarepl.Utils.randomServerPort; +import static javarepl.client.EvaluationLog.Type.CONTROL; import static javarepl.completion.CompletionResult.methods.fromJson; import static javarepl.completion.CompletionResult.methods.toJson; +import static javarepl.console.commands.ClearScreen.CLEAR_SCREEN_CMD; import static javax.tools.ToolProvider.getSystemJavaCompiler; public class Main { @@ -53,9 +54,10 @@ public class Main { public static void main(String... args) throws Exception { console = new ResultPrinter(printColors(args)); - Sequence initialExpressions = initialExpressionsFromFile().join(initialExpressionsFromArgs(args)); + ConsoleReader consoleReader = new ConsoleReader(System.in, AnsiConsole.out); JavaREPLClient client = clientFor(hostname(args), port(args)); - ExpressionReader expressionReader = expressionReaderFor(client, initialExpressions); + Sequence initialExpressions = initialExpressionsFromFile().join(initialExpressionsFromArgs(args)); + ExpressionReader expressionReader = expressionReaderFor(consoleReader, client, initialExpressions); Option expression = none(); Option result = none(); @@ -64,17 +66,48 @@ public static void main(String... args) throws Exception { if (!expression.isEmpty()) { result = client.execute(expression.get()); - if (!result.isEmpty()) - console.printEvaluationResult(result.get()); + if (!result.isEmpty()) { + for (EvaluationLog log : result.get().logs()) { + if (!handleTerminalCommand(log)) { + handleTerminalMessage(log); + } + } + } } } } - private static JavaREPLClient clientFor(Option hostname, Option port) throws Exception { - console.printInfo(format("Welcome to JavaREPL version %s (%s, Java %s)", + private static void handleTerminalMessage(EvaluationLog log) { + console.printEvaluationLog(log); + } + + private static boolean handleTerminalCommand(EvaluationLog log) { + if (log.type().equals(CONTROL)){ + switch (log.message()) { + case CLEAR_SCREEN_CMD: { + console.printInfo("\033c"); + console.printInfo(welcomeMessage()); + console.printInfo(welcomeInstructions()); + } break; + + default: return false; + } + return true; + } + return false; + } + + + + private static String welcomeMessage() { + return format("Welcome to JavaREPL version %s (%s, Java %s)", applicationVersion(), getProperty("java.vm.name"), - getProperty("java.version"))); + getProperty("java.version")); + } + + private static JavaREPLClient clientFor(Option hostname, Option port) throws Exception { + console.printInfo(welcomeMessage()); if (hostname.isEmpty() && port.isEmpty()) { return startNewLocalInstance("localhost", randomServerPort()); @@ -108,7 +141,7 @@ private static JavaREPLClient startNewLocalInstance(String hostname, Integer por System.exit(0); } - console.printInfo("Type expression to evaluate, \u001B[32m:help\u001B[0m for more options or press \u001B[32mtab\u001B[0m to auto-complete."); + console.printInfo(welcomeInstructions()); ProcessBuilder builder = new ProcessBuilder("java", "-cp", System.getProperty("java.class.path"), Repl.class.getCanonicalName(), "--port=" + port); builder.redirectErrorStream(true); @@ -130,6 +163,10 @@ public void run() { return replClient; } + private static String welcomeInstructions() { + return "Type expression to evaluate, \u001B[32m:help\u001B[0m for more options or press \u001B[32mtab\u001B[0m to auto-complete."; + } + private static boolean waitUntilInstanceStarted(JavaREPLClient client) throws Exception { for (int i = 0; i < 500; i++) { Thread.sleep(10); @@ -169,15 +206,13 @@ private static Boolean printColors(String[] args) { return !sequence(args).contains("--noColors"); } - private static ExpressionReader expressionReaderFor(final JavaREPLClient client, Sequence initialExpressions) throws IOException { + private static ExpressionReader expressionReaderFor(ConsoleReader consoleReader, final JavaREPLClient client, Sequence initialExpressions) throws IOException { return new ExpressionReader(new Function1, String>() { private static final char CTRL_C = (char) 3; private static final char CTRL_D = (char) 4; - private final ConsoleReader consoleReader; private Sequence expressions = initialExpressions; { - consoleReader = new ConsoleReader(System.in, AnsiConsole.out); consoleReader.setCompletionHandler(new JlineCompletionHandler()); consoleReader.setHistoryEnabled(true); consoleReader.setExpandEvents(false); @@ -213,7 +248,7 @@ private jline.console.completer.Completer clientCompleter() { return (expression, cursor, candidates) -> { try { CompletionResult result = client.completions(expression); - candidates.addAll(asList(toJson(result))); + candidates.addAll(singletonList(toJson(result))); return result.candidates().isEmpty() ? -1 : result.position(); } catch (Exception e) { return -1; diff --git a/src/javarepl/ResultPrinter.java b/src/javarepl/ResultPrinter.java index abdff86..f6a105f 100644 --- a/src/javarepl/ResultPrinter.java +++ b/src/javarepl/ResultPrinter.java @@ -23,12 +23,6 @@ public void printInfo(String message) { AnsiConsole.out.println(ansiColored(message)); } - public void printEvaluationResult(EvaluationResult result) { - for (EvaluationLog log : result.logs()) { - printEvaluationLog(log); - } - } - public void printEvaluationLog(EvaluationLog log) { switch (log.type()) { case INFO: diff --git a/src/javarepl/client/EvaluationLog.java b/src/javarepl/client/EvaluationLog.java index 51fe748..26e06fd 100644 --- a/src/javarepl/client/EvaluationLog.java +++ b/src/javarepl/client/EvaluationLog.java @@ -2,7 +2,7 @@ public class EvaluationLog { public static enum Type { - INFO, SUCCESS, ERROR; + INFO, SUCCESS, ERROR, CONTROL; public static Type type(String type) { return valueOf(type); diff --git a/src/javarepl/console/ConsoleLog.java b/src/javarepl/console/ConsoleLog.java index 421aba2..dc5e2c1 100644 --- a/src/javarepl/console/ConsoleLog.java +++ b/src/javarepl/console/ConsoleLog.java @@ -4,7 +4,7 @@ public class ConsoleLog { public static enum Type { - INFO, SUCCESS, ERROR + INFO, SUCCESS, ERROR, CONTROL } private final Type type; @@ -15,6 +15,10 @@ private ConsoleLog(Type type, String message) { this.message = message; } + public static ConsoleLog control(String message) { + return consoleLog(CONTROL, message); + } + public static ConsoleLog success(String message) { return consoleLog(SUCCESS, message); } diff --git a/src/javarepl/console/ConsoleLogger.java b/src/javarepl/console/ConsoleLogger.java index 3b9d19c..5f488a0 100644 --- a/src/javarepl/console/ConsoleLogger.java +++ b/src/javarepl/console/ConsoleLogger.java @@ -29,6 +29,10 @@ public void info(String message) { log(ConsoleLog.info(message)); } + public void control(String message) { + log(ConsoleLog.control(message)); + } + public void success(String message) { log(ConsoleLog.success(message)); } diff --git a/src/javarepl/console/commands/ClearScreen.java b/src/javarepl/console/commands/ClearScreen.java index 3195404..beccd45 100644 --- a/src/javarepl/console/commands/ClearScreen.java +++ b/src/javarepl/console/commands/ClearScreen.java @@ -1,24 +1,22 @@ package javarepl.console.commands; -import javarepl.Evaluator; import javarepl.completion.CommandCompleter; import javarepl.console.ConsoleLogger; -import static com.googlecode.totallylazy.predicates.Predicates.equalTo; +import static com.googlecode.totallylazy.Strings.startsWith; public final class ClearScreen extends Command { + public static final String CLEAR_SCREEN_CMD = "CLEAR_SCREEN"; private static final String COMMAND = ":cls"; - private final Evaluator evaluator; private final ConsoleLogger logger; - public ClearScreen(Evaluator evaluator, ConsoleLogger logger) { - super(COMMAND + " - clear screen", equalTo(COMMAND).or(equalTo(null)), new CommandCompleter(COMMAND)); - this.evaluator = evaluator; + public ClearScreen(ConsoleLogger logger) { + super(COMMAND + " - clears screen", startsWith(COMMAND), new CommandCompleter(COMMAND)); this.logger = logger; } public void execute(String expression) { this.logger.reset(); - this.logger.info("\033[2J"); + this.logger.control(CLEAR_SCREEN_CMD); } } diff --git a/src/javarepl/console/rest/RestConsoleResource.java b/src/javarepl/console/rest/RestConsoleResource.java index 83fbc3d..368a337 100644 --- a/src/javarepl/console/rest/RestConsoleResource.java +++ b/src/javarepl/console/rest/RestConsoleResource.java @@ -48,7 +48,7 @@ public Map execute(@FormParam("expression") String expr) { return emptyMap(String.class, Object.class) .insert("expression", result.expression()) - .insert("logs", result.logs().map(commandResultToModel())); + .insert("logs", result.logs().map(toCommandResultMap())); } @POST @@ -86,7 +86,7 @@ public Map history() { .insert("history", console.history().items().toList()); } - private static Function1> commandResultToModel() { + private static Function1> toCommandResultMap() { return consoleLog -> emptyMap(String.class, Object.class) .insert("type", consoleLog.type()) .insert("message", consoleLog.message()); diff --git a/src/javarepl/web/term.js b/src/javarepl/web/term.js index f6e5c7c..3c6020e 100644 --- a/src/javarepl/web/term.js +++ b/src/javarepl/web/term.js @@ -125,6 +125,30 @@ function echoCompletionCandidates(term, candidates) { term.echo(layoutCompletions(candidates, term.width() / 8)); } +function handleTerminalCommand(log, term) { + if (log.type == "CONTROL") { + switch (log.message) { + case "CLEAR_SCREEN": + term.clear(); + term.echo(session.welcomeMessage); + term.echo(' '); + break; + } + return true; + } + return false; +} + +function handleTerminalMessage(log, term) { + if (log.type != "CONTROL") { + var style = log.type == "ERROR" ? "terminal-message-error" : "terminal-message-success"; + term.echo(log.message, messageStyle(style)) + return log.type == "ERROR"; + } + return false; +} + + $(document).ready(function () { jQuery(function ($, undefined) { createNewSession(getParam("expression"), getParam("snap")); @@ -146,16 +170,11 @@ $(document).ready(function () { data: {id: session.clientId, expression: expression} }).done(function (data) { var hadError = false; - for (var i = 0; i < data.logs.length; i++) { - var style = data.logs[i].type == "ERROR" ? "terminal-message-error" : "terminal-message-success"; - - if (data.logs[i].type == "ERROR") { - hadError = true; - + var log = data.logs[i]; + if (!handleTerminalCommand(log, term)) { + hadError = handleTerminalMessage(log, term) || hadError; } - - term.echo(data.logs[i].message, messageStyle(style)) } if (!hadError) {