1use ::rustyline::config::Configurer;
2
3impl<C, R, A> ::clap::Parser for crate::Shell<C, R, A>
4 where A: ::clap::Parser + crate::Command<C, R>
5{}
6
7impl<C, R, A> ::clap::Args for crate::Shell<C, R, A>
8 where A: ::clap::Parser + crate::Command<C, R>
9{
10 fn augment_args<'b>(cmd: ::clap::Command<'b>) -> ::clap::Command<'b> {
11 cmd
12 }
13
14 fn augment_args_for_update<'b>(cmd: ::clap::Command<'b>) -> ::clap::Command<'b> {
15 cmd
16 }
17}
18
19impl<C, R, A> ::clap::IntoApp for crate::Shell<C, R, A>
20 where A: ::clap::Parser + crate::Command<C, R>,
21{
22 fn into_app<'b>() -> ::clap::App<'b> {
23 ::clap::App::new("shell").about("Try out this CLI in a shell!")
26 }
27
28 fn into_app_for_update<'b>() -> ::clap::App<'b> {
29 Self::into_app()
30 }
31}
32
33impl<C, R, A> ::clap::FromArgMatches for crate::Shell<C, R, A>
34 where A: ::clap::Parser + crate::Command<C, R>,
35{
36 fn from_arg_matches(_matches: &::clap::ArgMatches) -> Result<Self, ::clap::Error> {
37 Ok(Self{
38 _phda: ::std::marker::PhantomData::<A>,
39 _phdc: ::std::marker::PhantomData::<C>,
40 _phdr: ::std::marker::PhantomData::<R>,
41 })
42 }
43
44 fn update_from_arg_matches(
45 &mut self,
46 _matches: &::clap::ArgMatches,
47 ) -> Result<(), ::clap::Error> {
48 Ok(())
49 }
50}
51
52impl<C, R, A> crate::Command<C, R> for crate::Shell<C, R, A>
53 where A: ::clap::Parser + crate::Command<C, R>,
54{
55 fn run(self, ctx: &mut C) -> ::anyhow::Result<R> {
56 let mut rl = ::rustyline::Editor::<()>::new()?;
57 rl.set_completion_type(::rustyline::CompletionType::List);
58 rl.set_edit_mode(::rustyline::EditMode::Vi);
59
60 let mut last_res = Err(::anyhow::Error::msg("no result available (no command ran)"));
61 loop {
62 let args = match ::shellwords::split(rl.readline("> ")?.trim_end()) {
64 Err(_) => { eprintln!("mismatched quotes"); continue },
65 Ok(args) => args,
66 };
67
68 if is_asking_to_exit(&args) {
70 break last_res; } else {
72 let args = ::std::iter::once("shell".to_owned()).chain(args.into_iter());
76 match A::try_parse_from(args) {
77 Err(err) => eprintln!("{}", err), Ok(app) => {
79 last_res = match app.run(ctx) {
80 Err(err) => { eprintln!("{}", err); Err(err) }
81 Ok(res) => Ok(res),
82 }
83 }
84 }
85 }
86 }
87 }
88}
89
90fn is_asking_to_exit(args: &Vec<String>) -> bool {
91 args.len() == 1 && (args[0] == "exit" || args[0] == "quit" || args[0] == "q")
92}