* Fix fish completing for flag/option names that contain dashes.
* Fix fish completing for flag/option names that are `r`.
* Remove vestigial `present_flags_and_options` from fish completion scripts.
* Use double quotes for fish completion string test arguments.
* Simplify fish while loop.
* Make `FishCompletionsGenerator.swift` & generated fish completion scripts more concise.
* Require positional_index_comparison argument for all calls to fish shouldOfferCompletionsForPositionalFunction.
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
* In zsh completion scripts, set ret=0 after completing subcommands or subcommand arguments, which prevents functions from being unnecessarily called multiple times.
* Improve zsh completion function registration.
Call the main completion function iff the function is being called, which avoids an unnecessary call, but calls when necessary to avoid requiring a second tab when the script is first loaded.
Otherwise, calls compdef for the function & command, which allows the script to be sourced instead of autoloaded.
---------
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
* Complete repeatable positional instances after the first in bash.
* Complete repeatable positional instances after the first in fish.
* Only complete positionals through the first repeating positional in zsh.
* Complete repeatable flag & option instances after the first in bash.
* Complete non-repeatable flag & option instances only once in fish.
* add implementation of replacing(_:with:)
* remove use of range(of:)
* Consolidate foundation usage
* Consolidate error to string logic
* Clean up env a bit
* Adopt upcoming Swift language feature MemberImportVisibility.
Enable the language feature flag for SE-0444. This instructs the compiler to
be stricter about requiring import declarations in order to access member
declarations.
* Replace `#if swift(>=6.0)` guards with `#if compiler(>=6.0)`.
All uses of `internal import` were previously guarded with `#if swift(>=6.0)`,
presumably to handle differences in compiler support for `internal import`.
However, `#if swift(>=)` is not the correct directive to use for this purpose,
as it primarily tests the language mode that is enabled. These existing
conditionals never evaluated true when building this package since it is not
configured to build with Swift 6 enabled. Instead, use `#if compiler(>=6.0)`
which correctly predicates the imports on only the compiler version.
* Nonexclusive flags implemented via an array of enum cases are now separate ArgumentInfoV0 instances, instead of different names for the same ArgumentInfoV0.
* Improve ToolInfoV0 HelpCommand injection.
* Add ArgumentInfoV0.ParsingStrategyV0 enum.
* Refactor bash completions to use ToolInfoV0.
* Refactor fish completions to use ToolInfoV0.
* Refactor zsh completions to use ToolInfoV0.
* Remove vestigial shellVariableNamePrefix.
* Add .editorconfig files to prevent automatic whitespace changes to test snapshots.
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Improve zsh quoting.
Many quoting issues remain.
To fix them, there should first be enforced & documented limits on the acceptable characters in various values throughout SAP to avoid unnecessary quoting.
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
They indicate to the Swift custom completion function:
1. the word for which completions are being requested.
2. the location of the cursor within that word.
* Fix DocC one-line summary for CompletionKind.file(extensions:).
* Use descriptions instead of argument names in DocC for CompletionKind cases.
* Improve DocC for CompletionKind.custom(_:).
* Update zsh option settings for generated completion scripts.
* Separate shell-specific CompletionKind DocC notes under separate subheadings.
* Improve fish escaping.
* Escape backslashes for fish single-quoted strings.
If someone already escapes backslashes for such strings, this will
cause an issue, but no one should be required to go to the trouble
to manually escape backslashes in their strings, especially since
the requirement isn't documented or normal.
If someone doesn't escape backslashes, then that can break then old
version of the script.
* Output fish functions via one Swift multiline string.
* Join fish short flags/options.
* Replace fish double quotes with single quotes.
* Use option terminator in each call to string split in fish completion.
* Add default help to fish completions iff no existing help subcommand.
* Rename fish variables.
* Rename fish functions & associated Swift functions & variables.
* Inline single-use Swift variables in FishCompletionsGenerator.swift.
* Use separator in FishCompletionsGenerator.swift.
* Overhaul FishCompletionsGenerator.swift as [ParsableCommand.Type]
extension.
* Move argumentSegments(…) in FishCompletionsGenerator.swift.
* Fix fish file, directory, shell command & custom Swift call
completions.
* Properly complete fish positionals.
Fix custom completion of empty argument.
Associate a description with a fish completion iff it's a
flag/option or a subcommand.
* Improve custom completion args for fish 4+.
* Fix switch end keyword bugs in _swift_*_commands_and_positionals fish
functions.
* Lowercase fish variables that were once global but that are now local.
* Use double-quoted variable instead of `string join ''` in fish
completion scripts.
* Use option terminator in call to string split in fish completion.
* Pass each fish option spec to _swift_*_commands_and_positionals
functions as a separate argument.
* Overhaul generated fish completion scripts:
Allow positionals & subcommands on the same (sub)command.
Don't use `-r` for complete calls for positionals.
Use `-\(r)fka ''` for positionals or option values with no
completion candidates.
Allow option_specs elements to contain spaces.
Explicitly scope variables.
Rename functions.
Prevent odd characters in (sub)command names from breaking the
script in some places.
Prevent missing data from breaking if tests.
* Backwards compatibility in fish completion scripts with fish 3.3.x-
Change set -f to set -l.
Replace $(…) with (…) command substitutions.
* Change fish function prefixes from `_swift_` to `__` to align with
other shells.
* Restrict access to symbols in BashCompletionsGenerator.swift.
* Use key path instead of closure in BashCompletionsGenerator.swift.
* Remove extraneous bash spacing.
* Do not indent bash cases.
Standardize bash indents.
* Do not prefix bash cases with an open parenthesis.
* Brace & quote bash variable uses.
* Remove extraneous bash blank line.
* Improve bash escaping.
* Improve bash $cur, $prev, & $COMPREPLY.
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=().
* Improve bash $SAP_SHELL & $SAP_SHELL_VERSION.
Make them local & readonly.
* Overhaul BashCompletionsGenerator.swift as [ParsableCommand.Type] extension.
Inline some single-use functions.
* Move bashValueCompletion(…) in BashCompletionsGenerator.swift.
Move from ArgumentDefinition extension to [ParsableCommand.Type] extension.
* Overhaul bash completion script generation:
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.
* Add default help to bash completions iff no existing help subcommand.
* Improve bash file & directory completions.
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.
* Disable history ! in bash completion scripts.
* Do not include uppercased extensions in bash file(extensions:) completions.
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.
* Use single quoted string for bash list completions.
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
* Allow bash list completions to contain spaces.
* Allow bash custom completions to contain spaces.
Properly refuses to complete when there are no completion candidates.
Still cannot complete to an empty string.
* bash custom completion of empty word followed by other words.
* Prevent bash shellCommand completion scripting from breaking scripts.
Eval the given command from a single-quoted string instead of running it directly in the shell.
* Allow bash shellCommand completions to contain spaces.
If existing shellCommand completions depend on spaces as completion delimiters, they will not work anymore. Newlines are now the only supported delimiters.
Resolve#734
* Use zip(…) to generate bash positional argument numbers.
* Rework bash positional case generation.
* Reverse the polarity of the neutron flow of the completions help subcommand detector.
* Rename flags & options vars to flagCompletions & optionCompletions, respectively, in BashCompletionsGenerator.swift.
* Remove TODO comments from generated bash completion scripts.
---------
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
* Do not indent zsh cases.
Simplify zsh indent generation.
* Do not prefix zsh cases with an open parenthesis.
* Prevent zsh parameter word splitting.
Brace & quote parameter uses.
Use [@] for quoted array output.
* Improve comment in ZshCompletionsGenerator.swift.
* Fix incorrect zsh shellCommand single quotes:
4 consecutive single quotes were obviously intended to be 2 escaped single quotes,
but that isn't zsh syntax.
Use 2 double quotes instead.
* Remove extraneous zsh newline.
* Improve zsh variable declarations: scoping, typing & readonly.
Remove trailing spaces from InstallingCompletionScripts.md.
* Include zsh words before current subcommand in custom completion arg.
* Make subcommandHandler in ZshCompletionsGenerator.swift immutable.
* Escape zsh single quotes via '\'' instead of via '"'"'.
* Escape single quotes in zsh shellCommand String.
If someone already escapes single quotes from the String, this will cause an issue,
but no one should be required to go to the trouble to manually escape single quotes
in their script, especially since the requirement isn't documented or normal.
* Fix zsh custom completions for empty [String] & String elements.
If a Swift custom completion function returns an empty [String], if the user tries to
complete it, refuse to complete instead of inserting a blank space into the command line.
If a Swift custom completion function returns a [String] including a Swift empty String
or including a String with a description but with a blank completion
(e.g., ":description"), if that completion is selected, complete to a zsh empty string
'' instead of inserting a blank space into the command line.
Disambiguating between an empty [String] & a [String] with one empty String element
requires that an extra value be appended to the output of the Swift custom function,
which is then removed by the completion script.
* Simplify zsh subcommand completion function dispatch.
* Restrict access to symbols in ZshCompletionsGenerator.swift.
* Add default help to zsh completions iff no existing help subcommand.
* Use interpolated Strings in ZshCompletionsGenerator.swift.
* Create & use zsh __completion function.
* Improve zsh escaping.
* Set zsh settings to a known state.
Disable history ! in zsh completion scripts.
* Inline single-use functions & variables in ZshCompletionsGenerator.swift.
* Overhaul ZshCompletionsGenerator.swift as [ParsableCommand.Type] extension.
* Move functions in ZshCompletionsGenerator.swift.
Move from ArgumentDefinition extension to [ParsableCommand.Type] extension.
* Move zsh helper functions before command functions to mirror other shells.
* Prefix zsh helper functions with command name to prevent naming clashes.
Function names are globally scoped.
Without namespacing, if 2 programs use different versions of Swift Argument Parser,
one could overwrite the other's different version of the same helper function.
Renamed functions from *_completion to *_complete, as they complete, not return a
completion.
* Separate zsh _arguments flags from specs using :.
* Rename zsh args variable as arg_specs.
* Simplify zshCompletionString(…).
* Allow generating zsh setup scripts for arguments.
* Use zsh array for list completions instead of nested strings.
Allows list completions to contain spaces.
Resolve#726
* Make CompletionShell.format(…) internal instead of public.
* Reword uses of "iff" in completions code.
Redid a comment as a DocC.
* Replace zsh END_MARKER pseudo-completion with a space to ease migration.
Document why & how this pseudo-completion is used.
Do not trim whitespace in testing, as that breaks with the space pseudo-completion.
Testing should be as exact as possible; trimming whitespace makes it less exact.
* Throw error if attempting to generate a zsh completion script for no commands.
Force unwrap first in ZshCompletionsGenerator.swift.
---------
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
Create a `String?` singleton named `CompletionShell.requestingVersion` that
indicates which shell version is requesting completion candidates.
It will be set to the correct value while a Swift custom completion function is
executing to offer completions for a word from a command line (e.g., while
`customCompletion` from `@Option(completion: .custom(customCompletion))`
executes). Otherwise, it will be set to `nil`.
The requesting shell version is communicated to the Swift app via an environment
variable named `SAP_SHELL_VERSION`, which is exported by each of the generated
completion scripts.
Improve some nearby DocC.
Resolve#689
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
A CompletionShell singleton named CompletionShell.requesting has been created
that indicates which shell is requesting completion candidates.
The singleton is populated when a completion script is generated, so functions
used to generate arguments for CompletionKind creation functions can return
completion candidate syntax / shell commands tailored for that shell.
For the custom(:) CompletionKind creation function, the singleton is populated
at runtime (when a completion script requests completions from the Swift app
after a user types tab while composing a command line to call the app).
The requesting shell is communicated to the Swift app via an environment variable
named SAP_SHELL, which is exported by each of the generated completion scripts.
Resolve#672
Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com>
* Added conversion for InputKey to/from fullPathString.
* Updated custom completions to use the IndexKey.fullPathString.
This resolves an issue where custom completion for arguments in an OptionGroup would fail to match the argument. It was caused by:
- the completion script only using the name of the argument (instead of the full path)
- the CommandParser looking for the matching argument by comparing a name only IndexKey with the “full” IndexKeys
* Updated BashCompletionsGenerator to use customCompletionCall.
The zsh completions already uses this function. The function’s implementation is the same as what the BashCompletionsGenerator is doing. This removes the duplicated logic.
* Updated completion tests to include nested arguments with custom completions.
* Switched to using the split method from the stdlib.
Prevously was using .components(seperatedBy:) from Foundation.
* Updated the fish completions to include arguments
This adds support for aliases for subcommands via a new parameter to
CommandConfigurations constructors. The aliases are passed as an array
of strings, where the default is just an empty array that signifies there
are no aliases. The aliases are supported regardless of if a different
commandName is chosen or not. This also updates how subcommands show up
in the help text. Any aliases are now displayed to the right of the original
command.
In addition to the functionality itself, this change:
1. Updates some of the EndToEnd parsing tests to make sure they function
while using aliases.
2. Sprinkles mentions where I saw fit in the documentation.
3. Updates the Math example to have aliases for `math stats average`
(`math stats avg`), and `math multiply` (`math mul`).
`math`'s help text now looks like the below:
```
~ math --help
OVERVIEW: A utility for performing maths.
USAGE: math <subcommand>
OPTIONS:
--version Show the version.
-h, --help Show help information.
SUBCOMMANDS:
add (default) Print the sum of the values.
multiply, mul Print the product of the values.
stats Calculate descriptive statistics.
See 'math help <subcommand>' for detailed help.
~ math stats --help
OVERVIEW: Calculate descriptive statistics.
USAGE: math stats <subcommand>
OPTIONS:
--version Show the version.
-h, --help Show help information.
SUBCOMMANDS:
average, avg Print the average of the values.
stdev Print the standard deviation of the values.
quantiles Print the quantiles of the values (TBD).
See 'math help stats <subcommand>' for detailed help.
```
and use of the aliases:
```
~ math mul 10 10
100
~ math stats avg 10 20
15.0
```
This change does NOT add any updates to the shell completion logic for
this feature.
Fixes#248
This change adds conditional `Sendable` conformance to all
property wrapper types when their `Value` is `Sendable`, enabling
commands to be used in concurrent contexts. Some notes on
the implementation:
* Fix flag exclusivity issues
This derives the `hasUpdated` check from the parsed values data type,
rather than storing it in the closure (which breaks sendability) or
passing it through the closure invocation (which wasn't finished
enough to actually work).
* Mark all `transform` methods as `@Sendable`
This allows for a stronger, compiler-supported guarantee of
sendability when a compound `ParsableArguments` or `ParsableCommand`
type is marked `Sendable`. Most transformations shouldn't be a
problem, since the general case is that these are pure string ->
value transformations.
In cases where making such a transformation sendable is impossible,
an author can always change the property to be just a string and
perform the transformation within the context of the command's
execution, in either the `run()` or `validate()` methods.
* Add `@preconcurrency` to Sendable closure APIs
This adds the `@preconcurrency` attribute to all public APIs that
have changed to take a `@Sendable` closure. This will ease the
migration path for sendable adoption for ArgumentParser users, since
a warning will only appear for using these APIs (like the `transform`
parameter in an @Option or @Argument) once they've turned on strict
concurrency checking.
I'm also backing out changes that avoided those warnings in the tests
and examples, since in most cases those warnings are spurious;
unapplied functions don't capture state. See
https://forums.swift.org/t/pitch-inferring-sendable-for-methods-and-key-path-literals/68011
for more on this and hopefully an upcoming fix for these issues.
* Raise minimum Swift version to 5.7
In order to provide `@preconcurrency` support, the package needs to
have a minimum Swift requirement of 5.7. This makes that change and
updates the README to indicate this for the next version.
* Respect the `COLUMNS` and `LINES` environment variables, if set, when determining screen size.
* Add test for COLUMNS environment override
* Make columns test idempotent against there being a COLUMNS value already set in the environment
* Make help tests be more explicit about screen widths.
Updates HelpGenerator to print possible value options as a suffix to the
user defined help string. In practice this looks like:
> Set diagnostic level to report public declarations without an
> availability attribute. (values: error, warn, ignore; default: warn)
A generated fish script didn't complete an option after an argument.
The cause is the generated fish script doesn't accept an input text which already has arguments.
For example, when the input is `repeat -`, the script can complete `--count`, but when the text is `repeat foo -`, the script cannot complete `repeat foo --count`, because the input text already has the argument "foo".
To fix the issue, `FishCompletionsGenerator` got a capability that can accept a text which has arguments.
* Use existential CodingKey parameters consistently
Swift 5.7 supports implicit opening for existentials, so these
conversions from `CodingKey` parameters to pass to methods that
are generic over `CodingKey` work fine. Prior to Swift 5.7, however,
these don't compile, with the message that `CodingKey` doesn't conform
to itself.
* Bump the required Swift version for the count-lines test
The overload resolution for the `static func main()` in an `@main`
type still had issues in Swift 5.6, such that a package with a min.
platform below that which works for concurrency backdeployment doesn't
properly resolve the AsyncParsableCommand `main()` function. In
Swift 5.7, this is properly resolved, so just the availability on
the main type is sufficient.
This change just skips the test of `count-lines` prior to Swift 5.7,
so that we can maintain the open platform minimum for the package
as a whole.
- Fixes#466.
- Adds initializers to ArgumentDefinition generic over a Container type.
The Container type must conform to a new internal protocol
ArgumentDefinitionContainer which describes functionality like default
set of help options for the argument defined by the property wrapper,
etc.
- Adds overloads for Optional @Arguments and @Options with default
values which emit deprecation warning to guide users towards using the
non-Optional versions.
Adds a new `AsyncParsableCommand` protocol, which provides a
`static func main() async` entry point and can call through to the root
command's or a subcommand's asynchronous `run()` method. For this
asynchronous execution, the root command must conform to `AsyncParsableCommand`,
but its subcommands can be a mix of asynchronous and synchronous commands.
Due to an issue in Swift 5.5, you can only use `@main` on an
`AsyncParsableCommand` root command starting in Swift 5.6.
This change also includes a workaround for clients that are using Swift 5.5.
Declare a separate type that conforms to `AsyncMainProtocol` and add the `@main`
attribute to that type.
```
@main enum Main: AsyncMain {
typealias Command = <#command#>
}
```
* Improve support for multi-word completions in Z shell
I will not pretend to fully understand why this new "expand string into array" expression works when the other didn't, but it does. The new expression is based on this SO answer: https://unix.stackexchange.com/a/29748.
The motivation for this change was for the install command of xcodes (https://github.com/RobotsAndPencils/xcodes) to support Xcode version completion strings with multiple words, like "11.6 Beta". The previous version of this expression would split this string into two, so that "11.6" and "Beta" were independent options in the ZSH completion UI, which didn't make sense for this use case.
* `shellCommand` stores output in a local array that is passed
to `_describe` to handle spaces and other punctuation in
the shell command output
* elide the help abstract if it is empty, as it confuses
the zsh completion system
* set the `_<commandName>_commandname` to `$words[1]`, which
is the full name of the command used to invoke the completion.
This ensures invocations like `./build/debug/math` ...
as passed on to the `_custom_completion` command.
Support for generating shell completion scripts for `ParsableCommand`
types, with customization points for `ExpressibleByArgument` types and
individual arguments and options. Zsh and Bash are supported in this
initial release.