1#[derive(Clone, Debug)]
2pub enum Span {
3 Exact(usize), FirstArg,
5 End,
6 NthArg(usize), 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}