From 74f7090f6bc131576c78a8461e9b323b65e60526 Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Mon, 20 Jan 2025 10:25:53 -0500 Subject: [PATCH 1/8] Improve CompletionKind DocC. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Parsable Properties/CompletionKind.swift | 195 ++++++++++++++++-- 1 file changed, 182 insertions(+), 13 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index e74f3394..f034cb8a 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -9,56 +9,225 @@ // //===----------------------------------------------------------------------===// -/// The type of completion to use for an argument or option. +/// The type of completion to use for an argument or option value. +/// +/// For all `CompletionKind`s, the completion shell script is configured with +/// the following settings, which will not affect the requesting shell outside +/// the completion script: +/// +/// - bash: +/// +/// ```shell +/// shopt -s extglob +/// set +o history +o posix +/// ``` +/// +/// - fish: no settings +/// +/// - zsh: +/// +/// ```shell +/// emulate -RL zsh -G +/// setopt extendedglob +/// unsetopt aliases banghist +/// ``` public struct CompletionKind { + /// The type of completion to use for an argument or option value. + /// + /// For all `Kind`s, the completion shell script is configured with the + /// following settings, which will not affect the requesting shell outside the + /// completion script: + /// + /// - bash: + /// + /// ```shell + /// shopt -s extglob + /// set +o history +o posix + /// ``` + /// + /// - fish: no settings + /// + /// - zsh: + /// + /// ```shell + /// emulate -RL zsh -G + /// setopt extendedglob + /// unsetopt aliases banghist + /// ``` internal enum Kind { - /// Use the default completion kind for the value's type. + /// Use the default completion kind for the argument's or option value's + /// type. case `default` - /// Use the specified list of completion strings. + /// The completion candidates are the elements of the given `[String]`. + /// + /// Completion candidates are interpreted by the requesting shell as + /// literals. They must be neither escaped nor quoted; Swift Argument Parser + /// escapes or quotes them as necessary for the requesting shell. + /// + /// The completion candidates are included in a completion script when it is + /// generated. case list([String]) - /// Complete file names with the specified extensions. + /// The completion candidates include: + /// + /// - all directory names + /// - if `extensions` is empty, all file names + /// - if `extensions` is not empty, all file names whose respective + /// extension matches any element of `extensions` + /// + /// Given file extensions must not include the `.` initial extension + /// separator. + /// + /// Given file extensions are parsed by the requesting shell as globs; Swift + /// Argument Parser does not perform any escaping or quoting. + /// + /// In zsh, `EXTENDED_GLOB` & `NULL_GLOB` are set, while `KSH_GLOB` & `SH_GLOB` are unset + /// ? `BARE_GLOB_QUAL`, `GLOB_DOTS`, `GLOB_STAR_SHORT`, `GLOB_SUBST`, `NOMATCH`, `NUMERIC_GLOB_SORT` + /// + /// The directory/file filter & the given list of extensions are included in + /// a completion script when it is generated. case file(extensions: [String]) - /// Complete directory names that match the specified pattern. + /// The completion candidates are directory names. + /// + /// The directory filter is included in a completion script when it is + /// generated. case directory - /// Call the given shell command to generate completions. + /// The completion candidates are specified by the stdout output of the + /// given `String` run as a shell command when a user requests completions. + /// + /// Swift Argument Parser does not perform any escaping or quoting on the + /// given shell command. + /// + /// The given shell command is included in a completion script when it is + /// generated. case shellCommand(String) - /// Generate completions using the given closure. + /// The completion candidates are the elements of the `[String]` returned by + /// the given closure when it is run when a user requests completions. + /// + /// Completion candidates are interpreted by the requesting shell as + /// literals. They must be neither escaped nor quoted; Swift Argument Parser + /// escapes or quotes them as necessary for the requesting shell. + /// + /// The given closure is evaluated after a user invokes completion in their + /// shell (normally by pressing TAB); it is not evaluated when a completion + /// script is generated. + /// + /// Depending on which shell is requesting completions, the `[String]` + /// argument passed to the given closure contains: + /// + /// - the command being called as the first element (bash & fish, not zsh) + /// - either: + /// - all the arguments on the command line (bash & zsh, presumably fish + /// 4+) + /// - the arguments on the command line only up to & including the + /// argument for which completions are being requested (fish 3-) + /// + /// The arguments are passed to Swift verbatim, not unquoted. e.g., the + /// representation in Swift of the shell argument `"abc\\""def"` would be + /// exactly the same, including the quotes & the double backslash. + /// + /// Due to limitations in fish 3, arguments are passed to Swift unquoted. + /// e.g., the aforementioned example argument would be passed as `abc\def`. + /// fish 4 will not be constrained by such limitations, so this behavior + /// will be able to be fixed in a subsequent update to Swift Argument + /// Parser. case custom(@Sendable ([String]) -> [String]) } internal var kind: Kind - /// Use the default completion kind for the value's type. + /// Use the default completion kind for the argument's or option value's type. public static var `default`: CompletionKind { CompletionKind(kind: .default) } - /// Use the specified list of completion strings. + /// The completion candidates are the elements of `words`. + /// + /// Completion candidates are interpreted by the requesting shell as literals. + /// They must be neither escaped nor quoted; Swift Argument Parser escapes or + /// quotes them as necessary for the requesting shell. + /// + /// The completion candidates are included in a completion script when it is + /// generated. public static func list(_ words: [String]) -> CompletionKind { CompletionKind(kind: .list(words)) } - /// Complete file names. + // swift-format-ignore: BeginDocumentationCommentWithOneLineSummary + /// The completion candidates include: + /// + /// - all directory names + /// - if `extensions` is empty, all file names + /// - if `extensions` is not empty, all file names whose respective + /// extension matches any element of `extensions` + /// + /// Given file extensions must not include the `.` initial extension + /// separator. + /// + /// Given file extensions are parsed by the requesting shell as globs; Swift + /// Argument Parser does not perform any escaping or quoting. + /// + /// In zsh, `EXTENDED_GLOB` & `NULL_GLOB` are set, while `KSH_GLOB` & `SH_GLOB` are unset + /// ? `BARE_GLOB_QUAL`, `GLOB_DOTS`, `GLOB_STAR_SHORT`, `GLOB_SUBST`, `NOMATCH`, `NUMERIC_GLOB_SORT` + /// + /// The directory/file filter & the given list of extensions are included in a + /// completion script when it is generated. public static func file(extensions: [String] = []) -> CompletionKind { CompletionKind(kind: .file(extensions: extensions)) } - /// Complete directory names. + /// The completion candidates are directory names. + /// + /// The directory filter is included in a completion script when it is + /// generated. public static var directory: CompletionKind { CompletionKind(kind: .directory) } - /// Call the given shell command to generate completions. + /// The completion candidates are specified by the stdout output of `command` + /// run as a shell command when a user requests completions. + /// + /// Swift Argument Parser does not perform any escaping or quoting on + /// `command`. + /// + /// The given shell command is included in a completion script when it is + /// generated. public static func shellCommand(_ command: String) -> CompletionKind { CompletionKind(kind: .shellCommand(command)) } - /// Generate completions using the given closure. + /// The completion candidates are the elements of the `[String]` returned by + /// the given closure when it is run when a user requests completions. + /// + /// Completion candidates are interpreted by the requesting shell as literals. + /// They must be neither escaped nor quoted; Swift Argument Parser escapes or + /// quotes them as necessary for the requesting shell. + /// + /// The given closure is evaluated after a user invokes completion in their + /// shell (normally by pressing TAB); it is not evaluated when a completion + /// script is generated. + /// + /// Depending on which shell is requesting completions, the `[String]` + /// argument passed to the given closure contains: + /// + /// - the command being called as the first element (bash & fish, not zsh) + /// - either: + /// - all the arguments on the command line (bash & zsh, presumably fish 4+) + /// - the arguments on the command line only up to & including the argument + /// for which completions are being requested (fish 3-) + /// + /// The arguments are passed to Swift verbatim, not unquoted. e.g., the + /// representation in Swift of the shell argument `"abc\\""def"` would be + /// exactly the same, including the quotes & the double backslash. + /// + /// Due to limitations in fish 3, arguments are passed to Swift unquoted. + /// e.g., the aforementioned example argument would be passed as `abc\def`. + /// fish 4 will not be constrained by such limitations, so this behavior will + /// be able to be fixed in a subsequent update to Swift Argument Parser. @preconcurrency public static func custom( _ completion: @Sendable @escaping ([String]) -> [String] From e6c8e5bfc3660a2b8e64977ae8b7ecc7eaf27250 Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Sun, 16 Feb 2025 15:50:24 -0500 Subject: [PATCH 2/8] Remove DocC from CompletionKind.Kind. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Parsable Properties/CompletionKind.swift | 97 ------------------- 1 file changed, 97 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index f034cb8a..af965feb 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -32,109 +32,12 @@ /// unsetopt aliases banghist /// ``` public struct CompletionKind { - /// The type of completion to use for an argument or option value. - /// - /// For all `Kind`s, the completion shell script is configured with the - /// following settings, which will not affect the requesting shell outside the - /// completion script: - /// - /// - bash: - /// - /// ```shell - /// shopt -s extglob - /// set +o history +o posix - /// ``` - /// - /// - fish: no settings - /// - /// - zsh: - /// - /// ```shell - /// emulate -RL zsh -G - /// setopt extendedglob - /// unsetopt aliases banghist - /// ``` internal enum Kind { - /// Use the default completion kind for the argument's or option value's - /// type. case `default` - - /// The completion candidates are the elements of the given `[String]`. - /// - /// Completion candidates are interpreted by the requesting shell as - /// literals. They must be neither escaped nor quoted; Swift Argument Parser - /// escapes or quotes them as necessary for the requesting shell. - /// - /// The completion candidates are included in a completion script when it is - /// generated. case list([String]) - - /// The completion candidates include: - /// - /// - all directory names - /// - if `extensions` is empty, all file names - /// - if `extensions` is not empty, all file names whose respective - /// extension matches any element of `extensions` - /// - /// Given file extensions must not include the `.` initial extension - /// separator. - /// - /// Given file extensions are parsed by the requesting shell as globs; Swift - /// Argument Parser does not perform any escaping or quoting. - /// - /// In zsh, `EXTENDED_GLOB` & `NULL_GLOB` are set, while `KSH_GLOB` & `SH_GLOB` are unset - /// ? `BARE_GLOB_QUAL`, `GLOB_DOTS`, `GLOB_STAR_SHORT`, `GLOB_SUBST`, `NOMATCH`, `NUMERIC_GLOB_SORT` - /// - /// The directory/file filter & the given list of extensions are included in - /// a completion script when it is generated. case file(extensions: [String]) - - /// The completion candidates are directory names. - /// - /// The directory filter is included in a completion script when it is - /// generated. case directory - - /// The completion candidates are specified by the stdout output of the - /// given `String` run as a shell command when a user requests completions. - /// - /// Swift Argument Parser does not perform any escaping or quoting on the - /// given shell command. - /// - /// The given shell command is included in a completion script when it is - /// generated. case shellCommand(String) - - /// The completion candidates are the elements of the `[String]` returned by - /// the given closure when it is run when a user requests completions. - /// - /// Completion candidates are interpreted by the requesting shell as - /// literals. They must be neither escaped nor quoted; Swift Argument Parser - /// escapes or quotes them as necessary for the requesting shell. - /// - /// The given closure is evaluated after a user invokes completion in their - /// shell (normally by pressing TAB); it is not evaluated when a completion - /// script is generated. - /// - /// Depending on which shell is requesting completions, the `[String]` - /// argument passed to the given closure contains: - /// - /// - the command being called as the first element (bash & fish, not zsh) - /// - either: - /// - all the arguments on the command line (bash & zsh, presumably fish - /// 4+) - /// - the arguments on the command line only up to & including the - /// argument for which completions are being requested (fish 3-) - /// - /// The arguments are passed to Swift verbatim, not unquoted. e.g., the - /// representation in Swift of the shell argument `"abc\\""def"` would be - /// exactly the same, including the quotes & the double backslash. - /// - /// Due to limitations in fish 3, arguments are passed to Swift unquoted. - /// e.g., the aforementioned example argument would be passed as `abc\def`. - /// fish 4 will not be constrained by such limitations, so this behavior - /// will be able to be fixed in a subsequent update to Swift Argument - /// Parser. case custom(@Sendable ([String]) -> [String]) } From 15f70f19dddec67aee886e4886418fd39acc04c7 Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Sun, 16 Feb 2025 16:29:47 -0500 Subject: [PATCH 3/8] Fix DocC one-line summary for CompletionKind.file(extensions:). Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Parsable Properties/CompletionKind.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index af965feb..d35d0900 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -60,13 +60,11 @@ public struct CompletionKind { CompletionKind(kind: .list(words)) } - // swift-format-ignore: BeginDocumentationCommentWithOneLineSummary - /// The completion candidates include: + /// The completion candidates include directory & file names, the latter + /// filtered by the given list of extensions. /// - /// - all directory names - /// - if `extensions` is empty, all file names - /// - if `extensions` is not empty, all file names whose respective - /// extension matches any element of `extensions` + /// If the given list of extensions is empty, then file names are not + /// filtered. /// /// Given file extensions must not include the `.` initial extension /// separator. From 04d6b1d6a7803056a75192b68b2a2b526151dc77 Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Sun, 16 Feb 2025 16:31:38 -0500 Subject: [PATCH 4/8] Use descriptions instead of argument names in DocC for CompletionKind cases. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Parsable Properties/CompletionKind.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index d35d0900..01035f4a 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -48,7 +48,7 @@ public struct CompletionKind { CompletionKind(kind: .default) } - /// The completion candidates are the elements of `words`. + /// The completion candidates are the strings in the given array. /// /// Completion candidates are interpreted by the requesting shell as literals. /// They must be neither escaped nor quoted; Swift Argument Parser escapes or @@ -89,11 +89,11 @@ public struct CompletionKind { CompletionKind(kind: .directory) } - /// The completion candidates are specified by the stdout output of `command` - /// run as a shell command when a user requests completions. + /// The completion candidates are specified by the stdout output of the given + /// string run as a shell command when a user requests completions. /// - /// Swift Argument Parser does not perform any escaping or quoting on - /// `command`. + /// Swift Argument Parser does not perform any escaping or quoting on the + /// given shell command. /// /// The given shell command is included in a completion script when it is /// generated. @@ -101,8 +101,8 @@ public struct CompletionKind { CompletionKind(kind: .shellCommand(command)) } - /// The completion candidates are the elements of the `[String]` returned by - /// the given closure when it is run when a user requests completions. + /// The completion candidates are the strings in the array returned by the + /// given closure when it is run when a user requests completions. /// /// Completion candidates are interpreted by the requesting shell as literals. /// They must be neither escaped nor quoted; Swift Argument Parser escapes or From e3052d2fbf55e2eda228f7999cbc10ca8fc2963c Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Sun, 16 Feb 2025 16:32:54 -0500 Subject: [PATCH 5/8] Improve DocC for CompletionKind.custom(_:). Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Parsable Properties/CompletionKind.swift | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index 01035f4a..65eabc71 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -112,23 +112,46 @@ public struct CompletionKind { /// shell (normally by pressing TAB); it is not evaluated when a completion /// script is generated. /// - /// Depending on which shell is requesting completions, the `[String]` - /// argument passed to the given closure contains: - /// - /// - the command being called as the first element (bash & fish, not zsh) - /// - either: - /// - all the arguments on the command line (bash & zsh, presumably fish 4+) - /// - the arguments on the command line only up to & including the argument - /// for which completions are being requested (fish 3-) - /// - /// The arguments are passed to Swift verbatim, not unquoted. e.g., the - /// representation in Swift of the shell argument `"abc\\""def"` would be - /// exactly the same, including the quotes & the double backslash. - /// - /// Due to limitations in fish 3, arguments are passed to Swift unquoted. - /// e.g., the aforementioned example argument would be passed as `abc\def`. - /// fish 4 will not be constrained by such limitations, so this behavior will - /// be able to be fixed in a subsequent update to Swift Argument Parser. + /// The array of strings passed to the given closure contains all the shell + /// words in the command line for the current command at completion + /// invocation; this is exclusive of words for prior or subsequent commands or + /// pipes, but inclusive of redirects & any other command line elements. Each + /// word is its own element in the argument array; they appear in the same + /// order as in the command line. Note that shell words may contain spaces if + /// they are escaped or quoted. + /// + /// TODO: ensure that process substitutions work in bash 4. If not, check bash + /// 5, then check minor then patch releases until the first version where they + /// work has been identified. Assume that they work in all subsequent bash + /// versions. + /// + /// In bash 3?-, a process substitution (`<(…)`) in the command line prevents + /// Swift custom completion functions from being called. + /// + /// In bash 4?+, a process substitution (`<(…)`) is split into multiple + /// elements in the argument array: one for the starting `<(`, and one for + /// each unescaped/unquoted-space-separated token through the closing `)`. + /// + /// In bash, if the cursor is between the backslash and the single quote for + /// the last escaped single quote in a word, all subsequent pipes or other + /// commands are included in the words passed to Swift. This oddity might + /// occur only when additional constraints are met. This or similar oddities + /// might occur in other circumstances. + /// + /// In fish 3-, due to a bug, the argument array includes the fish words only + /// through the word being completed. This is fixed in fish 4+. + /// + /// In fish, a redirect's symbol is not included, but its source/target is. + /// + /// In zsh, redirects (both their symbol & source/target) are omitted. + /// + /// Shell words are passed to Swift verbatim, not unquoted. e.g., the + /// representation in Swift of the shell word `"abc\\""def"` would be exactly + /// the same, including the double quotes & the double backslash. + /// + /// In fish 3-, due to limitations, words are passed to Swift unquoted. e.g., + /// the aforementioned example word would be passed as `abc\def`. This is + /// fixed in fish 4+. @preconcurrency public static func custom( _ completion: @Sendable @escaping ([String]) -> [String] From 703e47f96865a972b8724b1c2b09ecd411e78732 Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Sun, 16 Feb 2025 16:33:46 -0500 Subject: [PATCH 6/8] Insert TODOs in DocC for CompletionKind cases. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Parsable Properties/CompletionKind.swift | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index 65eabc71..40eac83a 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -15,6 +15,8 @@ /// the following settings, which will not affect the requesting shell outside /// the completion script: /// +/// TODO: investigate more settings +/// /// - bash: /// /// ```shell @@ -72,8 +74,19 @@ public struct CompletionKind { /// Given file extensions are parsed by the requesting shell as globs; Swift /// Argument Parser does not perform any escaping or quoting. /// - /// In zsh, `EXTENDED_GLOB` & `NULL_GLOB` are set, while `KSH_GLOB` & `SH_GLOB` are unset - /// ? `BARE_GLOB_QUAL`, `GLOB_DOTS`, `GLOB_STAR_SHORT`, `GLOB_SUBST`, `NOMATCH`, `NUMERIC_GLOB_SORT` + /// In zsh, `EXTENDED_GLOB` & `NULL_GLOB` are set, while `KSH_GLOB` & + /// `SH_GLOB` are unset. + /// + /// TODO: determine if the following should be set or unset: + /// + /// `BARE_GLOB_QUAL` + /// `GLOB_DOTS` + /// `GLOB_STAR_SHORT` + /// `GLOB_SUBST` + /// `NOMATCH` + /// `NUMERIC_GLOB_SORT` + /// + /// TODO: determine settings for bash & fish /// /// The directory/file filter & the given list of extensions are included in a /// completion script when it is generated. From 5c5c8fb06f1b2e81c333e4b234d5efbec90d62fb Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Wed, 19 Feb 2025 08:20:07 -0500 Subject: [PATCH 7/8] Update zsh option settings for generated completion scripts. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Completions/ZshCompletionsGenerator.swift | 2 +- .../Parsable Properties/CompletionKind.swift | 27 +++---------------- .../testMathZshCompletionScript().zsh | 2 +- .../Snapshots/testBase_Zsh().zsh | 2 +- 4 files changed, 6 insertions(+), 27 deletions(-) diff --git a/Sources/ArgumentParser/Completions/ZshCompletionsGenerator.swift b/Sources/ArgumentParser/Completions/ZshCompletionsGenerator.swift index 826af9d2..c570fb70 100644 --- a/Sources/ArgumentParser/Completions/ZshCompletionsGenerator.swift +++ b/Sources/ArgumentParser/Completions/ZshCompletionsGenerator.swift @@ -94,7 +94,7 @@ extension [ParsableCommand.Type] { \(isRootCommand ? """ emulate -RL zsh -G - setopt extendedglob + setopt extendedglob nullglob numericglobsort unsetopt aliases banghist local -xr \(CompletionShell.shellEnvironmentVariableName)=zsh diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index 40eac83a..2c11960f 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -15,8 +15,6 @@ /// the following settings, which will not affect the requesting shell outside /// the completion script: /// -/// TODO: investigate more settings -/// /// - bash: /// /// ```shell @@ -30,7 +28,7 @@ /// /// ```shell /// emulate -RL zsh -G -/// setopt extendedglob +/// setopt extendedglob nullglob numericglobsort /// unsetopt aliases banghist /// ``` public struct CompletionKind { @@ -74,20 +72,6 @@ public struct CompletionKind { /// Given file extensions are parsed by the requesting shell as globs; Swift /// Argument Parser does not perform any escaping or quoting. /// - /// In zsh, `EXTENDED_GLOB` & `NULL_GLOB` are set, while `KSH_GLOB` & - /// `SH_GLOB` are unset. - /// - /// TODO: determine if the following should be set or unset: - /// - /// `BARE_GLOB_QUAL` - /// `GLOB_DOTS` - /// `GLOB_STAR_SHORT` - /// `GLOB_SUBST` - /// `NOMATCH` - /// `NUMERIC_GLOB_SORT` - /// - /// TODO: determine settings for bash & fish - /// /// The directory/file filter & the given list of extensions are included in a /// completion script when it is generated. public static func file(extensions: [String] = []) -> CompletionKind { @@ -133,15 +117,10 @@ public struct CompletionKind { /// order as in the command line. Note that shell words may contain spaces if /// they are escaped or quoted. /// - /// TODO: ensure that process substitutions work in bash 4. If not, check bash - /// 5, then check minor then patch releases until the first version where they - /// work has been identified. Assume that they work in all subsequent bash - /// versions. - /// - /// In bash 3?-, a process substitution (`<(…)`) in the command line prevents + /// In bash 3-, a process substitution (`<(…)`) in the command line prevents /// Swift custom completion functions from being called. /// - /// In bash 4?+, a process substitution (`<(…)`) is split into multiple + /// In bash 4+, a process substitution (`<(…)`) is split into multiple /// elements in the argument array: one for the starting `<(`, and one for /// each unescaped/unquoted-space-separated token through the closing `)`. /// diff --git a/Tests/ArgumentParserExampleTests/Snapshots/testMathZshCompletionScript().zsh b/Tests/ArgumentParserExampleTests/Snapshots/testMathZshCompletionScript().zsh index cf7c3695..fe600706 100644 --- a/Tests/ArgumentParserExampleTests/Snapshots/testMathZshCompletionScript().zsh +++ b/Tests/ArgumentParserExampleTests/Snapshots/testMathZshCompletionScript().zsh @@ -16,7 +16,7 @@ __math_custom_complete() { _math() { emulate -RL zsh -G - setopt extendedglob + setopt extendedglob nullglob numericglobsort unsetopt aliases banghist local -xr SAP_SHELL=zsh diff --git a/Tests/ArgumentParserUnitTests/Snapshots/testBase_Zsh().zsh b/Tests/ArgumentParserUnitTests/Snapshots/testBase_Zsh().zsh index ef2da963..0b0762c7 100644 --- a/Tests/ArgumentParserUnitTests/Snapshots/testBase_Zsh().zsh +++ b/Tests/ArgumentParserUnitTests/Snapshots/testBase_Zsh().zsh @@ -16,7 +16,7 @@ __base-test_custom_complete() { _base-test() { emulate -RL zsh -G - setopt extendedglob + setopt extendedglob nullglob numericglobsort unsetopt aliases banghist local -xr SAP_SHELL=zsh From 8fcde5484d464a9663c9b54fff8c95579e68c43f Mon Sep 17 00:00:00 2001 From: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> Date: Thu, 1 May 2025 10:19:33 -0400 Subject: [PATCH 8/8] Separate shell-specific CompletionKind DocC notes under separate subheadings. Signed-off-by: Ross Goldberg <484615+rgoldberg@users.noreply.github.com> --- .../Parsable Properties/CompletionKind.swift | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift index 2c11960f..bb6c2371 100644 --- a/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift +++ b/Sources/ArgumentParser/Parsable Properties/CompletionKind.swift @@ -15,22 +15,24 @@ /// the following settings, which will not affect the requesting shell outside /// the completion script: /// -/// - bash: +/// ### bash /// -/// ```shell -/// shopt -s extglob -/// set +o history +o posix -/// ``` +/// ```shell +/// shopt -s extglob +/// set +o history +o posix +/// ``` /// -/// - fish: no settings +/// ### fish /// -/// - zsh: +/// no settings /// -/// ```shell -/// emulate -RL zsh -G -/// setopt extendedglob nullglob numericglobsort -/// unsetopt aliases banghist -/// ``` +/// ### zsh +/// +/// ```shell +/// emulate -RL zsh -G +/// setopt extendedglob nullglob numericglobsort +/// unsetopt aliases banghist +/// ``` public struct CompletionKind { internal enum Kind { case `default` @@ -117,6 +119,12 @@ public struct CompletionKind { /// order as in the command line. Note that shell words may contain spaces if /// they are escaped or quoted. /// + /// Shell words are passed to Swift verbatim, not unquoted. e.g., the + /// representation in Swift of the shell word `"abc\\""def"` would be exactly + /// the same, including the double quotes & the double backslash. + /// + /// ### bash + /// /// In bash 3-, a process substitution (`<(…)`) in the command line prevents /// Swift custom completion functions from being called. /// @@ -130,20 +138,20 @@ public struct CompletionKind { /// occur only when additional constraints are met. This or similar oddities /// might occur in other circumstances. /// + /// ### fish + /// /// In fish 3-, due to a bug, the argument array includes the fish words only /// through the word being completed. This is fixed in fish 4+. /// /// In fish, a redirect's symbol is not included, but its source/target is. /// - /// In zsh, redirects (both their symbol & source/target) are omitted. - /// - /// Shell words are passed to Swift verbatim, not unquoted. e.g., the - /// representation in Swift of the shell word `"abc\\""def"` would be exactly - /// the same, including the double quotes & the double backslash. - /// /// In fish 3-, due to limitations, words are passed to Swift unquoted. e.g., /// the aforementioned example word would be passed as `abc\def`. This is /// fixed in fish 4+. + /// + /// ### zsh + /// + /// In zsh, redirects (both their symbol & source/target) are omitted. @preconcurrency public static func custom( _ completion: @Sendable @escaping ([String]) -> [String]