This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch CAMEL-23226-all-jbang-ux in repository https://gitbox.apache.org/repos/asf/camel.git
commit fda09114ccd726f18cb3ebce8786c7b883139d48 Author: Guillaume Nodet <[email protected]> AuthorDate: Sat Mar 21 10:05:54 2026 +0100 CAMEL-23226: Migrate Shell to JLine 4 Shell API Co-Authored-By: Claude Opus 4.6 <[email protected]> --- dsl/camel-jbang/camel-jbang-core/pom.xml | 8 +- .../camel/dsl/jbang/core/commands/Shell.java | 118 +++------------------ 2 files changed, 20 insertions(+), 106 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-core/pom.xml b/dsl/camel-jbang/camel-jbang-core/pom.xml index 31dccd48d50d..f236054ebe75 100644 --- a/dsl/camel-jbang/camel-jbang-core/pom.xml +++ b/dsl/camel-jbang/camel-jbang-core/pom.xml @@ -89,13 +89,13 @@ <version>${picocli-version}</version> </dependency> <dependency> - <groupId>info.picocli</groupId> - <artifactId>picocli-shell-jline3</artifactId> - <version>${picocli-version}</version> + <groupId>org.jline</groupId> + <artifactId>jline</artifactId> + <version>${jline-version}</version> </dependency> <dependency> <groupId>org.jline</groupId> - <artifactId>jline</artifactId> + <artifactId>jline-picocli</artifactId> <version>${jline-version}</version> </dependency> <dependency> diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java index 4eb84de7e2b5..b8a5f17a3a8e 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Shell.java @@ -18,33 +18,11 @@ package org.apache.camel.dsl.jbang.core.commands; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.function.Supplier; import org.apache.camel.util.HomeHelper; -import org.jline.builtins.ClasspathResourceUtil; -import org.jline.builtins.ConfigurationPath; -import org.jline.console.SystemRegistry; -import org.jline.console.impl.Builtins; -import org.jline.console.impl.SystemRegistryImpl; -import org.jline.keymap.KeyMap; -import org.jline.reader.Binding; -import org.jline.reader.EndOfFileException; +import org.jline.picocli.PicocliCommandRegistry; import org.jline.reader.LineReader; -import org.jline.reader.LineReaderBuilder; -import org.jline.reader.MaskingCallback; -import org.jline.reader.Parser; -import org.jline.reader.Reference; -import org.jline.reader.UserInterruptException; -import org.jline.reader.impl.DefaultHighlighter; -import org.jline.reader.impl.DefaultParser; -import org.jline.terminal.Terminal; -import org.jline.terminal.TerminalBuilder; -import org.jline.utils.AttributedStringBuilder; -import org.jline.utils.AttributedStyle; -import org.jline.utils.InfoCmp; -import org.jline.widget.TailTipWidgets; import picocli.CommandLine; -import picocli.shell.jline3.PicocliCommands; @CommandLine.Command(name = "shell", description = "Interactive Camel JBang shell.", @@ -57,86 +35,22 @@ public class Shell extends CamelCommand { @Override public Integer doCall() throws Exception { - Supplier<Path> workDir = () -> Paths.get(System.getProperty("user.dir")); - // set up JLine built-in commands - Path appConfig = ClasspathResourceUtil.getResourcePath("/nano/jnanorc", getClass()).getParent(); - Builtins builtins = new Builtins(workDir, new ConfigurationPath(appConfig, workDir.get()), null) { - @Override - public String name() { - return "built-in"; - } - }; - - PicocliCommands.PicocliCommandsFactory factory = new PicocliCommands.PicocliCommandsFactory(); - PicocliCommands commands = new PicocliCommands(CamelJBangMain.getCommandLine()); - commands.name("Camel"); - - try (Terminal terminal = TerminalBuilder.builder().build()) { - Parser parser = new DefaultParser(); - SystemRegistry systemRegistry = new SystemRegistryImpl(parser, terminal, workDir, null); - systemRegistry.setCommandRegistries(builtins, commands); - systemRegistry.register("help", commands); - - String history = Paths.get(HomeHelper.resolveHomeDir(), ".camel-jbang-history").toString(); - LineReader reader = LineReaderBuilder.builder() - .terminal(terminal) - .completer(systemRegistry.completer()) - .parser(parser) - .highlighter(new ReplHighlighter()) - .variable(LineReader.LIST_MAX, 50) // max tab completion candidates - .variable(LineReader.HISTORY_FILE, history) - .variable(LineReader.OTHERS_GROUP_NAME, "Others") - .variable(LineReader.COMPLETION_STYLE_GROUP, "fg:blue,bold") - .variable("HELP_COLORS", "ti=1;34:co=38:ar=3:op=33:de=90") - .option(LineReader.Option.GROUP_PERSIST, true) - .build(); - builtins.setLineReader(reader); - factory.setTerminal(terminal); - TailTipWidgets widgets - = new TailTipWidgets(reader, systemRegistry::commandDescription, 5, TailTipWidgets.TipType.COMPLETER); - widgets.enable(); - KeyMap<Binding> keyMap = reader.getKeyMaps().get("main"); - keyMap.bind(new Reference("tailtip-toggle"), KeyMap.alt("s")); - String prompt = "camel> "; - String rightPrompt = null; - - // start the shell and process input until the user quits with Ctrl-C or Ctrl-D - String line; - boolean run = true; - TerminalBuilder.setTerminalOverride(terminal); - while (run) { - try { - systemRegistry.cleanUp(); - line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null); - systemRegistry.execute(line); - } catch (UserInterruptException e) { - // ctrl + c is pressed so exit - run = false; - } catch (EndOfFileException e) { - // ctrl + d is pressed so exit - run = false; - } catch (Exception e) { - systemRegistry.trace(e); - } - } - } finally { - TerminalBuilder.setTerminalOverride(null); + PicocliCommandRegistry registry = new PicocliCommandRegistry(CamelJBangMain.getCommandLine()); + + Path history = Paths.get(HomeHelper.resolveHomeDir(), ".camel-jbang-history"); + + try (org.jline.shell.Shell shell = org.jline.shell.Shell.builder() + .prompt("camel> ") + .groups(registry) + .historyFile(history) + .historyCommands(true) + .helpCommands(true) + .commandHighlighter(true) + .variable(LineReader.LIST_MAX, 50) + .option(LineReader.Option.GROUP_PERSIST, true) + .build()) { + shell.run(); } return 0; } - - private static class ReplHighlighter extends DefaultHighlighter { - @Override - protected void commandStyle(LineReader reader, AttributedStringBuilder sb, boolean enable) { - if (enable) { - if (reader.getTerminal().getNumericCapability(InfoCmp.Capability.max_colors) >= 256) { - sb.style(AttributedStyle.DEFAULT.bold().foreground(69)); - } else { - sb.style(AttributedStyle.DEFAULT.foreground(AttributedStyle.CYAN)); - } - } else { - sb.style(AttributedStyle.DEFAULT.boldOff().foregroundOff()); - } - } - } }
