Skip to content

Dynamic shell completion issues: missing file completions, duplicate negatable entries, no prefix filtering #443

@stalep

Description

@stalep

Summary

When using --aesh-complete for dynamic shell completion (fish/bash/zsh), several issues prevent parity with what users expect from a CLI framework:

Issues

1. Positional argument position shows options instead of file completions

When the cursor is at a positional argument position (no - prefix), aesh lists all -- options instead of offering file/path completions.

$ jbang --aesh-complete -- "run "
--help	Display help (use --help=all for all options)
--runtime-option	Options to pass to the Java runtime
...

Expected: Since run has an @Argument of type String (representing a script file), it should offer file/path completions when no prefix is typed — not dump all options.

Root cause: AeshRuntimeRunner.handleDynamicCompletion() does not check whether the cursor position corresponds to a positional argument (hasArgument()/hasArguments()) and does not fall back to file completions when appropriate.

2. Negatable options shown as two separate entries

Options with negatable = true produce two separate completion candidates:

--cds	If specified Class Data Sharing (CDS) will be used...
--no-cds

Expected: A single combined entry like --[no-]cds with the description, or at minimum only the base form --cds with a description noting the --no- prefix.

3. Short option prefix does not filter candidates

Typing -a<tab> lists all short options (including those not starting with a) plus all long options:

$ jbang -a<tab>
# shows -R, -d, -i, -c, --help, --runtime-option, ... everything

Expected: Only short options starting with -a should be shown (or none if no match exists).

4. Already-used options still appear in completion candidates

Options that have already been specified on the command line are still listed as completion candidates:

$ jbang run --offline --<tab>
# --offline still appears in the list

Expected: Options already present on the command line should be excluded from candidates (unless they are repeatable).

Reproduction

All issues can be reproduced with any aesh-based CLI using --aesh-complete:

# Issue 1: options shown instead of file completions
java -jar app.jar --aesh-complete -- "subcommand "

# Issue 2: check for negatable options in output
java -jar app.jar --aesh-complete -- "subcommand --"

# Issue 3: short option prefix
java -jar app.jar --aesh-complete -- "-a"

# Issue 4: already-used options
java -jar app.jar --aesh-complete -- "subcommand --verbose --"

Context

These were found while porting jbang from picocli to aesh (PR jbangdev/jbang#2453). The previous picocli-based completion handled all four cases correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions