1use std::{
2 fmt::Display,
3 ops::{Add, AddAssign, Sub},
4};
5
6use super::Position;
7
8#[derive(Debug, Default, Clone, Copy, PartialEq)]
9pub struct Span {
11 start: Position,
12 end: Position,
13}
14
15impl Span {
16 pub fn new(start: Position, end: Position) -> Self {
18 Self { start, end }
19 }
20
21 pub(crate) fn tie_end(&mut self) {
22 self.start = self.end;
23 }
24
25 pub(crate) fn tie_start(&mut self) {
26 self.end = self.start;
27 }
28
29 pub(crate) fn unquote(&self) -> Self {
30 let mut span = *self;
31 span.start += (0, 1);
32 span.end -= (0, 1);
33 span
34 }
35
36 pub(crate) fn inserted() -> Self {
38 let pos = Position::new(0, 0);
39 Span::new(pos, pos)
40 }
41
42 pub fn calculate(source: &str) -> Self {
44 let start = Position::default();
45
46 let mut end = start;
47 for c in source.chars() {
48 if c == '\n' {
49 end.line += 1;
50 end.column = 1;
51 } else {
52 end.column += 1;
53 }
54 }
55
56 Self { start, end }
57 }
58}
59
60impl Add<(i32, i32)> for Span {
61 type Output = Span;
62
63 fn add(mut self, rhs: (i32, i32)) -> Self::Output {
64 self.end += rhs;
65 self
66 }
67}
68
69impl AddAssign<(i32, i32)> for Span {
70 fn add_assign(&mut self, rhs: (i32, i32)) {
71 self.end += rhs;
72 }
73}
74
75impl AddAssign for Span {
76 fn add_assign(&mut self, rhs: Self) {
77 self.end = rhs.end
78 }
79}
80
81impl Sub<(i32, i32)> for Span {
82 type Output = Span;
83
84 fn sub(mut self, rhs: (i32, i32)) -> Self::Output {
85 self.start -= rhs;
86 self
87 }
88}
89
90impl Display for Span {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 if f.alternate() {
93 f.write_fmt(format_args!("{:#}..{:#}", self.start, self.end))
94 } else if *self == Span::inserted() {
95 f.write_str("\x1b[4minserted\x1b[24m")
96 } else {
97 f.write_fmt(format_args!("{}..{}", self.start, self.end))
98 }
99 }
100}