1 use std::fmt::Display; 2 use std::str::FromStr; 3 4 use clap::builder::PossibleValue; 5 use clap::ValueEnum; 6 7 /// Completion support for built-in shells 8 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 9 #[non_exhaustive] 10 pub enum Shell { 11 /// Bourne Again `SHell` (bash) 12 Bash, 13 /// Friendly Interactive `SHell` (fish) 14 Fish, 15 } 16 17 impl Display for Shell { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 19 self.to_possible_value() 20 .expect("no values are skipped") 21 .get_name() 22 .fmt(f) 23 } 24 } 25 26 impl FromStr for Shell { 27 type Err = String; 28 from_str(s: &str) -> Result<Self, Self::Err>29 fn from_str(s: &str) -> Result<Self, Self::Err> { 30 for variant in Self::value_variants() { 31 if variant.to_possible_value().unwrap().matches(s, false) { 32 return Ok(*variant); 33 } 34 } 35 Err(format!("invalid variant: {s}")) 36 } 37 } 38 39 // Hand-rolled so it can work even when `derive` feature is disabled 40 impl ValueEnum for Shell { value_variants<'a>() -> &'a [Self]41 fn value_variants<'a>() -> &'a [Self] { 42 &[Shell::Bash, Shell::Fish] 43 } 44 to_possible_value(&self) -> Option<PossibleValue>45 fn to_possible_value(&self) -> Option<PossibleValue> { 46 Some(match self { 47 Shell::Bash => PossibleValue::new("bash"), 48 Shell::Fish => PossibleValue::new("fish"), 49 }) 50 } 51 } 52 53 impl Shell { completer(&self) -> &dyn crate::dynamic::Completer54 fn completer(&self) -> &dyn crate::dynamic::Completer { 55 match self { 56 Self::Bash => &super::Bash, 57 Self::Fish => &super::Fish, 58 } 59 } 60 } 61 62 impl crate::dynamic::Completer for Shell { file_name(&self, name: &str) -> String63 fn file_name(&self, name: &str) -> String { 64 self.completer().file_name(name) 65 } write_registration( &self, name: &str, bin: &str, completer: &str, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error>66 fn write_registration( 67 &self, 68 name: &str, 69 bin: &str, 70 completer: &str, 71 buf: &mut dyn std::io::Write, 72 ) -> Result<(), std::io::Error> { 73 self.completer() 74 .write_registration(name, bin, completer, buf) 75 } write_complete( &self, cmd: &mut clap::Command, args: Vec<std::ffi::OsString>, current_dir: Option<&std::path::Path>, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error>76 fn write_complete( 77 &self, 78 cmd: &mut clap::Command, 79 args: Vec<std::ffi::OsString>, 80 current_dir: Option<&std::path::Path>, 81 buf: &mut dyn std::io::Write, 82 ) -> Result<(), std::io::Error> { 83 self.completer().write_complete(cmd, args, current_dir, buf) 84 } 85 } 86