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