aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--var/shell-complete.rs109
1 files changed, 107 insertions, 2 deletions
diff --git a/var/shell-complete.rs b/var/shell-complete.rs
index 0a525d8..c69a426 100644
--- a/var/shell-complete.rs
+++ b/var/shell-complete.rs
@@ -52,8 +52,113 @@ pub struct Args {
pub command: String,
}
+fn generate_bash<W>(command: &str, output: &mut W)
+where
+ W: io::Write,
+{
+ let mut app = nitrocli::Args::clap();
+ app.gen_completions_to(command, clap::Shell::Bash, output);
+}
+
fn main() {
let args = Args::from_args();
- let mut app = nitrocli::Args::clap();
- app.gen_completions_to(&args.command, clap::Shell::Bash, &mut io::stdout());
+ generate_bash(&args.command, &mut io::stdout())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use std::io;
+ use std::ops::Add as _;
+ use std::process;
+
+ /// Separate the given words by newlines.
+ fn lines<'w, W>(mut words: W) -> String
+ where
+ W: Iterator<Item = &'w str>,
+ {
+ let first = words.next().unwrap_or("");
+ words
+ .fold(first.to_string(), |words, word| {
+ format!("{}\n{}", words, word)
+ })
+ .add("\n")
+ }
+
+ /// Check if `bash` is present on the system.
+ fn has_bash() -> bool {
+ match process::Command::new("bash").arg("-c").arg("exit").spawn() {
+ // We deliberately only indicate that bash does not exist if we
+ // get a file-not-found error. We don't expect any other error but
+ // should there be one things will blow up later.
+ Err(ref err) if err.kind() == io::ErrorKind::NotFound => false,
+ _ => true,
+ }
+ }
+
+ /// Perform a bash completion of the given arguments to nitrocli.
+ fn complete_bash<'w, W>(words: W) -> Vec<u8>
+ where
+ W: ExactSizeIterator<Item = &'w str>,
+ {
+ let mut buffer = Vec::new();
+ generate_bash("nitrocli", &mut buffer);
+
+ let script = String::from_utf8(buffer).unwrap();
+ let command = format!(
+ "
+set -e;
+eval '{script}';
+export COMP_WORDS=({words});
+export COMP_CWORD={index};
+_nitrocli;
+echo -n ${{COMPREPLY}}
+ ",
+ index = words.len(),
+ words = lines(Some("nitrocli").into_iter().chain(words)),
+ script = script
+ );
+
+ let output = process::Command::new("bash")
+ .arg("-c")
+ .arg(command)
+ .output()
+ .unwrap();
+
+ output.stdout
+ }
+
+ #[test]
+ fn array_lines() {
+ assert_eq!(&lines(vec![].into_iter()), "\n");
+ assert_eq!(&lines(vec!["first"].into_iter()), "first\n");
+ assert_eq!(
+ &lines(vec!["first", "second"].into_iter()),
+ "first\nsecond\n"
+ );
+ assert_eq!(
+ &lines(vec!["first", "second", "third"].into_iter()),
+ "first\nsecond\nthird\n"
+ );
+ }
+
+ #[test]
+ fn complete_all_the_things() {
+ if !has_bash() {
+ return;
+ }
+
+ assert_eq!(complete_bash(vec!["stat"].into_iter()), b"status");
+ assert_eq!(
+ complete_bash(vec!["status", "--ver"].into_iter()),
+ b"--version"
+ );
+ assert_eq!(complete_bash(vec!["--version"].into_iter()), b"--version");
+ assert_eq!(complete_bash(vec!["--model", "s"].into_iter()), b"storage");
+ assert_eq!(
+ complete_bash(vec!["otp", "get", "--model", "p"].into_iter()),
+ b"pro"
+ );
+ }
}