fpr_cli/
lib.rs

1mod i;
2mod parse;
3mod util;
4
5mod com {
6    pub use crate::*;
7    pub use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
8    pub use inquire::{
9        autocompletion::Replacement, list_option::ListOption, validator::CustomTypeValidator,
10        validator::ErrorMessage, Autocomplete, CustomType, CustomUserError, InquireError,
11        MultiSelect, Select, Text,
12    };
13    pub use itertools::Itertools;
14    pub use std::{env::args, fmt::Display, path::PathBuf, str::FromStr};
15}
16
17pub use util::*;
18
19pub use i::*;
20pub use parse::*;
21
22use com::*;
23
24pub enum ActsErr<'a> {
25    Run(ParseCtx<'a>, String),
26    Inquire(String),
27    ExpectedAct(ParseCtx<'a>, String),
28    UnknownAct(ParseCtx<'a>, &'a str),
29    Args(ParseCtx<'a>, ArgsParseErr<'a>, String),
30}
31
32#[derive(Clone, Debug)]
33pub struct ParseCtx<'a> {
34    pub pfx: Vec<Arg<'a>>,
35}
36
37impl<'a> ActsErr<'a> {
38    fn display(self, arg0: &'a Arg) -> DActsErr<'a> {
39        DActsErr { e: self, arg0 }
40    }
41}
42struct DActsErr<'a> {
43    e: ActsErr<'a>,
44    arg0: Arg<'a>,
45}
46
47impl<'a> Display for ActsErr<'a> {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        use ActsErr::*;
50        match self {
51            Run(_, ref e) => write!(f, "Failed to run:\n{e}"),
52            Inquire(ref e) => write!(f, "{e}"),
53            ExpectedAct(_, _) => write!(f, "Expected an act.\n"),
54            UnknownAct(_, ref e) => write!(f, "Unknown act '{e}.'\n"),
55            Args(_, ref e, _) => match e {
56                ArgsParseErr::Help(_) => write!(f, "{e}"),
57                _ => write!(f, "Failed to parse opts.\n{e}\n"),
58            },
59        }
60    }
61}
62impl<'a> Display for DActsErr<'a> {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        use ActsErr::*;
65        write!(f, "{}", self.e)?;
66        match self.e {
67            ExpectedAct(ref c, ref u) => {
68                write!(f, "Usage: {} {} <action>\n{u}", self.arg0, c.pfx.join(" "))?;
69            }
70            UnknownAct(ref c, ref u) => {
71                write!(f, "Usage: {} {} <action>\n{u}", self.arg0, c.pfx.join(" "))?;
72            }
73            Args(ref c, _, ref u) => {
74                write!(
75                    f,
76                    "Usage: {} {} <opts...>\nOpts:\n{u}",
77                    self.arg0,
78                    c.pfx.join(" ")
79                )?;
80            }
81            _ => (),
82        };
83        Ok(())
84    }
85}
86impl<'a> From<InquireError> for ActsErr<'a> {
87    fn from(v: InquireError) -> Self {
88        Self::Inquire(format!("{v}"))
89    }
90}
91
92pub type Arg<'a> = &'a str;
93pub trait Acts<C>: Sized {
94    fn run(c: &C) -> Result<(), String> {
95        let args = args().collect_vec();
96        let a: Vec<_> = args.iter().map(|e| e.as_str()).collect();
97        let mut s = ParseCtx { pfx: vec![] };
98        Self::next(c, &mut s, &a[1..]).map_err(|e| format!("{}", e.display(&a[0])))
99    }
100
101    fn next<'a>(c: &C, s: &mut ParseCtx<'a>, args: &[Arg<'a>]) -> Result<(), ActsErr<'a>> {
102        if args.is_empty() {
103            print!("{}", ActsErr::ExpectedAct(s.to_owned(), Self::usage()));
104            return Self::next(c, s, &[Self::select_act()?]);
105        };
106        let a = &args[0];
107        let args = &args[1..];
108
109        use ActsErr::*;
110        match Self::next_impl(c, s, a, args) {
111            Err(e) => match e {
112                UnknownAct(_, _) => {
113                    print!("{e}");
114                    Self::next(c, s, &[Self::select_act()?])
115                }
116                _ => return Err(e),
117            },
118            e => return e,
119        }
120    }
121    fn select_act<'a>() -> Result<&'static str, ActsErr<'a>> {
122        let opts: Vec<_> = to_lines(&Self::usage_v())
123            .into_iter()
124            .enumerate()
125            .map(|(i, o)| ListOption::new(i, o))
126            .collect();
127        Ok(Self::opts()[Select::new("Choose an action.", opts)
128            .with_page_size(50)
129            .prompt()?
130            .index])
131    }
132
133    fn list<'a>() -> Vec<Vec<Arg<'a>>> {
134        let pfx = vec![];
135        let mut res: Vec<Vec<Arg<'a>>> = vec![];
136        Self::add_paths(&pfx, &mut res);
137        return res;
138    }
139    fn usage() -> String {
140        to_table(&Self::usage_v())
141    }
142
143    fn opts() -> Vec<&'static str>;
144    fn next_impl<'a>(
145        c: &C,
146        s: &mut ParseCtx<'a>,
147        a: &Arg<'a>,
148        args: &[Arg<'a>],
149    ) -> Result<(), ActsErr<'a>>;
150    fn desc_act() -> &'static str;
151    fn usage_v() -> Vec<[&'static str; 2]>;
152    fn add_paths<'a>(pfx: &Vec<Arg<'a>>, p: &mut Vec<Vec<Arg<'a>>>);
153}
154pub trait Args<C>: Sized {
155    fn next_impl<'a>(c: &C, args: &[Arg<'a>]) -> Result<(), ArgsErr<'a>> {
156        let mut args = ParsedArgs::new(args).map_err(|e| {
157            use ParsedArgsErr::*;
158            match e {
159                UnexpectedToken(a) => ArgsParseErr::UnexpectedToken(a, Self::usage(c)),
160            }
161        })?;
162
163        if args.consume(&format!("{PFX}help")).is_some() {
164            return Err(ArgsParseErr::Help(Self::usage(c)).into());
165        }
166
167        let a = Self::new(c, &mut args)?;
168
169        let u = args
170            .keys
171            .iter()
172            .filter(|k| !k.used)
173            .filter(|k| args.args[k.i] != PFX)
174            .map(|k| args.args[k.i])
175            .collect::<Vec<_>>();
176        if !u.is_empty() {
177            return Err(ArgsParseErr::UnknownArgs(u, Self::usage(c)).into());
178        }
179
180        let _ = a.run(c).map_err(|s| ArgsErr::Run(s))?;
181        Ok(())
182    }
183    fn next<'a>(c: &C, s: &mut ParseCtx<'a>, args: &[Arg<'a>]) -> Result<(), ActsErr<'a>> {
184        match Self::next_impl(c, args) {
185            Err(e) => match e {
186                ArgsErr::Run(r) => Err(ActsErr::Run(s.to_owned(), r)),
187                ArgsErr::Parse(e) => Err(ActsErr::Args(s.to_owned(), e, Self::usage(c))),
188            },
189            Ok(o) => Ok(o),
190        }
191    }
192    fn usage(c: &C) -> String {
193        let mut r: Vec<[String; 4]> = vec![];
194        Self::add_usage(c, &mut r);
195        to_table(&r)
196    }
197    fn new<'a, 'b>(c: &C, args: &mut ParsedArgs<'a, 'b>) -> Result<Self, ArgsParseErr<'b>>;
198    fn desc_act() -> &'static str;
199    fn add_paths<'a>(pfx: &Vec<Arg<'a>>, p: &mut Vec<Vec<Arg<'a>>>);
200    fn add_usage(c: &C, r: &mut Vec<[String; 4]>);
201    fn default(c: &C) -> Self;
202
203    fn run(self, c: &C) -> Result<(), String>;
204}
205
206pub trait Parse<'a>
207where
208    Self: Sized + Display,
209{
210    fn parse(i: Arg<'a>) -> Result<Self, ParseErr<'a>>;
211    fn desc() -> &'static str;
212}
213#[derive(Debug)]
214pub struct ParseErr<'a> {
215    pub ty: &'static str,
216    pub i: Arg<'a>,
217    pub e: String,
218}
219
220pub struct DisplayVec<T: Display>(Vec<T>);
221impl<T: Display> Display for DisplayVec<T> {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        write!(f, "{}", self.0.iter().map(|t| format!("{t}")).join(", "))
224    }
225}
226impl<T: Display> From<Vec<T>> for DisplayVec<T> {
227    fn from(v: Vec<T>) -> Self {
228        Self(v)
229    }
230}
231impl<T: Display> Into<Vec<T>> for DisplayVec<T> {
232    fn into(self) -> Vec<T> {
233        self.0
234    }
235}