diff options
Diffstat (limited to 'crates/ra_ide_db/src')
-rw-r--r-- | crates/ra_ide_db/src/line_index.rs | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/crates/ra_ide_db/src/line_index.rs b/crates/ra_ide_db/src/line_index.rs index af7b759e5..b9db5c276 100644 --- a/crates/ra_ide_db/src/line_index.rs +++ b/crates/ra_ide_db/src/line_index.rs | |||
@@ -1,7 +1,8 @@ | |||
1 | //! `LineIndex` maps flat `TextUnit` offsets into `(Line, Column)` | 1 | //! `LineIndex` maps flat `TextUnit` offsets into `(Line, Column)` |
2 | //! representation. | 2 | //! representation. |
3 | use std::iter; | ||
3 | 4 | ||
4 | use ra_syntax::TextUnit; | 5 | use ra_syntax::{TextRange, TextUnit}; |
5 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
6 | use superslice::Ext; | 7 | use superslice::Ext; |
7 | 8 | ||
@@ -87,6 +88,19 @@ impl LineIndex { | |||
87 | self.newlines[line_col.line as usize] + col | 88 | self.newlines[line_col.line as usize] + col |
88 | } | 89 | } |
89 | 90 | ||
91 | pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | ||
92 | let lo = self.newlines.lower_bound(&range.start()); | ||
93 | let hi = self.newlines.upper_bound(&range.end()); | ||
94 | let all = iter::once(range.start()) | ||
95 | .chain(self.newlines[lo..hi].iter().copied()) | ||
96 | .chain(iter::once(range.end())); | ||
97 | |||
98 | all.clone() | ||
99 | .zip(all.skip(1)) | ||
100 | .map(|(lo, hi)| TextRange::from_to(lo, hi)) | ||
101 | .filter(|it| !it.is_empty()) | ||
102 | } | ||
103 | |||
90 | fn utf8_to_utf16_col(&self, line: u32, mut col: TextUnit) -> usize { | 104 | fn utf8_to_utf16_col(&self, line: u32, mut col: TextUnit) -> usize { |
91 | if let Some(utf16_chars) = self.utf16_lines.get(&line) { | 105 | if let Some(utf16_chars) = self.utf16_lines.get(&line) { |
92 | let mut correction = TextUnit::from_usize(0); | 106 | let mut correction = TextUnit::from_usize(0); |
@@ -221,4 +235,32 @@ const C: char = \"メ メ\"; | |||
221 | 235 | ||
222 | assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15)); | 236 | assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15)); |
223 | } | 237 | } |
238 | |||
239 | #[test] | ||
240 | fn test_splitlines() { | ||
241 | fn r(lo: u32, hi: u32) -> TextRange { | ||
242 | TextRange::from_to(lo.into(), hi.into()) | ||
243 | } | ||
244 | |||
245 | let text = "a\nbb\nccc\n"; | ||
246 | let line_index = LineIndex::new(text); | ||
247 | |||
248 | let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>(); | ||
249 | let expected = vec![r(0, 2), r(2, 5), r(5, 9)]; | ||
250 | assert_eq!(actual, expected); | ||
251 | |||
252 | let text = ""; | ||
253 | let line_index = LineIndex::new(text); | ||
254 | |||
255 | let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>(); | ||
256 | let expected = vec![]; | ||
257 | assert_eq!(actual, expected); | ||
258 | |||
259 | let text = "\n"; | ||
260 | let line_index = LineIndex::new(text); | ||
261 | |||
262 | let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>(); | ||
263 | let expected = vec![r(0, 1)]; | ||
264 | assert_eq!(actual, expected) | ||
265 | } | ||
224 | } | 266 | } |