Repository: kbknapp/clap-rs
Pull request #1214 (2018-03-18 16:34:56)

fish: Fix completion of >1 options
Fixes https://github.com/kbknapp/clap-rs/issues/1212 using upstream  [`__fish_use_subcommand`](https://github.com/fish-shell/fish-shell/blob/master/share/functions/__fish_use_subcommand.fish) / [`__fish_seen_subcommand_from`](https://github.com/fish-shell/fish-shell/blob/master/share/functions/__fish_seen_subcommand_from.fish) functions rather than creating our own custom one.

This is my first foray in to the world of Rust, so feel free to amend my changes as you see fit.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kbknapp/clap-rs/1214)
<!-- Reviewable:end -->


mention-bot: @gechr, thanks for your PR! By analyzing the history of the files in this pull request, we identified @kbknapp to be a potential reviewer.

Patch:
diff --git a/src/completions/fish.rs b/src/completions/fish.rs
index 841c39b3..c2c5a5e7 100644
--- a/src/completions/fish.rs
+++ b/src/completions/fish.rs
@@ -16,25 +16,8 @@ impl<'a, 'b> FishGen<'a, 'b> {
 
     pub fn generate_to<W: Write>(&self, buf: &mut W) {
         let command = self.p.meta.bin_name.as_ref().unwrap();
-
-        // function to detect subcommand
-        let detect_subcommand_function = r#"function __fish_using_command
-    set cmd (commandline -opc)
-    if [ (count $cmd) -eq (count $argv) ]
-        for i in (seq (count $argv))
-            if [ $cmd[$i] != $argv[$i] ]
-                return 1
-            end
-        end
-        return 0
-    end
-    return 1
-end
-
-"#.to_string();
-
-        let mut buffer = detect_subcommand_function;
-        gen_fish_inner(command, self, &command.to_string(), &mut buffer);
+        let mut buffer = String::new();
+        gen_fish_inner(command, self, command, &mut buffer);
         w!(buf, buffer.as_bytes());
     }
 }
@@ -42,7 +25,7 @@ end
 // Escape string inside single quotes
 fn escape_string(string: &str) -> String { string.replace("\\", "\\\\").replace("'", "\\'") }
 
-fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buffer: &mut String) {
+fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, subcommand: &str, buffer: &mut String) {
     debugln!("FishGen::gen_fish_inner;");
     // example :
     //
@@ -54,13 +37,15 @@ fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buf
     //      -a "{possible_arguments}"
     //      -r # if require parameter
     //      -f # don't use file completion
-    //      -n "__fish_using_command myprog subcmd1" # complete for command "myprog subcmd1"
+    //      -n "__fish_use_subcommand"               # complete for command "myprog"
+    //      -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1"
 
-    let basic_template = format!(
-        "complete -c {} -n \"__fish_using_command {}\"",
-        root_command,
-        parent_cmds
-    );
+    let mut basic_template = format!("complete -c {} -n ", root_command);
+    if root_command == subcommand {
+        basic_template.push_str("\"__fish_use_subcommand\"");
+    } else {
+        basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", subcommand).as_str());
+    }
 
     for option in comp_gen.p.opts() {
         let mut template = basic_template.clone();
@@ -109,12 +94,6 @@ fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, parent_cmds: &str, buf
     // generate options of subcommands
     for subcommand in &comp_gen.p.subcommands {
         let sub_comp_gen = FishGen::new(&subcommand.p);
-        // make new "parent_cmds" for different subcommands
-        let mut sub_parent_cmds = parent_cmds.to_string();
-        if !sub_parent_cmds.is_empty() {
-            sub_parent_cmds.push_str(" ");
-        }
-        sub_parent_cmds.push_str(&subcommand.p.meta.name);
-        gen_fish_inner(root_command, &sub_comp_gen, &sub_parent_cmds, buffer);
+        gen_fish_inner(root_command, &sub_comp_gen, &subcommand.to_string(), buffer);
     }
 }


Test patch:
diff --git a/tests/completions.rs b/tests/completions.rs
index efb001e8..09f0fb22 100644
--- a/tests/completions.rs
+++ b/tests/completions.rs
@@ -165,28 +165,15 @@ _myapp__test_commands() {
 
 _myapp "$@""#;
 
-static FISH: &'static str = r#"function __fish_using_command
-    set cmd (commandline -opc)
-    if [ (count $cmd) -eq (count $argv) ]
-        for i in (seq (count $argv))
-            if [ $cmd[$i] != $argv[$i] ]
-                return 1
-            end
-        end
-        return 0
-    end
-    return 1
-end
-
-complete -c myapp -n "__fish_using_command myapp" -s h -l help -d 'Prints help information'
-complete -c myapp -n "__fish_using_command myapp" -s V -l version -d 'Prints version information'
-complete -c myapp -n "__fish_using_command myapp" -f -a "test" -d 'tests things'
-complete -c myapp -n "__fish_using_command myapp" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)'
-complete -c myapp -n "__fish_using_command myapp test" -l case -d 'the case to test'
-complete -c myapp -n "__fish_using_command myapp test" -s h -l help -d 'Prints help information'
-complete -c myapp -n "__fish_using_command myapp test" -s V -l version -d 'Prints version information'
-complete -c myapp -n "__fish_using_command myapp help" -s h -l help -d 'Prints help information'
-complete -c myapp -n "__fish_using_command myapp help" -s V -l version -d 'Prints version information'
+static FISH: &'static str = r#"complete -c myapp -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
+complete -c myapp -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
+complete -c myapp -n "__fish_use_subcommand" -f -a "test" -d 'tests things'
+complete -c myapp -n "__fish_use_subcommand" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)'
+complete -c myapp -n "__fish_seen_subcommand_from test" -l case -d 'the case to test'
+complete -c myapp -n "__fish_seen_subcommand_from test" -s h -l help -d 'Prints help information'
+complete -c myapp -n "__fish_seen_subcommand_from test" -s V -l version -d 'Prints version information'
+complete -c myapp -n "__fish_seen_subcommand_from help" -s h -l help -d 'Prints help information'
+complete -c myapp -n "__fish_seen_subcommand_from help" -s V -l version -d 'Prints version information'
 "#;
 
 static POWERSHELL: &'static str = r#"
@@ -421,35 +408,22 @@ _my_app__test_commands() {
 
 _my_app "$@""#;
 
-static FISH_SPECIAL_CMDS: &'static str = r#"function __fish_using_command
-    set cmd (commandline -opc)
-    if [ (count $cmd) -eq (count $argv) ]
-        for i in (seq (count $argv))
-            if [ $cmd[$i] != $argv[$i] ]
-                return 1
-            end
-        end
-        return 0
-    end
-    return 1
-end
-
-complete -c my_app -n "__fish_using_command my_app" -s h -l help -d 'Prints help information'
-complete -c my_app -n "__fish_using_command my_app" -s V -l version -d 'Prints version information'
-complete -c my_app -n "__fish_using_command my_app" -f -a "test" -d 'tests things'
-complete -c my_app -n "__fish_using_command my_app" -f -a "some_cmd" -d 'tests other things'
-complete -c my_app -n "__fish_using_command my_app" -f -a "some-cmd-with-hypens"
-complete -c my_app -n "__fish_using_command my_app" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)'
-complete -c my_app -n "__fish_using_command my_app test" -l case -d 'the case to test'
-complete -c my_app -n "__fish_using_command my_app test" -s h -l help -d 'Prints help information'
-complete -c my_app -n "__fish_using_command my_app test" -s V -l version -d 'Prints version information'
-complete -c my_app -n "__fish_using_command my_app some_cmd" -l config -d 'the other case to test'
-complete -c my_app -n "__fish_using_command my_app some_cmd" -s h -l help -d 'Prints help information'
-complete -c my_app -n "__fish_using_command my_app some_cmd" -s V -l version -d 'Prints version information'
-complete -c my_app -n "__fish_using_command my_app some-cmd-with-hypens" -s h -l help -d 'Prints help information'
-complete -c my_app -n "__fish_using_command my_app some-cmd-with-hypens" -s V -l version -d 'Prints version information'
-complete -c my_app -n "__fish_using_command my_app help" -s h -l help -d 'Prints help information'
-complete -c my_app -n "__fish_using_command my_app help" -s V -l version -d 'Prints version information'
+static FISH_SPECIAL_CMDS: &'static str = r#"complete -c my_app -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_use_subcommand" -f -a "test" -d 'tests things'
+complete -c my_app -n "__fish_use_subcommand" -f -a "some_cmd" -d 'tests other things'
+complete -c my_app -n "__fish_use_subcommand" -f -a "some-cmd-with-hypens"
+complete -c my_app -n "__fish_use_subcommand" -f -a "help" -d 'Prints this message or the help of the given subcommand(s)'
+complete -c my_app -n "__fish_seen_subcommand_from test" -l case -d 'the case to test'
+complete -c my_app -n "__fish_seen_subcommand_from test" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from test" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -l config -d 'the other case to test'
+complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from some_cmd" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_seen_subcommand_from some-cmd-with-hypens" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from some-cmd-with-hypens" -s V -l version -d 'Prints version information'
+complete -c my_app -n "__fish_seen_subcommand_from help" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_seen_subcommand_from help" -s V -l version -d 'Prints version information'
 "#;
 
 static BASH_SPECIAL_CMDS: &'static str = r#"_my_app() {
@@ -575,27 +549,14 @@ static BASH_SPECIAL_CMDS: &'static str = r#"_my_app() {
 complete -F _my_app -o bashdefault -o default my_app
 "#;
 
-static FISH_SPECIAL_HELP: &'static str = r#"function __fish_using_command
-    set cmd (commandline -opc)
-    if [ (count $cmd) -eq (count $argv) ]
-        for i in (seq (count $argv))
-            if [ $cmd[$i] != $argv[$i] ]
-                return 1
-            end
-        end
-        return 0
-    end
-    return 1
-end
-
-complete -c my_app -n "__fish_using_command my_app" -l single-quotes -d 'Can be \'always\', \'auto\', or \'never\''
-complete -c my_app -n "__fish_using_command my_app" -l double-quotes -d 'Can be "always", "auto", or "never"'
-complete -c my_app -n "__fish_using_command my_app" -l backticks -d 'For more information see `echo test`'
-complete -c my_app -n "__fish_using_command my_app" -l backslash -d 'Avoid \'\\n\''
-complete -c my_app -n "__fish_using_command my_app" -l brackets -d 'List packages [filter]'
-complete -c my_app -n "__fish_using_command my_app" -l expansions -d 'Execute the shell command with $SHELL'
-complete -c my_app -n "__fish_using_command my_app" -s h -l help -d 'Prints help information'
-complete -c my_app -n "__fish_using_command my_app" -s V -l version -d 'Prints version information'
+static FISH_SPECIAL_HELP: &'static str = r#"complete -c my_app -n "__fish_use_subcommand" -l single-quotes -d 'Can be \'always\', \'auto\', or \'never\''
+complete -c my_app -n "__fish_use_subcommand" -l double-quotes -d 'Can be "always", "auto", or "never"'
+complete -c my_app -n "__fish_use_subcommand" -l backticks -d 'For more information see `echo test`'
+complete -c my_app -n "__fish_use_subcommand" -l backslash -d 'Avoid \'\\n\''
+complete -c my_app -n "__fish_use_subcommand" -l brackets -d 'List packages [filter]'
+complete -c my_app -n "__fish_use_subcommand" -l expansions -d 'Execute the shell command with $SHELL'
+complete -c my_app -n "__fish_use_subcommand" -s h -l help -d 'Prints help information'
+complete -c my_app -n "__fish_use_subcommand" -s V -l version -d 'Prints version information'
 "#;
 
 static ZSH_SPECIAL_HELP: &'static str = r#"#compdef my_app