From 026d6f775b7e03487db5fe1f6da256a726b76e30 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 8 Feb 2022 13:19:16 +1100 Subject: [PATCH] Easy activation of single letter aliases If you define a single letter alias in the interactive shell and it is not mapped to an existing command you can activate it from the normal terminal. Fixes #23432 --- .../deployment/console/AeshConsole.java | 45 ++++++++++++++++++- .../console/ConsoleStateManager.java | 24 ++++++++-- .../quarkus/dev/console/QuarkusConsole.java | 15 +++++++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/console/AeshConsole.java b/core/deployment/src/main/java/io/quarkus/deployment/console/AeshConsole.java index 5ca7b3da8a8ed2..c881b28d12b3fc 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/console/AeshConsole.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/console/AeshConsole.java @@ -1,7 +1,10 @@ package io.quarkus.deployment.console; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; import java.util.TreeMap; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.locks.Lock; @@ -589,11 +592,51 @@ public void run() { } catch (Exception e) { throw new RuntimeException(e); } + } + + @Override + public Map singleLetterAliases() { + try { + var manager = new AliasManager(Paths.get(System.getProperty("user.home")).resolve(ALIAS_FILE).toFile(), true); + Map ret = new HashMap<>(); + for (String alias : manager.getAllNames()) { + if (alias.length() == 1) { + ret.put(alias.charAt(0), manager.getAlias(alias).get().getValue()); + } + } + return ret; + } catch (IOException e) { + return Map.of(); + } + } + @Override + public void runAlias(char alias) { + try { + AeshCommandRegistryBuilder commandBuilder = AeshCommandRegistryBuilder.builder(); + ConsoleCliManager.commands.forEach(commandBuilder::command); + + CommandRegistry registry = commandBuilder + .create(); + Settings settings = SettingsBuilder + .builder() + .enableExport(false) + .inputStream(new ByteArrayInputStream(new byte[] { (byte) alias, '\n' })) + .enableAlias(true) + .aliasManager( + new AliasManager(Paths.get(System.getProperty("user.home")).resolve(ALIAS_FILE).toFile(), true)) + .connection(delegateConnection) + .commandRegistry(registry) + .build(); + aeshConsole = new ReadlineConsole(settings); + aeshConsole.start(); + } catch (IOException e) { + throw new RuntimeException(e); + } } public void exitCliMode() { - if (aeshConsole == null) { + if (aeshConsole == null || delegateConnection == null) { return; } aeshConsole.stop(); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleStateManager.java b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleStateManager.java index a21da1453d7228..132b50c0b2d32a 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleStateManager.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/console/ConsoleStateManager.java @@ -51,19 +51,20 @@ public class ConsoleStateManager { @Override public void accept(int[] ints) { for (int i : ints) { + char key = (char) i; if (readLineBuilder != null) { if (i == '\n' || i == '\r') { readLineConsumer.accept(readLineBuilder.toString()); readLineBuilder = null; readLineConsumer = null; } else { - readLineBuilder.append((char) i); + readLineBuilder.append(key); } } else { if (i == '\n') { System.out.println(""); } - Holder command = commands.get((char) i); + Holder command = commands.get(key); if (command != null) { if (command.consoleCommand.getReadLineHandler() != null) { QuarkusConsole.INSTANCE.doReadLine(); @@ -72,6 +73,10 @@ public void accept(int[] ints) { } else { command.consoleCommand.getRunnable().run(); } + } else { + if (QuarkusConsole.INSTANCE.singleLetterAliases().containsKey(key)) { + QuarkusConsole.INSTANCE.runAlias(key); + } } } } @@ -203,11 +208,16 @@ private void printHelp() { for (Holder i : commands.values()) { contexts.add(i.context); } + Set seen = new HashSet<>(); for (ConsoleContext ctx : contexts.stream().sorted(Comparator.comparing(ConsoleContext::getName)) .collect(Collectors.toList())) { System.out.println("\n" + RED + "==" + RESET + " " + UNDERLINE + ctx.name + NO_UNDERLINE + "\n"); for (var i : ctx.internal) { + if (seen.contains(i.getKey())) { + continue; + } + seen.add(i.getKey()); if (i.getDescription() != null) { if (i.getHelpState() == null) { System.out.println(helpOption(i.getKey(), i.getDescription())); @@ -220,7 +230,15 @@ private void printHelp() { } } } - + Map aliases = QuarkusConsole.INSTANCE.singleLetterAliases(); + if (!aliases.isEmpty()) { + System.out.println("\n" + RED + "==" + RESET + " " + UNDERLINE + "User Defined Aliases" + NO_UNDERLINE + "\n"); + for (Map.Entry entry : aliases.entrySet()) { + if (!seen.contains(entry.getKey())) { + System.out.println(helpOption(entry.getKey(), entry.getValue())); + } + } + } } static class Holder { diff --git a/core/devmode-spi/src/main/java/io/quarkus/dev/console/QuarkusConsole.java b/core/devmode-spi/src/main/java/io/quarkus/dev/console/QuarkusConsole.java index faca9f2dc0e8c4..c78f741202b86c 100644 --- a/core/devmode-spi/src/main/java/io/quarkus/dev/console/QuarkusConsole.java +++ b/core/devmode-spi/src/main/java/io/quarkus/dev/console/QuarkusConsole.java @@ -6,6 +6,7 @@ import java.io.PrintStream; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingDeque; import java.util.function.BiPredicate; @@ -152,6 +153,20 @@ public void exitCliMode() { //noop for the non-aesh console } + /** + * Exposes single character aliases so they can be displayed in the help screen + */ + public Map singleLetterAliases() { + return Map.of(); + } + + /** + * runs a single letter alias + */ + public void runAlias(char alias) { + + } + protected String stripAnsiCodes(String s) { if (s == null) { return null;