Skip to content

#1392: smart completions#1999

Open
Caylipp wants to merge 18 commits into
devonfw:mainfrom
Caylipp:feature/1392-smart-completions
Open

#1392: smart completions#1999
Caylipp wants to merge 18 commits into
devonfw:mainfrom
Caylipp:feature/1392-smart-completions

Conversation

@Caylipp

@Caylipp Caylipp commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #1392

Implemented changes:

  • Add AutoCompletionRegistry for tool-specific completion candidates
  • Add ToolArgumentsProperty for completing tool arguments
  • Delegate tool argument completion from ToolArgumentsProperty to ToolCommandlet
  • Add default empty completion registry in ToolCommandlet
  • Add initial Maven completion candidates in Mvn

Testing instructions

Please add conscise, understandable instructions on how a reviewer can test/verify the functionality of your contribution here:

  1. Create an run configuration for IDEasy.
  2. Set the program arguments to: -q complete mvn cl
  3. Verify that Maven goals and options are listed, e.g.: clean

Additionally, you can use the end-to-end testing script to test the completion natively in your terminal (#2011).


Checklist for this PR

Make sure everything is checked before merging this PR. For further info please also see
our DoD.

  • When running mvn clean test locally all tests pass and build is successful
  • PR title is of the form #«issue-id»: «brief summary» (e.g. #921: fixed setup.bat). If no issue ID exists, title only.
  • PR top-level comment summarizes what has been done and contains link to addressed issue(s)
  • PR and issue(s) have suitable labels
  • Issue is set to In Progress and assigned to you or there is no issue (might happen for very small PRs)
  • You followed all coding conventions
  • You have added the issue implemented by your PR in CHANGELOG.adoc unless issue is labeled
    with internal
  • You have formulated clear instructions on how to test your contribution under "Testing instructions"

Caylipp added 2 commits June 2, 2026 15:02
- Add AutoCompletionRegistry
- Add ToolArgumentsProperty
- Delegate tool argument completion to ToolCommandlet
- Add initial Maven completion entries
- Keep default registry empty
@github-project-automation github-project-automation Bot moved this to 🆕 New in IDEasy board Jun 2, 2026
@Caylipp Caylipp self-assigned this Jun 2, 2026
@Caylipp Caylipp moved this from 🆕 New to Team Review in IDEasy board Jun 2, 2026
@Caylipp Caylipp added enhancement New feature or request completion auto-completion in bash or build in CLI labels Jun 2, 2026
@coveralls

coveralls commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 27616222521

Coverage increased (+0.04%) to 71.325%

Details

  • Coverage increased (+0.04%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 107 coverage regressions across 6 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

107 previously-covered lines in 6 files lost coverage.

File Lines Losing Coverage Coverage
com/devonfw/tools/ide/tool/ToolCommandlet.java 57 73.67%
com/devonfw/tools/ide/context/AbstractIdeContext.java 28 66.97%
com/devonfw/tools/ide/tool/mvn/Mvn.java 18 84.69%
com/devonfw/tools/ide/cli/CliArguments.java 2 64.15%
com/devonfw/tools/ide/tool/ide/IdeToolCommandlet.java 1 78.33%
com/devonfw/tools/ide/version/VersionSegment.java 1 90.55%

Coverage Stats

Coverage Status
Relevant Lines: 16274
Covered Lines: 12104
Line Coverage: 74.38%
Relevant Branches: 7266
Covered Branches: 4686
Branch Coverage: 64.49%
Branches in Coverage %: Yes
Coverage Strength: 3.15 hits per line

💛 - Coveralls

@hohwille hohwille added this to the release:2026.06.001 milestone Jun 3, 2026
@AdemZarrouki AdemZarrouki self-assigned this Jun 3, 2026

@AdemZarrouki AdemZarrouki left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice Job. You extended the auto complition for mvn.

@AdemZarrouki

AdemZarrouki commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

When testing with GraalVM using ide shell, i typed ide mvn -Dexec.m and then pressed tab but the shell was not responding anymore. @Caylipp can you check the cause of this. Aslo tried to run it in a junit test

  @Test
  void testCompleteMavenToolArguments() {

    // arrange
    AbstractIdeContext context = newContext(PROJECT_BASIC, null, false);
    CliArguments args = CliArguments.ofCompletion("mvn", "-Dexec.main");

    // act
    List<CompletionCandidate> candidates = context.complete(args, true);

    // assert
    assertThat(candidates.stream().map(CompletionCandidate::text))
        .contains("-Dexec.mainClass=");
  }

but the test was running for ever

@AdemZarrouki AdemZarrouki self-requested a review June 4, 2026 11:16
@Caylipp

Caylipp commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

When testing with GraalVM using ide shell, i typed ide mvn -Dexec.m and then pressed tab but the shell was not responding anymore. @Caylipp can you check the cause of this. Aslo tried to run it in a junit test

  @Test
  void testCompleteMavenToolArguments() {

    // arrange
    AbstractIdeContext context = newContext(PROJECT_BASIC, null, false);
    CliArguments args = CliArguments.ofCompletion("mvn", "-Dexec.main");

    // act
    List<CompletionCandidate> candidates = context.complete(args, true);

    // assert
    assertThat(candidates.stream().map(CompletionCandidate::text))
        .contains("-Dexec.mainClass=");
  }

but the test was running for ever

Thanks for pointing this out.
I found and fixed the issue. The problem was that -Dexec.m was treated as an option because it starts with -. However, in this case it is not an IDEasy option, but a Maven argument.
If no matching option was found, the completion logic did not advance the current argument and ended up in an endless loop. I added a fallback to value completion for this case.
I tested complete mvn -Dexec.m locally in the shell.

@AdemZarrouki

Copy link
Copy Markdown
Contributor

I tested the new fix and the endless loop wasn't present anymore. The only problem is that in the issue its stated that
"Also be aware that those "keywords" above that end with = are not complete so they should not add a whitespace after its completion" but when testing the auto-completion with -Dexec.mainClass= and -Dexec.args= i get a whitespace after =. This need to be fixed.

@Caylipp

Caylipp commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

I tested the new fix and the endless loop wasn't present anymore. The only problem is that in the issue its stated that "Also be aware that those "keywords" above that end with = are not complete so they should not add a whitespace after its completion" but when testing the auto-completion with -Dexec.mainClass= and -Dexec.args= i get a whitespace after =. This need to be fixed.

You’re right, thanks for pointing this out.
The issue was caused by Bash automatically appending a whitespace after completion. I’ve fixed it in the _ide_completion function by applying compopt -o nospace for candidates ending with =.

@Caylipp

Caylipp commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Also fixed completion for : (e.g. dependency:list) by removing it from COMP_WORDBREAKS to prevent Bash from splitting the argument.

@AdemZarrouki AdemZarrouki left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good Job @Caylipp. You fixed the issue. I left a small comment regarding line break in javadoc that need to be removed

@Caylipp Caylipp force-pushed the feature/1392-smart-completions branch from 699b08e to f7e0575 Compare June 11, 2026 07:36
@Caylipp Caylipp moved this from Team Review to 👀 In review in IDEasy board Jun 11, 2026
@Caylipp Caylipp mentioned this pull request Jun 15, 2026
7 tasks

@hohwille hohwille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Caylipp thanks for your PR. Looks really nice now. Great work 👍
I have to admit that I do not fully understand the workaround for the = handling.
Is that maybe because = is by default in COMP_WORDBREAKS?
I guess this is for situations where we have --option=val[TAB] and want to get --option=value. So what is by default braking here? Is a space added before or directly after the equals sign?
Then I get at least the compopt -o nospace workaround.

Comment on lines +1509 to +1520
if (!matchedOption) {
if (valueIterator.hasNext()) {
Property<?> valueProperty = valueIterator.next();
boolean success = valueProperty.apply(arguments, this, cmd, collector);
if (!success) {
LOG.trace("Completion cannot match option or value.");
}
} else {
LOG.trace("No value left for completion.");
}
return;
}

@hohwille hohwille Jun 15, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like copy&paste of code (from outer else block). Could be avoided by taking the original code out of the else and add a separate condition by the new flag.
However, is it correct to complete from valueIterator if we are inside if-condition currentArgument.isOption()? This code does not really make sense to me.
In case I am missing something, please let me know...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now guess the problem is that for mvn you want to complete options like -DskipTests as part of the ToolArgumentsProperty.
If that is the correct understanding, then IMHO the proper fix would be that ToolArgumentsProperty should implicitly trigger endOptions() on CliArguments.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For multi-valued properties like here we have this:

if ((property != null) && property.isValue() && property.isMultiValued()) {
arguments.stopSplitShortOptions();
}

However, in this code:

if (currentArgument.isOption() && !arguments.isEndOptions()) {

Wo do check for !isEndOptions() but not for isSplitShortOpts().

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in this multi-valued property scenario we should call endOptions() instead of stopSplitShortOptions()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that makes sense.

The fallback was introduced to handle cases like -Dexec..., which are treated as options due to the leading -, but are actually tool arguments. So if no matching IDE option is found, the fallback allows completing them via the value logic. But I agree that this is not a cleanest solution, as it mixes option and value handling and duplicates logic from the value branch. Your suggestion makes more sense: treating ToolArgumentsProperty explicitly as values by triggering endOptions() avoids the need for the fallback. I'll rework the solution in that direction.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored this now so we no longer jump from option completion into value completion directly.
Instead, the code now uses isEndOptions() to stop option parsing when a value property requires it. This way, tool arguments like -Dexec.* are handled by the normal value completion flow.

Comment thread cli/src/main/package/functions Outdated
COMPREPLY=( $(ideasy -q complete ${COMP_WORDS[@]:1}) )
fi

# keywords ending with "=" remove whitespace

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# keywords ending with "=" remove whitespace
# keywords ending with "=" remove whitespace

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the comment.

Comment thread cli/src/main/package/functions Outdated
}

# remove ":" from word breaks for correct completion
if [ -n "${BASH_VERSION:-}" ]; then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand the condition. Should this not run in zsh?
I would rather expect something like this:

Suggested change
if [ -n "${BASH_VERSION:-}" ]; then
if [ -n "${COMP_WORDBREAKS}" ]; then

If I misunderstood, then maybe you could improve the comment above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I used BASH_VERSION because I considered COMP_WORDBREAKS to be Bash specific and wanted to make sure the workaround only runs in Bash.
I did not consider the zsh case here. But checking COMP_WORDBREAKS directly makes more sense here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the condition to check COMP_WORDBREAKS directly instead of BASH_VERSION.

@Caylipp

Caylipp commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@Caylipp thanks for your PR. Looks really nice now. Great work 👍 I have to admit that I do not fully understand the workaround for the = handling. Is that maybe because = is by default in COMP_WORDBREAKS? I guess this is for situations where we have --option=val[TAB] and want to get --option=value. So what is by default braking here? Is a space added before or directly after the equals sign? Then I get at least the compopt -o nospace workaround.

The whitespace issue is not caused by = being part of COMP_WORDBREAKS. Instead, this is Bash's default behavior: after inserting a completion candidate, Bash appends a space by default because it assumes the token is complete. Since in the issue (#1392) is mentioned "those "keywords" above that end with = are not complete so they should not add a whitespace after its completion", this assumption would be incorrect. Using compopt -o nospace prevents Bash from appending this whitespace.

In case of : (e.g. dependency:list), the problem is different. Here : is part of COMP_WORDBREAKS, so Bash stops completion at dependency:. Therefore, adjusting COMP_WORDBREAKS is required to allow completing the full token dependency:list.

@hohwille hohwille changed the title #1392 smart completions #1392: smart completions Jun 16, 2026
@Caylipp

Caylipp commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

I also noticed one additional edge case while retesting: ide mvn --<TAB> currently does not show the expected --... Maven suggestions, while ide mvn -<TAB> works.
This seems to be a separate parsing edge case around --, since -- can also be interpreted as the end-of-options marker.

@Caylipp

Caylipp commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

I did some debugging on this. For ideasy -q complete mvn --, the argument -- is already consumed during the initial parsing (before CompleteCommandlet.doRun() is called) so it never reaches the completion logic in CliArguments.ofCompletion(...).
That is why mvn --<TAB> currently does not work, while mvn -<TAB> and mvn --a<TAB> do.
So this seems to be a parsing limitation where -- is treated as end-of-options too early for the completion use case.
Since the release is close and the main Maven smart completion cases are working now, I would suggest tracking this -- edge case separately unless you think it should still be included in this PR.

I also noticed one additional edge case while retesting: ide mvn --<TAB> currently does not show the expected --... Maven suggestions, while ide mvn -<TAB> works. This seems to be a separate parsing edge case around --, since -- can also be interpreted as the end-of-options marker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

completion auto-completion in bash or build in CLI enhancement New feature or request

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

Smart completion

5 participants