diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java index 7c61d3684..bfce6451d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java @@ -134,13 +134,13 @@ protected void add(Commandlet commandlet) { KeywordProperty keyword = commandlet.getFirstKeyword(); if (keyword != null) { String name = keyword.getName(); - this.firstKeywordMap.putIfAbsent(name, commandlet); + registerKeyword(name, commandlet); if (name.startsWith("--")) { - this.firstKeywordMap.putIfAbsent(name.substring(2), commandlet); + registerKeyword(name.substring(2), commandlet); } String alias = keyword.getAlias(); if (alias != null) { - this.firstKeywordMap.putIfAbsent(alias, commandlet); + registerKeyword(alias, commandlet); } } for (int i = 0; i < propertyCount; i++) { @@ -160,6 +160,14 @@ protected void add(Commandlet commandlet) { } } + private void registerKeyword(String keyword, Commandlet commandlet) { + + Commandlet duplicate = this.firstKeywordMap.putIfAbsent(keyword, commandlet); + if (duplicate != null) { + this.context.debug("Duplicate keyword {} already used by {} so it cannot be associated also with {}", keyword, duplicate, commandlet); + } + } + @Override public Collection getCommandlets() { diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java index 426b03f16..c3b434ef9 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/HelpCommandlet.java @@ -38,7 +38,7 @@ public final class HelpCommandlet extends Commandlet { public HelpCommandlet(IdeContext context) { super(context); - addKeyword(getName()); + addKeyword("--help", "-h"); this.commandlet = add(new CommandletProperty("", false, "commandlet")); } diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java index 3a1a7cc8a..26aa65858 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java +++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/VersionCommandlet.java @@ -17,13 +17,13 @@ public class VersionCommandlet extends Commandlet { public VersionCommandlet(IdeContext context) { super(context); - addKeyword(getName(), "-v"); + addKeyword("--version", "-v"); } @Override public String getName() { - return "--version"; + return "version"; } @Override diff --git a/cli/src/main/java/com/devonfw/tools/ide/property/KeywordProperty.java b/cli/src/main/java/com/devonfw/tools/ide/property/KeywordProperty.java index 74d0574ad..fd615e876 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/property/KeywordProperty.java +++ b/cli/src/main/java/com/devonfw/tools/ide/property/KeywordProperty.java @@ -10,6 +10,8 @@ */ public class KeywordProperty extends BooleanProperty { + private final String optionName; + /** * The constructor. * @@ -19,8 +21,17 @@ public class KeywordProperty extends BooleanProperty { */ public KeywordProperty(String name, boolean required, String alias) { - super(name, required, alias); + super(getNormalizedName(name), required, alias); + this.optionName = name; + } + + private static String getNormalizedName(String name) { + assert !name.isEmpty(); + if (name.startsWith("--")) { + return name.substring(2); + } + return name; } @Override @@ -35,6 +46,25 @@ public boolean isExpectValue() { return false; } + @Override + public boolean matches(String nameOrAlias) { + + if (super.matches(nameOrAlias)) { + return true; + } + return this.optionName.equals(nameOrAlias); + } + + @Override + public boolean apply(CliArguments args, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) { + + String normalizedName = this.name; + if (args.current().isOption()) { + normalizedName = this.optionName; + } + return apply(normalizedName, args, context, commandlet, collector); + } + @Override protected boolean applyValue(String argValue, boolean lookahead, CliArguments args, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) { diff --git a/cli/src/main/java/com/devonfw/tools/ide/property/Property.java b/cli/src/main/java/com/devonfw/tools/ide/property/Property.java index 16ed1f71a..4898f4b2d 100644 --- a/cli/src/main/java/com/devonfw/tools/ide/property/Property.java +++ b/cli/src/main/java/com/devonfw/tools/ide/property/Property.java @@ -253,6 +253,10 @@ public void clearValue() { this.value.clear(); } + /** + * @param value the value to add to the {@link List} of values. + * @see #isMultiValued() + */ public void addValue(V value) { if (!this.multivalued) { @@ -331,13 +335,26 @@ protected V getNullValue() { */ public boolean apply(CliArguments args, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) { + return apply(this.name, args, context, commandlet, collector); + } + + /** + * @param normalizedName the {@link #getName() name} or potentially a normalized form of it (see {@link KeywordProperty}). + * @param args the {@link CliArguments} already {@link CliArguments#current() pointing} the {@link CliArgument} to apply. + * @param context the {@link IdeContext}. + * @param commandlet the {@link Commandlet} owning this property. + * @param collector the {@link CompletionCandidateCollector}. + * @return {@code true} if it matches, {@code false} otherwise. + */ + protected boolean apply(String normalizedName, CliArguments args, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) { + CliArgument argument = args.current(); if (argument.isCompletion()) { int size = collector.getCandidates().size(); - complete(argument, args, context, commandlet, collector); + complete(normalizedName, argument, args, context, commandlet, collector); return (collector.getCandidates().size() > size); } - boolean option = isOption(); + boolean option = normalizedName.startsWith("-"); if (option && !argument.isOption()) { return false; } @@ -346,7 +363,7 @@ public boolean apply(CliArguments args, IdeContext context, Commandlet commandle } String argValue = null; boolean lookahead = false; - if (this.name.isEmpty()) { + if (normalizedName.isEmpty()) { argValue = argument.get(); } else { if (!matches(argument.getKey())) { @@ -398,16 +415,18 @@ protected boolean applyValue(String argValue, boolean lookahead, CliArguments ar /** * Performs auto-completion for the {@code arg}. * + * @param normalizedName the {@link #getName() name} or potentially a normalized form of it (see {@link KeywordProperty}). * @param argument the {@link CliArgument CLI argument}. * @param args the {@link CliArguments}. * @param context the {@link IdeContext}. * @param commandlet the {@link Commandlet} owning this {@link Property}. * @param collector the {@link CompletionCandidateCollector}. */ - protected void complete(CliArgument argument, CliArguments args, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) { + protected void complete(String normalizedName, CliArgument argument, CliArguments args, IdeContext context, Commandlet commandlet, + CompletionCandidateCollector collector) { String arg = argument.get(); - if (this.name.isEmpty()) { + if (normalizedName.isEmpty()) { int count = collector.getCandidates().size(); completeValue(arg, context, commandlet, collector); if (collector.getCandidates().size() > count) { @@ -415,8 +434,8 @@ protected void complete(CliArgument argument, CliArguments args, IdeContext cont } return; } - if (this.name.startsWith(arg)) { - collector.add(this.name, null, this, commandlet); + if (normalizedName.startsWith(arg)) { + collector.add(normalizedName, null, this, commandlet); } if (this.alias != null) { if (this.alias.startsWith(arg)) { @@ -431,7 +450,7 @@ protected void complete(CliArgument argument, CliArguments args, IdeContext cont String value = argument.getValue(); if (value != null) { String key = argument.getKey(); - if (this.name.equals(key) || Objects.equals(this.alias, key)) { + if (normalizedName.equals(key) || Objects.equals(this.alias, key)) { completeValue(value, context, commandlet, new CompletionCandidateCollectorAdapter(key + "=", collector)); } } diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties index a9c0f5c5e..42486803f 100644 --- a/cli/src/main/resources/nls/Help.properties +++ b/cli/src/main/resources/nls/Help.properties @@ -1,5 +1,3 @@ -cmd.--version=Print the version of IDEasy. -cmd.--version.detail=To print the current version of IDEasy simply type: 'ide --version'. cmd.android-studio=Tool commandlet for Android Studio (IDE). cmd.android-studio.detail=The android-studio commandlet allows to install, configure, and launch Android Studio. To launch Android Studio for your current workspace and IDEasy installation, simply run: ide android-studio. Detailed documentation can be found at https://developer.android.com/studio/. cmd.aws=Tool commandlet for AWS CLI. @@ -110,6 +108,8 @@ cmd.uninstall-plugin.detail=Plugins can be only installed or uninstalled for too cmd.uninstall.detail=Can be used to uninstall any tool e.g. to uninstall java simply type: 'uninstall java'. cmd.update=Pull your settings and apply updates (software, configuration and repositories). cmd.update.detail=To update your IDE (if instructed by your ide-admin), you only need to run the following command: 'ide update'. +cmd.version=Print the version of IDEasy. +cmd.version.detail=To print the current version of IDEasy simply type: 'ide --version'. cmd.vscode=Tool commandlet for Visual Studio Code (IDE). cmd.vscode.detail=Visual Studio Code (VS Code) is a popular code editor developed by Microsoft. Detailed documentation can be found at https://code.visualstudio.com/docs/ commandlets=Available commandlets: diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties index 7893ace3e..3e7af8e8c 100644 --- a/cli/src/main/resources/nls/Help_de.properties +++ b/cli/src/main/resources/nls/Help_de.properties @@ -1,5 +1,3 @@ -cmd.--version=Gibt die Version von IDEasy aus. -cmd.--version.detail=Um die aktuelle Version von IDEasy auszugeben, brauchen Sie einfach nur 'ide --version' in die Konsole eingeben. cmd.android-studio=Werkzeug Kommando für Android Studio (IDE). cmd.android-studio.detail=Das android-studio Kommando ermöglicht die Installation, Konfiguration und den Start von Android Studio. Um Android Studio für Ihren aktuellen Arbeitsbereich und die IDEasy-Installation zu starten, führen Sie einfach: 'ide android-studio' aus. Detaillierte Dokumentation finden Sie unter https://developer.android.com/studio/. cmd.aws=Werkzeug Kommando für AWS Kommandoschnittstelle. @@ -110,6 +108,8 @@ cmd.uninstall-plugin.detail=Erweiterung können nur für Werkzeuge installiert u cmd.uninstall.detail=Wird dazu verwendet um jedwedes Werkzeug zu deinstallieren. Um z.B. Java zu deinstallieren geben Sie einfach 'uninstall java' in die Konsole ein. cmd.update=Updatet die Settings, Software und Repositories. cmd.update.detail=Um die IDE auf den neuesten Stand zu bringen (falls von Ihrem Admin angewiesen) geben Sie einfach 'ide update' in die Konsole ein. +cmd.version=Gibt die Version von IDEasy aus. +cmd.version.detail=Um die aktuelle Version von IDEasy auszugeben, brauchen Sie einfach nur 'ide --version' in die Konsole eingeben. cmd.vscode=Werkzeug Kommando für Visual Studio Code (IDE). cmd.vscode.detail=Visual Studio Code (VS Code) ist ein beliebter Code-Editor, der von Microsoft entwickelt wurde. Detaillierte Dokumentation ist zu finden unter https://code.visualstudio.com/docs/ commandlets=Verfügbare Kommandos: diff --git a/cli/src/test/java/com/devonfw/tools/ide/completion/CompleteTest.java b/cli/src/test/java/com/devonfw/tools/ide/completion/CompleteTest.java index 087cfbc69..9ccb62a4f 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/completion/CompleteTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/completion/CompleteTest.java @@ -11,6 +11,7 @@ import com.devonfw.tools.ide.commandlet.ContextCommandlet; import com.devonfw.tools.ide.context.AbstractIdeContext; import com.devonfw.tools.ide.context.IdeContextTest; +import com.devonfw.tools.ide.property.KeywordProperty; import com.devonfw.tools.ide.property.Property; /** @@ -92,7 +93,7 @@ public void testCompleteShortOptsCombined() { // act List candidates = context.complete(args, true); // assert - assertThat(candidates.stream().map(CompletionCandidate::text)).containsExactly("-f", "-fb", "-fd", "-fo", "-fq", + assertThat(candidates.stream().map(CompletionCandidate::text)).containsExactly("-f", "-fb", "-fd", "-fh", "-fo", "-fq", "-ft", "-fv"); } @@ -106,7 +107,7 @@ public void testCompleteShortOptsCombinedAllButVersion() { // act List candidates = context.complete(args, true); // assert - assertThat(candidates.stream().map(CompletionCandidate::text)).containsExactly("-fbdoqt", "-fbdoqtv"); + assertThat(candidates.stream().map(CompletionCandidate::text)).containsExactly("-fbdoqt", "-fbdoqth", "-fbdoqtv"); } /** Test of {@link AbstractIdeContext#complete(CliArguments, boolean) auto-completion} for input "help", "". */ @@ -151,7 +152,7 @@ public void testCompleteCommandletOption() { } private static List getExpectedCandidates(AbstractIdeContext context, boolean commandlets, - boolean ctxOptions, boolean addVersionAlias) { + boolean ctxOptions, boolean addAlias) { List expectedCandidates = new ArrayList<>(); if (ctxOptions) { @@ -167,9 +168,14 @@ private static List getExpectedCandidates(AbstractIdeContext context, bo if (commandlets) { for (Commandlet cmd : context.getCommandletManager().getCommandlets()) { expectedCandidates.add(cmd.getName()); - } - if (addVersionAlias) { - expectedCandidates.add("-v"); // alias for VersionCommandlet (--version) + if (addAlias) { + Property firstProperty = cmd.getValues().get(0); + assert (firstProperty instanceof KeywordProperty); + String alias = firstProperty.getAlias(); + if (alias != null) { + expectedCandidates.add(alias); + } + } } } Collections.sort(expectedCandidates); diff --git a/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java b/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java index 2c4318f86..969faf909 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/property/CommandletPropertyTest.java @@ -18,22 +18,31 @@ class CommandletPropertyTest { @Test public void testCompleteValue() { + + // arrange IdeContext context = IdeTestContextMock.get(); String[] expectedCandidates = { "help", "helm" }; String input = "he"; CompletionCandidateCollector collector = new CompletionCandidateCollectorDefault(context); - CommandletProperty cmdProp = new CommandletProperty("", false, ""); + + // act cmdProp.completeValue(input, context, new ContextCommandlet(), collector); + // assert assertThat(collector.getCandidates().stream().map(CompletionCandidate::text)).containsExactlyInAnyOrder(expectedCandidates); } @Test public void testParse() { + + // arrange IdeContext context = IdeTestContextMock.get(); + + // act CommandletProperty cmdProp = new CommandletProperty("", false, ""); + // act + assert assertThat(cmdProp.parse("help", context)).isInstanceOf(HelpCommandlet.class); assertThat(cmdProp.parse("helm", context)).isInstanceOf(Helm.class); assertThat(cmdProp.parse("intellij", context)).isInstanceOf(Intellij.class);