-
Notifications
You must be signed in to change notification settings - Fork 335
Improve bash completion script generation #735
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
Conversation
3aa4fbf
to
c848407
Compare
@natecook1000 Just rebased on the new FYI: there are tons of TODOs in the bash completion code, as I haven't had a chance to get to all of the issues that I've seen. There are other issues that I've identified (in bash, fish, or zsh) for which I haven't included TODOs, too. I basically only noted issues in new code that I wrote, rather than in existing code; I completely rewrote the main completion logic for bash, so there is a lot of new code… |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rgoldberg This is great, again! 👏🏻 👏🏻 👏🏻 I really appreciate you starting from first principles for a rewrite of this size – the generated script is working without issues for me locally, so I just have these few implementation notes.
\(positionalArguments | ||
.compactMap { arg in | ||
position += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I generally try to have a transform like this be a pure function, without the side effect of mutating a captured variable (i.e. position
here). If you zip positionalArguments
with an open range, you can iterate over both the position and the arguments at the same time:
\(positionalArguments | |
.compactMap { arg in | |
position += 1 | |
\(zip(1..., positionalArguments) | |
.compactMap { position, arg in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know about Swift zip(…)
before. Thanks for the tip. Being a Swift newbie has its drawbacks…
\(functionName)_\(subcommand._commandName) \(subcommandArgument) | ||
return | ||
;; | ||
if !positionalArguments.allSatisfy({ bashValueCompletion($0).isEmpty }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you think about always doing the compactMap
on lines 254+, and then, when that's not empty, adding the result plus the wrapper text (instead of this check)?
;; | ||
""" | ||
/// Returns flags for the last command of the given array. | ||
private var flags: [String] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on naming this something like flagCompletions
instead? Reading the source above it looked like it would be the same type as positionalArguments
(an array of ArgumentDefinition
). Same thoughts for options
, below.
/// Include default 'help' subcommand in nonempty subcommand list if & only if | ||
/// no help subcommand already exists. | ||
mutating func addHelpSubcommandIfMissing() { | ||
if !isEmpty && allSatisfy({ $0._commandName != "help" }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rewrite to flip the polarity:
if !isEmpty && allSatisfy({ $0._commandName != "help" }) { | |
if !isEmpty && !contains(where: { $0._commandName == "help" }) { |
# TODO: handle joined-value options (-o=file.ext), stacked flags (-aBc), legacy long (-long), combos | ||
# TODO: if multi-valued options can exist, support them |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move these implementation notes out of the generated script – if there's a place for them in the Swift source, that's okay; otherwise let's just capture in issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. I put the notes in situ since I used them as a guide for what to work on. Once the code is in GitHub, however, I can use code links in issues, which I couldn't do before.
fi | ||
|
||
# ${word} is neither a flag, nor an option, nor an option value | ||
# TODO: can SAP be configured to require options before positionals? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a feature currently – options/flags can come anywhere in the list of arguments.
@natecook1000 Thanks for the feedback. Will try to get to it all tomorrow, then also submit a fish PR. |
@natecook1000 Subimtted fixes for all the comments. |
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Standardize bash indents. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Use positional arguments passed by bash to the main completion function instead of reading from COMP_WORDS, as that can return the wrong info if completing an empty word before a non-empty word. Make $cur & $prev local & readonly. Remove unnecessary COMPREPLY=(). Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Make them local & readonly. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
…ension. Inline some single-use functions. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Move from ArgumentDefinition extension to [ParsableCommand.Type] extension. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Attempt to emulate the much more complete & correct zsh completion script. Offer candidates for only the current positional / option value, not for all. Generate completions for positionals the same as for option values. Offer flags & options only if no prior option-terminator marker (a standalone --). Offer flags & options only if current word starts with a -, or if there are no remaining positional parameters. Parse options prior to subcommands later in the command line. Offer flags & options only once. Do not offer flags or options if the current word is an option value. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Do not split paths with spaces into separate completions. Escape spaces in paths. Append / to directory paths. Do not use _filedir from bash-completions; use builtin bash constructs instead. Fix broken existing escaping of single quotes in file extension filters. More succinct & performant. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
…tions. That behavior was a bug, not a feature. Released Swift Argument Parser documentation says: "Complete file names with the specified extensions." It does not mention including uppercase versions of the extensions. None of the other shells include uppercase versions of extensions. Why should uppercase versions be special? Why not case-insensitive matching? Why not lowercase versions? Etc. Any config depending on this behavior won't match uppercase extensions without manually being reconfigured, but there are a ton of other bug fixes that can also break compatibility. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
bash scripts now escape single quotes in list values. Any existing list values with escapes that worked in double quotes will not work in the single quotes. But now: - list values needn't be escaped - unescaped double quotes in list values won't break the script - $ & other characters won't interact with the shell, so, e.g., command substitutions cannot cause problems Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Properly refuses to complete when there are no completion candidates. Still cannot complete to an empty string. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Eval the given command from a single-quoted string instead of running it directly in the shell. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
If existing shellCommand completions depend on spaces as completion delimiters, they will not work anymore. Newlines are now the only supported delimiters. Resolve apple#734 Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
…ommand detector. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
…espectively, in BashCompletionsGenerator.swift. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
8d1ead6
to
0ad7911
Compare
@natecook1000 Rebased on new |
@swift-ci Please test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚢
Improve bash completion script generation.
There are many issues with script generation. Some of them are documented in #679 & its comments.
This issue is for a first batch of bash completion script fixes.
Each commit should note the fix(es) that it contains.
Note that I use "iff" in some Swift & bash comments, but not in code or in DocC. If you want "iff" removed from comments, please let me know.
Will rebase if
main
is updated (especially if #726 is merged).Resolve #734
Checklist