Skip to content

completion: fix bash and zsh shell completion when completing aliases of multiple arguments #6407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 29, 2025

Conversation

jgreitemann
Copy link
Contributor

Fixes #5377.

The fix ended up as exactly like @yuja mentioned in the issue and what the TODO comment in the code was already proposing. Still, it took a fair bit of fiddling around with the different shells to understand where they are differing in behavior exactly.

I've gotten a wee bit carried away refactoring the existing tests to cover multiple shells (where sensible) without duplicating too much of the test code. Even so, insta needs a match over the different shell flavors to snapshot their output individually. For a while, I've entertained the idea of adding a .normalize_shell_completions(shell) function on the test output to basically strip away the comment (because bash doesn't have that) such that it would produce the same (normalized) output for each shell and we could do away with the matches. Obviously, that would lose the comment snapshots, so I decided against it for now. Let me know if that's something you want me to revisit.

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added tests to cover my changes

@jgreitemann jgreitemann requested a review from a team as a code owner April 24, 2025 17:26
Copy link
Member

@steadmon steadmon left a comment

Choose a reason for hiding this comment

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

Generally LGTM, but I'm not familiar with completion details so it might be worth having an expert review.

Copy link
Contributor

@yuja yuja left a comment

Choose a reason for hiding this comment

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

The implementation looks good, thanks.

Copy link
Contributor

@yuja yuja left a comment

Choose a reason for hiding this comment

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

Thanks!

The completion mechanism works differently in different shells:

For example, when the command line `jj aaa bb ccc` is completed at the
end of the `bb` token, bash and zsh pass the completer the whole line
`-- jj aaa bb ccc` and an index of 2 which refers to the `bb` token;
they are then expected to complete `bb`. Meanwhile, fish and Powershell
only pass the command up to the completion point, so `-- jj aaa bb`;
the completer is always expected to complete the last token. In all
cases, the shell ultimately decides what to do with the completions,
e.g. to complete up to a common prefix (bash), to show an interactive
picker (zsh, fish), or to insert the completion if it is the only one
(all shells). Remaining tokens (`ccc`) are also always appended by the
shell and not part of the completion.

While this is mostly handled by the clap_complete crate, we do expand
aliases and present clap_complete with a fake view of the real command
line, thereby reaching into its internals by wrapping the interface
between the completion shell script that is provided by clap_complete
and its Rust code in `CommandEnv::try_complete()`. If we get this wrong,
completion might yield unexpected results, so it is worth testing
completion for both flavors of shells whenever aliases are potentially
in the mix.

To avoid redundancy, the shell-specific invocation of `jj` is factored
into a `complete_at()` function of the test fixture. The `test-case`
crate is then used to instantiate each test case for different values of
clap_complete's `Shell` enum.

filter

bash/zsh specific behavior

move impl
…n bash and zsh

This also adds a test case for the completion of arguments following
multi-argument aliases, to cover the bug reported in issue #5377.

The default command is like a special kind of alias, one which is
expanded from zero tokens. Consequently, it also triggers the bug
#5377 on bash/zsh, even if the `default-command` is just a single token.

The fix is along the lines sketched out by the "TODO" comment. Bash and
Zsh don't behave identical, so the padding ([""]) still needs to be
applied (and removed) conditionally in a disciplined manner.
@jgreitemann jgreitemann added this pull request to the merge queue Apr 29, 2025
Merged via the queue into main with commit 9289840 Apr 29, 2025
28 checks passed
@jgreitemann jgreitemann deleted the push-rxquwlluvknr branch April 29, 2025 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Argument completion in bash doesn't work for aliases with arguments
4 participants