1use std::ops::Range;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct FileSpan {
12 pub start: usize,
13 pub end: usize,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum LintSpan {
26 Global(nu_protocol::Span),
27 File(FileSpan),
28}
29
30impl FileSpan {
31 #[must_use]
32 pub const fn new(start: usize, end: usize) -> Self {
33 Self { start, end }
34 }
35
36 #[must_use]
38 pub fn to_global_span(self, file_offset: usize) -> nu_protocol::Span {
39 nu_protocol::Span::new(self.start + file_offset, self.end + file_offset)
40 }
41
42 #[must_use]
44 pub fn merge(self, other: Self) -> Self {
45 Self {
46 start: self.start.min(other.start),
47 end: self.end.max(other.end),
48 }
49 }
50
51 #[must_use]
52 pub const fn len(&self) -> usize {
53 self.end.saturating_sub(self.start)
54 }
55
56 #[must_use]
57 pub const fn is_empty(&self) -> bool {
58 self.start >= self.end
59 }
60
61 #[must_use]
62 pub const fn as_range(&self) -> Range<usize> {
63 self.start..self.end
64 }
65}
66
67impl LintSpan {
68 #[must_use]
70 pub const fn to_file_span(self, file_offset: usize) -> FileSpan {
71 match self {
72 Self::Global(g) => FileSpan {
73 start: g.start.saturating_sub(file_offset),
74 end: g.end.saturating_sub(file_offset),
75 },
76 Self::File(f) => f,
77 }
78 }
79
80 #[must_use]
84 pub fn file_span(&self) -> FileSpan {
85 match self {
86 Self::File(f) => *f,
87 Self::Global(_) => panic!("Span not normalized - call normalize_spans first"),
88 }
89 }
90}
91
92impl From<nu_protocol::Span> for LintSpan {
93 fn from(span: nu_protocol::Span) -> Self {
94 Self::Global(span)
95 }
96}
97
98impl From<FileSpan> for LintSpan {
99 fn from(span: FileSpan) -> Self {
100 Self::File(span)
101 }
102}
103
104impl From<FileSpan> for nu_protocol::Span {
105 fn from(span: FileSpan) -> Self {
106 Self::new(span.start, span.end)
107 }
108}