Repository: clap-rs/clap
Pull request #5987 (2025-05-05 21:42:04)

complete: Only parse arguments before current in Bash
Addresses #5986.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 42b93ccd..9ce19976 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -496,7 +496,7 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.49"
+version = "4.5.48"
 dependencies = [
  "automod",
  "clap 4.5.37",
diff --git a/clap_complete/CHANGELOG.md b/clap_complete/CHANGELOG.md
index b0b8acc3..fad3e5cc 100644
--- a/clap_complete/CHANGELOG.md
+++ b/clap_complete/CHANGELOG.md
@@ -7,13 +7,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 <!-- next-header -->
 ## [Unreleased] - ReleaseDate
 
-## [4.5.49] - 2025-05-05
-
-### Fixes
-
-- *(dynamic)* Improve handling of empty or quoted content
-- *(aot)* Improve handling of empty or quoted content
-
 ## [4.5.48] - 2025-04-28
 
 ### Fixes
@@ -550,8 +543,7 @@ MSRV changed to 1.64.0
 ## [3.0.1] - 2022-01-03
 
 <!-- next-url -->
-[Unreleased]: https://github.com/clap-rs/clap/compare/clap_complete-v4.5.49...HEAD
-[4.5.49]: https://github.com/clap-rs/clap/compare/clap_complete-v4.5.48...clap_complete-v4.5.49
+[Unreleased]: https://github.com/clap-rs/clap/compare/clap_complete-v4.5.48...HEAD
 [4.5.48]: https://github.com/clap-rs/clap/compare/clap_complete-v4.5.47...clap_complete-v4.5.48
 [4.5.47]: https://github.com/clap-rs/clap/compare/clap_complete-v4.5.46...clap_complete-v4.5.47
 [4.5.46]: https://github.com/clap-rs/clap/compare/clap_complete-v4.5.45...clap_complete-v4.5.46
diff --git a/clap_complete/Cargo.toml b/clap_complete/Cargo.toml
index d72420c0..7c0a93f0 100644
--- a/clap_complete/Cargo.toml
+++ b/clap_complete/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clap_complete"
-version = "4.5.49"
+version = "4.5.48"
 description = "Generate shell completion scripts for your clap::Command"
 categories = ["command-line-interface"]
 keywords = [
diff --git a/clap_complete/README.md b/clap_complete/README.md
index 94bc0727..27626dfe 100644
--- a/clap_complete/README.md
+++ b/clap_complete/README.md
@@ -5,16 +5,16 @@
 
 [![Crates.io](https://img.shields.io/crates/v/clap_complete?style=flat-square)](https://crates.io/crates/clap_complete)
 [![Crates.io](https://img.shields.io/crates/d/clap_complete?style=flat-square)](https://crates.io/crates/clap_complete)
-[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.49/LICENSE-APACHE)
-[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.49/LICENSE-MIT)
+[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.48/LICENSE-APACHE)
+[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.48/LICENSE-MIT)
 
 Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
 
 1. [About](#about)
 2. [API Reference](https://docs.rs/clap_complete)
 3. [Questions & Discussions](https://github.com/clap-rs/clap/discussions)
-4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.49/clap_complete/CONTRIBUTING.md)
-5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.49/README.md#sponsors)
+4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.48/clap_complete/CONTRIBUTING.md)
+5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_complete-v4.5.48/README.md#sponsors)
 
 ## About
 
diff --git a/clap_complete/src/aot/shells/bash.rs b/clap_complete/src/aot/shells/bash.rs
index 98253947..092afd62 100644
--- a/clap_complete/src/aot/shells/bash.rs
+++ b/clap_complete/src/aot/shells/bash.rs
@@ -34,7 +34,7 @@ impl Generator for Bash {
     cmd=\"\"
     opts=\"\"
 
-    for i in ${{COMP_WORDS[@]}}
+    for i in \"${{COMP_WORDS[@]:0:COMP_CWORD}}\"
     do
         case \"${{cmd}},${{i}}\" in
             \",$1\")


Test patch:
diff --git a/clap_complete/tests/snapshots/aliases.bash b/clap_complete/tests/snapshots/aliases.bash
index 5d548281..8cc1e77b 100644
--- a/clap_complete/tests/snapshots/aliases.bash
+++ b/clap_complete/tests/snapshots/aliases.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/basic.bash b/clap_complete/tests/snapshots/basic.bash
index 3d69f0c4..cda98cec 100644
--- a/clap_complete/tests/snapshots/basic.bash
+++ b/clap_complete/tests/snapshots/basic.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/custom_bin_name.bash b/clap_complete/tests/snapshots/custom_bin_name.bash
index 781e5518..c8ad6d69 100644
--- a/clap_complete/tests/snapshots/custom_bin_name.bash
+++ b/clap_complete/tests/snapshots/custom_bin_name.bash
@@ -10,7 +10,7 @@ _bin-name() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/feature_sample.bash b/clap_complete/tests/snapshots/feature_sample.bash
index c3b5b28b..6f74ab13 100644
--- a/clap_complete/tests/snapshots/feature_sample.bash
+++ b/clap_complete/tests/snapshots/feature_sample.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc
index 5184f1a1..360462a8 100644
--- a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc
+++ b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc
@@ -12,7 +12,7 @@ _exhaustive() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/quoting.bash b/clap_complete/tests/snapshots/quoting.bash
index 1d3a799a..a08c4c3a 100644
--- a/clap_complete/tests/snapshots/quoting.bash
+++ b/clap_complete/tests/snapshots/quoting.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/special_commands.bash b/clap_complete/tests/snapshots/special_commands.bash
index 663346ec..bc5857c6 100644
--- a/clap_complete/tests/snapshots/special_commands.bash
+++ b/clap_complete/tests/snapshots/special_commands.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/sub_subcommands.bash b/clap_complete/tests/snapshots/sub_subcommands.bash
index 1faeea7b..7435f56b 100644
--- a/clap_complete/tests/snapshots/sub_subcommands.bash
+++ b/clap_complete/tests/snapshots/sub_subcommands.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/subcommand_last.bash b/clap_complete/tests/snapshots/subcommand_last.bash
index 7060160c..debd9cdd 100644
--- a/clap_complete/tests/snapshots/subcommand_last.bash
+++ b/clap_complete/tests/snapshots/subcommand_last.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/two_multi_valued_arguments.bash b/clap_complete/tests/snapshots/two_multi_valued_arguments.bash
index a0f32f56..9ab4d314 100644
--- a/clap_complete/tests/snapshots/two_multi_valued_arguments.bash
+++ b/clap_complete/tests/snapshots/two_multi_valued_arguments.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/value_hint.bash b/clap_complete/tests/snapshots/value_hint.bash
index c9ae7e05..acc184ff 100644
--- a/clap_complete/tests/snapshots/value_hint.bash
+++ b/clap_complete/tests/snapshots/value_hint.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/snapshots/value_terminator.bash b/clap_complete/tests/snapshots/value_terminator.bash
index 36c6d8a3..2f8e29d8 100644
--- a/clap_complete/tests/snapshots/value_terminator.bash
+++ b/clap_complete/tests/snapshots/value_terminator.bash
@@ -10,7 +10,7 @@ _my-app() {
     cmd=""
     opts=""
 
-    for i in ${COMP_WORDS[@]}
+    for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
     do
         case "${cmd},${i}" in
             ",$1")
diff --git a/clap_complete/tests/testsuite/bash.rs b/clap_complete/tests/testsuite/bash.rs
index e43f97f1..4a030bf3 100644
--- a/clap_complete/tests/testsuite/bash.rs
+++ b/clap_complete/tests/testsuite/bash.rs
@@ -208,6 +208,15 @@ another  shell    bash     fish     zsh
     let actual = runtime.complete(input, &term).unwrap();
     assert_data_eq!(actual, expected);
 
+    // Trigger completion immediately after "--"
+    let input = "exhaustive -- hint\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D\t\t";
+    let expected = snapbox::str![[r#"
+% 
+--generate      --empty-choice  --help          
+"#]];
+    let actual = runtime.complete(input, &term).unwrap();
+    assert_data_eq!(actual, expected);
+
     {
         use std::fs::File;
         use std::path::Path;
@@ -449,6 +458,15 @@ fn complete_dynamic_middle_of_word() {
     let expected = snapbox::str![[r#"
 % 
 another shell  bash           fish           zsh            
+"#]];
+    let actual = runtime.complete(input, &term).unwrap();
+    assert_data_eq!(actual, expected);
+
+    // Trigger completion immediately after "--"
+    let input = "exhaustive -- hint\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D\t\t";
+    let expected = snapbox::str![[r#"
+% 
+--generate      --empty-choice  --help          
 "#]];
     let actual = runtime.complete(input, &term).unwrap();
     assert_data_eq!(actual, expected);