1use std::{
2 borrow::Borrow,
3 ops::{Deref, DerefMut},
4};
5
6use ropey::Rope;
7
8use crate::{
9 lsp_types::{Location, Position, Range},
10 Label,
11};
12
13pub mod fs;
14pub mod ns;
16pub mod token;
17pub mod triple;
18
19pub fn range_to_range(range: &std::ops::Range<usize>, rope: &Rope) -> Option<Range> {
32 let start = offset_to_position(range.start, rope)?;
33 let end = offset_to_position(range.end, rope)?;
34 Range::new(start, end).into()
35}
36
37pub fn lsp_range_to_range(
38 range: &crate::lsp_types::Range,
39 rope: &Rope,
40) -> Option<std::ops::Range<usize>> {
41 if range.start.line as usize >= rope.len_lines() || range.end.line as usize >= rope.len_lines()
42 {
43 return None;
44 }
45
46 let start = rope.line_to_byte(range.start.line as usize) + range.start.character as usize;
47 let end = rope.line_to_byte(range.end.line as usize) + range.end.character as usize;
48
49 Some(start..end)
50}
51
52pub fn offset_to_position(offset: usize, rope: &Rope) -> Option<Position> {
53 let line = rope.try_char_to_line(offset).ok()?;
54 let first_char = rope.try_line_to_char(line).ok()?;
55 let column = offset - first_char;
56 Some(Position::new(line as u32, column as u32))
57}
58pub fn position_to_offset(position: Position, rope: &Rope) -> Option<usize> {
59 let line_offset = rope.try_line_to_char(position.line as usize).ok()?;
60 let line_length = rope.get_line(position.line as usize)?.len_chars();
61
62 if (position.character as usize) < line_length {
63 Some(line_offset + position.character as usize)
64 } else {
65 None
66 }
67}
68pub fn offsets_to_range(start: usize, end: usize, rope: &Rope) -> Option<Range> {
69 let start = offset_to_position(start, rope)?;
70 let end = offset_to_position(end, rope)?;
71 Some(Range { start, end })
72}
73
74#[derive(Debug, Clone)]
75pub struct Spanned<T>(pub T, pub std::ops::Range<usize>);
76impl<T> Default for Spanned<T>
77where
78 T: Default,
79{
80 fn default() -> Self {
81 Self(T::default(), 0..1)
82 }
83}
84
85impl<T> Spanned<T> {
86 pub fn map<O>(self, f: impl Fn(T) -> O) -> Spanned<O> {
87 let v = f(self.0);
88 Spanned(v, self.1)
89 }
90 pub fn map_ref<'a, O: 'a>(&'a self, f: impl Fn(&'a T) -> O) -> Spanned<O> {
91 let v = f(&self.0);
92 Spanned(v, self.1.clone())
93 }
94 pub fn as_ref<'a>(&'a self) -> Spanned<&'a T> {
95 Spanned(&self.0, self.1.clone())
96 }
97
98 pub fn try_map_ref<'a, O>(&'a self, f: impl FnOnce(&'a T) -> Option<O>) -> Option<Spanned<O>> {
99 if let Some(v) = f(&self.0) {
100 Some(Spanned(v, self.1.clone()))
101 } else {
102 None
103 }
104 }
105 pub fn try_map<O>(self, f: impl FnOnce(T) -> Option<O>) -> Option<Spanned<O>> {
106 if let Some(v) = f(self.0) {
107 Some(Spanned(v, self.1))
108 } else {
109 None
110 }
111 }
112}
113impl<T> Spanned<Option<T>> {
114 pub fn transpose(self) -> Option<Spanned<T>> {
115 self.0.map(|inner| Spanned(inner, self.1))
116 }
117}
118
119impl<T: PartialEq> PartialEq for Spanned<T> {
120 fn eq(&self, other: &Self) -> bool {
121 self.0.eq(&other.0)
122 }
123}
124impl<T: std::hash::Hash> std::hash::Hash for Spanned<T> {
125 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
126 self.0.hash(state)
127 }
128}
129impl<T: PartialEq> Eq for Spanned<T> {}
130
131pub fn spanned<T>(t: T, span: std::ops::Range<usize>) -> Spanned<T> {
132 Spanned(t, span)
133}
134
135impl Borrow<str> for Spanned<String> {
136 #[inline]
137 fn borrow(&self) -> &str {
138 &self[..]
139 }
140}
141
142impl<T> Deref for Spanned<T> {
143 type Target = T;
144
145 fn deref(&self) -> &Self::Target {
146 &self.0
147 }
148}
149
150impl<T> DerefMut for Spanned<T> {
151 fn deref_mut(&mut self) -> &mut Self::Target {
152 &mut self.0
153 }
154}
155
156impl<T> Spanned<T> {
157 pub fn into_value(self) -> T {
158 self.0
159 }
160 pub fn into_span(self) -> std::ops::Range<usize> {
161 self.1
162 }
163 pub fn value(&self) -> &T {
164 &self.0
165 }
166 pub fn value_mut(&mut self) -> &mut T {
167 &mut self.0
168 }
169 pub fn span(&self) -> &std::ops::Range<usize> {
170 &self.1
171 }
172}
173
174pub fn token_to_location(
175 token: &std::ops::Range<usize>,
176 label: &Label,
177 rope: &Rope,
178) -> Option<Location> {
179 let range = range_to_range(token, rope)?;
180 Some(Location {
181 range,
182 uri: label.0.clone(),
183 })
184}