Skip to content
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

Rudimentary bash completion #115

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions complete/src/bash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

use crate::{Command, Flag};

/// Create completion script for `bash`
///
/// Short and long options are combined into single `complete` calls, even if
/// they differ in whether they take arguments or not; just like in case of `fish`.
/// Also, pretend that files are fine in any position. ValueHints are ignored entirely.
pub fn render(c: &Command) -> String {
let mut out = String::new();
// Be careful around the program '['!
let name_identifier = if c.name == "[" { &"bracket" } else { &c.name };
// Register _comp_uu_FOO as a bash function that computes completions:
out.push_str(&format!(
"complete -F _comp_uu_{name_identifier} '{}';",
&c.name
));
out.push_str(&format!("_comp_uu_{name_identifier}()"));
// Unless the current argument starts with "-", pre-populate the completions list with all files and dirs:
out.push_str("{ local cur;_init_completion||return;COMPREPLY=();if [[ \"$cur\" != \"-*\" ]]; then _filedir;fi;COMPREPLY+=($(compgen -W \"");
for arg in &c.args {
for Flag { flag, .. } in &arg.short {
out.push_str(&format!("-{flag} "));
}
for Flag { flag, .. } in &arg.long {
out.push_str(&format!("--{flag} "));
}
}
out.push_str("\" -- \"$cur\"));}\n");
out
}

#[cfg(test)]
mod test {
use super::render;
use crate::{Arg, Command, Flag, Value};

#[test]
fn simple() {
let c = Command {
name: "foo",
args: vec![
Arg {
short: vec![Flag {
flag: "a",
value: Value::No,
}],
long: vec![Flag {
flag: "all",
value: Value::No,
}],
..Arg::default()
},
Arg {
short: vec![Flag {
flag: "x",
value: Value::No,
}],
..Arg::default()
},
],
..Command::default()
};
assert_eq!(render(&c), "complete -F _comp_uu_foo 'foo';_comp_uu_foo(){ local cur;_init_completion||return;COMPREPLY=();if [[ \"$cur\" != \"-*\" ]]; then _filedir;fi;COMPREPLY+=($(compgen -W \"-a --all -x \" -- \"$cur\"));}\n")
}

#[test]
fn bracket() {
let c = Command {
name: "[",
args: vec![Arg {
short: vec![Flag {
flag: "x",
value: Value::No,
}],
..Arg::default()
}],
..Command::default()
};
assert_eq!(render(&c), "complete -F _comp_uu_bracket '[';_comp_uu_bracket(){ local cur;_init_completion||return;COMPREPLY=();if [[ \"$cur\" != \"-*\" ]]; then _filedir;fi;COMPREPLY+=($(compgen -W \"-x \" -- \"$cur\"));}\n")
}
}
6 changes: 4 additions & 2 deletions complete/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! - Some information is removed because it is irrelevant for completion and documentation
//! - This struct is meant to exist at runtime of the program
//!
mod bash;
mod fish;
mod man;
mod md;
Expand Down Expand Up @@ -75,7 +76,8 @@ pub fn render(c: &Command, shell: &str) -> String {
"zsh" => zsh::render(c),
"nu" | "nushell" => nu::render(c),
"man" => man::render(c),
"sh" | "bash" | "csh" | "elvish" | "powershell" => panic!("shell '{shell}' completion is not implemented yet!"),
_ => panic!("unknown option '{shell}'! Expected one of: \"md\", \"fish\", \"zsh\", \"man\", \"sh\", \"bash\", \"csh\", \"elvish\", \"powershell\""),
"bash" => bash::render(c),
"sh" | "csh" | "elvish" | "powershell" => panic!("shell '{shell}' completion is not implemented yet!"),
_ => panic!("unknown option '{shell}'! Expected one of: \"md\", \"fish\", \"zsh\", \"nu[shell]\", \"man\", \"sh\", \"bash\", \"csh\", \"elvish\", \"powershell\""),
}
}
4 changes: 2 additions & 2 deletions docs/guide/completions.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Shell completions and documentation can be generated automatically by this crate
cargo run --features parse-is-complete -- [shell]
```

The `[shell]` value here can be `fish`, `zsh`, `bash`, `powershell`, `elvish` or `nu`.
The `[shell]` value here can be `fish`, `zsh`, `nu`, `sh`, `bash`, `csh`, `elvish`, or `powershell`.

> **Note**: Some of these remain unimplemented as of writing.

Expand All @@ -47,4 +47,4 @@ If you do not want to hijack the [`Options::parse`](crate::Options::parse) funct
[Up](super)
[Next]()

</div>
</div>
Loading