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}