From 94b7bdf412f77d73994c7b0433c9ff5754f0575e Mon Sep 17 00:00:00 2001 From: caylipp Date: Fri, 15 May 2026 17:14:46 +0200 Subject: [PATCH 1/2] #836: add Changelog entry --- CHANGELOG.adoc | 1 + .../tools/ide/commandlet/ShellCommandlet.java | 29 ++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index bbfe750876..82b81cd0b1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -31,6 +31,7 @@ Release with new features and bugfixes: * https://github.com/devonfw/IDEasy/issues/800[#800]: Fix infinite recursion in Sonar start/stop on macOS * https://github.com/devonfw/IDEasy/issues/1716[#1716]: Add commandlet for Claude Code CLI * https://github.com/devonfw/IDEasy/issues/1844[#1844]: Fix vscode installation hanging indefinitely in WSL Linux environments +* https://github.com/devonfw/IDEasy/issues/1950[#1950]: Fix exit autocompletion The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/44?closed=1[milestone 2026.05.001]. diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java index 9667c9e269..5e855072d6 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java @@ -4,18 +4,19 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Iterator; +import java.util.List; import org.fusesource.jansi.AnsiConsole; +import org.jline.reader.Candidate; import org.jline.reader.Completer; 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.Parser; import org.jline.reader.UserInterruptException; import org.jline.reader.impl.DefaultParser; -import org.jline.reader.impl.completer.AggregateCompleter; -import org.jline.reader.impl.completer.StringsCompleter; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; import org.jline.widget.AutosuggestionWidgets; @@ -72,11 +73,23 @@ protected void doRun() { try { Parser parser = new DefaultParser(); try (Terminal terminal = TerminalBuilder.builder().build()) { - // initialize our own completer here and add exit as an autocompletion option - Completer completer = new AggregateCompleter( - new StringsCompleter("exit"), new IdeCompleter((AbstractIdeContext) this.context)); + IdeCompleter ideCompleter = new IdeCompleter((AbstractIdeContext) this.context); - LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(completer).parser(parser) + Completer shellCompleter = new Completer() { + @Override + public void complete(LineReader reader, ParsedLine commandLine, List candidates) { + String currentWord = commandLine.word(); + int wordIndex = commandLine.wordIndex(); + + if (wordIndex == 0 && !currentWord.isEmpty() && "exit".startsWith(currentWord)) { + candidates.add(new Candidate("exit")); + } + + ideCompleter.complete(reader, commandLine, candidates); + } + }; + + LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(shellCompleter).parser(parser) .variable(LineReader.LIST_MAX, AUTOCOMPLETER_MAX_RESULTS).build(); // Create autosuggestion widgets @@ -94,10 +107,6 @@ protected void doRun() { try { String prompt = context.getCwd() + "$ ide "; line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null); - line = line.trim(); - if (line.equals("exit")) { - return; - } reader.getHistory().add(line); int rc = runCommand(line); if (rc == RC_EXIT) { From d09cc8410149f8746c19e73ceae61827fd25ed48 Mon Sep 17 00:00:00 2001 From: caylipp Date: Wed, 20 May 2026 09:34:32 +0200 Subject: [PATCH 2/2] #836: address exit completion fix review feedback - restored exit command handling since it is actual shell functionality - removed anonymous completer wrapper - moved exit completion logic into IdeCompleter - added EXIT_COMMAND constant --- .../tools/ide/commandlet/ShellCommandlet.java | 30 ++++++------------- .../tools/ide/completion/IdeCompleter.java | 10 +++++++ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java index 5e855072d6..48991a73c0 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/ShellCommandlet.java @@ -4,16 +4,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Iterator; -import java.util.List; import org.fusesource.jansi.AnsiConsole; -import org.jline.reader.Candidate; -import org.jline.reader.Completer; 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.Parser; import org.jline.reader.UserInterruptException; import org.jline.reader.impl.DefaultParser; @@ -44,6 +40,8 @@ public final class ShellCommandlet extends Commandlet { private static final int RC_EXIT = 987654321; + private static final String EXIT_COMMAND = "exit"; + /** * The constructor. * @@ -73,23 +71,9 @@ protected void doRun() { try { Parser parser = new DefaultParser(); try (Terminal terminal = TerminalBuilder.builder().build()) { - IdeCompleter ideCompleter = new IdeCompleter((AbstractIdeContext) this.context); - - Completer shellCompleter = new Completer() { - @Override - public void complete(LineReader reader, ParsedLine commandLine, List candidates) { - String currentWord = commandLine.word(); - int wordIndex = commandLine.wordIndex(); - - if (wordIndex == 0 && !currentWord.isEmpty() && "exit".startsWith(currentWord)) { - candidates.add(new Candidate("exit")); - } + IdeCompleter completer = new IdeCompleter((AbstractIdeContext) this.context); - ideCompleter.complete(reader, commandLine, candidates); - } - }; - - LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(shellCompleter).parser(parser) + LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(completer).parser(parser) .variable(LineReader.LIST_MAX, AUTOCOMPLETER_MAX_RESULTS).build(); // Create autosuggestion widgets @@ -107,6 +91,10 @@ public void complete(LineReader reader, ParsedLine commandLine, List try { String prompt = context.getCwd() + "$ ide "; line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null); + line = line.trim(); + if (EXIT_COMMAND.equals(line)) { + return; + } reader.getHistory().add(line); int rc = runCommand(line); if (rc == RC_EXIT) { @@ -141,7 +129,7 @@ public void complete(LineReader reader, ParsedLine commandLine, List */ private int runCommand(String args) { - if ("exit".equals(args) || "quit".equals(args)) { + if (EXIT_COMMAND.equals(args) || "quit".equals(args)) { return RC_EXIT; } String[] arguments = args.split(" ", 0); diff --git a/cli/src/main/java/com/devonfw/tools/ide/completion/IdeCompleter.java b/cli/src/main/java/com/devonfw/tools/ide/completion/IdeCompleter.java index 3051cf309c..ade9d6866d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/completion/IdeCompleter.java +++ b/cli/src/main/java/com/devonfw/tools/ide/completion/IdeCompleter.java @@ -15,6 +15,8 @@ */ public class IdeCompleter implements Completer { + private static final String EXIT_COMMAND = "exit"; + private final AbstractIdeContext context; /** @@ -30,6 +32,14 @@ public IdeCompleter(AbstractIdeContext context) { @Override public void complete(LineReader reader, ParsedLine commandLine, List candidates) { + + String currentWord = commandLine.word(); + int wordIndex = commandLine.wordIndex(); + + if (wordIndex == 0 && !currentWord.isEmpty() && EXIT_COMMAND.startsWith(currentWord)) { + candidates.add(new Candidate(EXIT_COMMAND)); + } + List words = commandLine.words(); CliArguments args = CliArguments.ofCompletion(words.toArray(String[]::new)); List completion = this.context.complete(args, true);