This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch Guillaume-Nodet/jbang-improvements in repository https://gitbox.apache.org/repos/asf/camel.git
commit 834c15d48a97d460adccc61bbb0d1606ed014e87 Author: Guillaume Nodet <[email protected]> AuthorDate: Mon Mar 23 08:37:17 2026 +0100 CAMEL-23224: Switch JBang shell to JLine 4 PicocliCommandRegistry - Replace picocli-shell-jline3 with JLine 4's built-in jline-picocli module which provides PicocliCommandRegistry with proper argument completion via picocli's AutoComplete - Simplify Shell.java using JLine 4's Shell.builder() API - Bump JLine version to 4.0.8-1-SNAPSHOT (pending JLine release) Co-Authored-By: Claude Opus 4.6 <[email protected]> --- dsl/camel-jbang/camel-jbang-core/pom.xml | 6 +- .../camel/dsl/jbang/core/commands/Shell.java | 120 ++++----------------- parent/pom.xml | 2 +- 3 files changed, 23 insertions(+), 105 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-core/pom.xml b/dsl/camel-jbang/camel-jbang-core/pom.xml index 31dccd48d50d..29d34469f198 100644 --- a/dsl/camel-jbang/camel-jbang-core/pom.xml +++ b/dsl/camel-jbang/camel-jbang-core/pom.xml @@ -89,9 +89,9 @@ <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-picocli</artifactId> + <version>${jline-version}</version> </dependency> <dependency> <groupId>org.jline</groupId> 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..ed4046bc4d77 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 @@ -16,35 +16,13 @@ */ 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,26 @@ 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"; + PicocliCommandRegistry registry = new PicocliCommandRegistry(CamelJBangMain.getCommandLine()); + + String history = Paths.get(HomeHelper.resolveHomeDir(), ".camel-jbang-history").toString(); + + try (org.jline.shell.Shell shell = org.jline.shell.Shell.builder() + .prompt("camel> ") + .groups(registry) + .historyFile(Paths.get(history)) + .commandHighlighter(true) + .helpCommands(true) + .variable(LineReader.LIST_MAX, 50) + .build()) { + + TerminalBuilder.setTerminalOverride(shell.terminal()); + try { + shell.run(); + } finally { + TerminalBuilder.setTerminalOverride(null); } - }; - - 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); } 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()); - } - } - } } diff --git a/parent/pom.xml b/parent/pom.xml index 625fc58218fe..dfc6e3581579 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -324,7 +324,7 @@ <jgroups-raft-leveldbjni-version>1.8</jgroups-raft-leveldbjni-version> <jgroups-raft-mapdb-version>1.0.8</jgroups-raft-mapdb-version> <jira-rest-client-api-version>6.0.2</jira-rest-client-api-version> - <jline-version>4.0.7</jline-version> + <jline-version>4.0.8-1-SNAPSHOT</jline-version> <libthrift-version>0.22.0</libthrift-version> <jodatime2-version>2.14.1</jodatime2-version> <jolokia-version>2.5.1</jolokia-version>
