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 {
25    Run(ParseCtx, String),
26    Inquire(String),
27    ExpectedAct(ParseCtx, String),
28    UnknownAct(ParseCtx, String),
29    Args(ParseCtx, ArgsParseErr, String),
30}
31
32#[derive(Clone, Debug)]
33pub struct ParseCtx {
34    pub pfx: Vec<Arg>,
35}
36
37impl ActsErr {
38    fn display<'a>(self, arg0: &'a Arg) -> DActsErr<'a> {
39        DActsErr { e: self, arg0 }
40    }
41}
42struct DActsErr<'a> {
43    e: ActsErr,
44    arg0: &'a Arg,
45}
46
47impl Display for ActsErr {
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) | UnknownAct(ref c, ref u) => {
68                write!(f, "Usage: {} {} <action>\n{u}", self.arg0, c.pfx.join(" "))?;
69            }
70            Args(ref c, _, ref u) => {
71                write!(
72                    f,
73                    "Usage: {} {} <opts...>\nOpts:\n{u}",
74                    self.arg0,
75                    c.pfx.join(" ")
76                )?;
77            }
78            _ => (),
79        };
80        Ok(())
81    }
82}
83impl From<InquireError> for ActsErr {
84    fn from(v: InquireError) -> Self {
85        Self::Inquire(format!("{v}"))
86    }
87}
88
89pub type Arg = String;
90pub trait Acts<C>: Sized {
91    fn run(c: &C) -> Result<(), String> {
92        let a: Vec<_> = args().collect();
93        let mut s = ParseCtx { pfx: vec![] };
94        Self::next(c, &mut s, &a[1..]).map_err(|e| format!("{}", e.display(&a[0])))
95    }
96
97    fn next(c: &C, s: &mut ParseCtx, args: &[Arg]) -> Result<(), ActsErr> {
98        if args.is_empty() {
99            print!("{}", ActsErr::ExpectedAct(s.to_owned(), Self::usage()));
100            return Self::next(c, s, &[Self::select_act()?.to_owned()]);
101        };
102        let a = &args[0];
103        let args = &args[1..];
104
105        use ActsErr::*;
106        match Self::next_impl(c, s, a, args) {
107            Err(e) => match e {
108                UnknownAct(_, _) => {
109                    print!("{e}");
110                    Self::next(c, s, &[Self::select_act()?.to_owned()])
111                }
112                _ => return Err(e),
113            },
114            e => return e,
115        }
116    }
117    fn select_act() -> Result<&'static str, ActsErr> {
118        let opts: Vec<_> = to_lines(&Self::usage_v())
119            .into_iter()
120            .enumerate()
121            .map(|(i, o)| ListOption::new(i, o))
122            .collect();
123        Ok(Self::opts()[Select::new("Choose an action.", opts)
124            .with_page_size(50)
125            .prompt()?
126            .index])
127    }
128
129    fn list() -> Vec<Vec<String>> {
130        let pfx = vec![];
131        let mut res: Vec<Vec<String>> = vec![];
132        Self::add_paths(&pfx, &mut res);
133        return res;
134    }
135    fn usage() -> String {
136        to_table(&Self::usage_v())
137    }
138
139    fn opts() -> Vec<&'static str>;
140    fn next_impl(c: &C, s: &mut ParseCtx, a: &Arg, args: &[Arg]) -> Result<(), ActsErr>;
141    fn desc_act() -> &'static str;
142    fn usage_v() -> Vec<[&'static str; 2]>;
143    fn add_paths(pfx: &Vec<String>, p: &mut Vec<Vec<String>>);
144}
145pub trait Args<C>: Sized {
146    fn next_impl(c: &C, args: &[Arg]) -> Result<(), ArgsErr> {
147        let mut args = ParsedArgs::new(args).map_err(|e| {
148            use ParsedArgsErr::*;
149            match e {
150                UnexpectedToken(a) => ArgsParseErr::UnexpectedToken(a, Self::usage(c)),
151            }
152        })?;
153
154        if args.consume(&format!("{PFX}help")).is_some() {
155            return Err(ArgsParseErr::Help(Self::usage(c)).into());
156        }
157
158        let a = Self::new(c, &mut args)?;
159
160        let u = args
161            .keys
162            .iter()
163            .filter(|k| !k.used)
164            .filter(|k| args.args[k.i] != PFX)
165            .map(|k| args.args[k.i].to_owned())
166            .collect::<Vec<_>>();
167        if !u.is_empty() {
168            return Err(ArgsParseErr::UnknownArgs(u, Self::usage(c)).into());
169        }
170
171        let _ = a.run(c).map_err(|s| ArgsErr::Run(s))?;
172        Ok(())
173    }
174    fn next(c: &C, s: &mut ParseCtx, args: &[Arg]) -> Result<(), ActsErr> {
175        match Self::next_impl(c, args) {
176            Err(e) => match e {
177                ArgsErr::Run(r) => Err(ActsErr::Run(s.to_owned(), r)),
178                ArgsErr::Parse(e) => Err(ActsErr::Args(s.to_owned(), e, Self::usage(c))),
179            },
180            Ok(o) => Ok(o),
181        }
182    }
183    fn usage(c: &C) -> String {
184        let mut r: Vec<[String; 4]> = vec![];
185        Self::add_usage(c, &mut r);
186        to_table(&r)
187    }
188    fn new(c: &C, args: &mut ParsedArgs) -> Result<Self, ArgsParseErr>;
189    fn desc_act() -> &'static str;
190    fn add_paths(pfx: &Vec<String>, p: &mut Vec<Vec<String>>);
191    fn add_usage(c: &C, r: &mut Vec<[String; 4]>);
192    fn default(c: &C) -> Self;
193
194    fn run(self, c: &C) -> Result<(), String>;
195}
196
197pub trait Parse
198where
199    Self: Sized + Display,
200{
201    fn parse(i: &Arg) -> Result<Self, ParseErr>;
202    fn desc() -> &'static str;
203}
204#[derive(Debug)]
205pub struct ParseErr {
206    pub ty: &'static str,
207    pub i: Arg,
208    pub e: String,
209}
210
211pub struct DisplayVec<T: Display>(Vec<T>);
212impl<T: Display> Display for DisplayVec<T> {
213    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214        write!(f, "{}", self.0.iter().map(|t| format!("{t}")).join(", "))
215    }
216}
217impl<T: Display> From<Vec<T>> for DisplayVec<T> {
218    fn from(v: Vec<T>) -> Self {
219        Self(v)
220    }
221}
222impl<T: Display> Into<Vec<T>> for DisplayVec<T> {
223    fn into(self) -> Vec<T> {
224        self.0
225    }
226}