1use std::fmt::Display;
2
3use crate::Position;
4
5#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct Span {
7 pub input: String,
8 pub start: Position,
9 pub end: Position,
10}
11impl Span {
12 pub fn new<T: Display>(input: T, start: (usize, usize), end: (usize, usize)) -> Span {
13 Span {
14 input: input.to_string(),
15 start: Position::from_tuple(start),
16 end: Position::from_tuple(end),
17 }
18 }
19
20 pub fn input(&self) -> &str {
21 self.input.as_str()
22 }
23
24 pub fn with_input(&self, input: &str) -> Span {
25 let mut info = self.clone();
26 info.input = input.to_string();
27 info
28 }
29
30 pub fn info(&self) -> Span {
31 self.clone()
32 }
33
34 pub fn start(&self) -> (usize, usize) {
35 self.start.to_tuple()
36 }
37
38 pub fn end(&self) -> (usize, usize) {
39 self.end.to_tuple()
40 }
41
42 pub fn highlight_input(&self, indent: usize) -> String {
43 crate::color::fore(self.highlight_input_chars(indent), 32)
44 }
45
46 fn highlight_input_chars(&self, indent: usize) -> String {
47 let start = self.start.clone();
48 let end = self.end.clone();
49 self.input
50 .lines()
51 .enumerate()
52 .map(|(no, line)| {
53 (
54 no + 1,
55 line.chars()
56 .enumerate()
57 .map(|(no, column)| (no + 1, column.to_string()))
58 .collect::<Vec<(usize, String)>>(),
59 )
60 })
61 .map(|(line, columns)| {
62 crate::color::bg(
63 format!(
64 "{}{}",
65 " ".repeat(indent),
66 columns
67 .iter()
68 .map(|(column, text)| {
69 let column = column.clone();
70 if line == start.line && column == start.column {
71 crate::color::bgfg(text, 235, 198)
72 } else if line == end.line && column == end.column {
73 [crate::color::reset(""), crate::color::bg(text, 235)].join("")
74 } else {
75 crate::color::bg(text, 235)
76 }
77 })
78 .collect::<String>()
79 ),
80 235,
81 )
82 })
83 .collect::<Vec<String>>()
84 .join("\n")
85 }
86}
87
88impl std::fmt::Display for Span {
89 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
90 write!(f, "{}", &self.input)
91 }
92}
93
94impl Into<String> for Span {
95 fn into(self) -> String {
96 self.to_string()
97 }
98}
99
100impl Into<((usize, usize), (usize, usize))> for Span {
101 fn into(self) -> ((usize, usize), (usize, usize)) {
102 (self.start.to_tuple(), self.end.to_tuple())
103 }
104}