ragit_cli/
span.rs

1#[derive(Clone, Debug)]
2pub enum Span {
3    Exact(usize),  // including flags and args
4    FirstArg,
5    End,
6    NthArg(usize),  // including args, not including flags
7    Rendered((String, usize, usize)),
8}
9
10impl Span {
11    pub(crate) fn render(&self, args: &[String]) -> Self {
12        let mut rendered_args = Vec::with_capacity(args.len());
13        let mut arg_indices = vec![];
14
15        for (index, arg) in args.iter().enumerate() {
16            if !arg.starts_with("--") {
17                arg_indices.push(index);
18            }
19
20            if arg.contains(" ") || arg.contains("\"") || arg.contains("'") || arg.contains("\n") {
21                rendered_args.push(format!("{arg:?}"));
22            }
23
24            else {
25                rendered_args.push(arg.to_string());
26            }
27        }
28
29        let selected_index = match self {
30            Span::Exact(n) => *n,
31            Span::FirstArg => match arg_indices.get(0) {
32                Some(n) => *n,
33                None => 0,
34            },
35            Span::NthArg(n) => match arg_indices.get(*n) {
36                Some(n) => *n,
37                None => 0,
38            },
39            _ => 0,
40        };
41        let mut joined_args = rendered_args.join(" ");
42        let (start, end) = if joined_args.is_empty() {
43            joined_args = String::from(" ");
44            (0, 1)
45        } else {
46            match self {
47                Span::End => (joined_args.len() - 1, joined_args.len()),
48                _ => (
49                    rendered_args[..selected_index].iter().map(|arg| arg.len()).sum::<usize>() + selected_index,
50                    rendered_args[..(selected_index + 1)].iter().map(|arg| arg.len()).sum::<usize>() + selected_index,
51                ),
52            }
53        };
54
55        Span::Rendered((
56            joined_args,
57            start,
58            end,
59        ))
60    }
61
62    pub fn unwrap_rendered(&self) -> (String, usize, usize) {
63        match self {
64            Span::Rendered((span, start, end)) => (span.to_string(), *start, *end),
65            _ => panic!(),
66        }
67    }
68}