diff options
author | Bernardo <[email protected]> | 2018-12-22 11:59:48 +0000 |
---|---|---|
committer | Bernardo <[email protected]> | 2018-12-25 19:03:14 +0000 |
commit | 36f2b1f3b9c36ace65852d971f998a090cf9b5d5 (patch) | |
tree | 7844f2e759fe477f69b8ba449490a6e4fca58977 /crates | |
parent | 1c44ba0f04a0997617d517111d0a08245f0dacac (diff) |
iterate over `Step`s which are either, newlines or multibyte chars
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_editor/src/line_index.rs | 14 | ||||
-rw-r--r-- | crates/ra_editor/src/line_index_utils.rs | 133 |
2 files changed, 121 insertions, 26 deletions
diff --git a/crates/ra_editor/src/line_index.rs b/crates/ra_editor/src/line_index.rs index 7d9b8d79f..c29e2e49a 100644 --- a/crates/ra_editor/src/line_index.rs +++ b/crates/ra_editor/src/line_index.rs | |||
@@ -15,9 +15,9 @@ pub struct LineCol { | |||
15 | } | 15 | } |
16 | 16 | ||
17 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 17 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
18 | struct Utf16Char { | 18 | pub(crate) struct Utf16Char { |
19 | start: TextUnit, | 19 | pub(crate) start: TextUnit, |
20 | end: TextUnit, | 20 | pub(crate) end: TextUnit, |
21 | } | 21 | } |
22 | 22 | ||
23 | impl Utf16Char { | 23 | impl Utf16Char { |
@@ -122,7 +122,13 @@ impl LineIndex { | |||
122 | } | 122 | } |
123 | 123 | ||
124 | pub(crate) fn newlines(&self) -> &[TextUnit] { | 124 | pub(crate) fn newlines(&self) -> &[TextUnit] { |
125 | &self.newlines[1..] | 125 | &self.newlines[..] |
126 | } | ||
127 | |||
128 | pub(crate) fn utf16_chars(&self, newline_idx: usize) -> Option<&[Utf16Char]> { | ||
129 | self.utf16_lines | ||
130 | .get(&(newline_idx as u32)) | ||
131 | .map(|x| x.as_slice()) | ||
126 | } | 132 | } |
127 | } | 133 | } |
128 | 134 | ||
diff --git a/crates/ra_editor/src/line_index_utils.rs b/crates/ra_editor/src/line_index_utils.rs index 2dd7fd708..9c8d801e9 100644 --- a/crates/ra_editor/src/line_index_utils.rs +++ b/crates/ra_editor/src/line_index_utils.rs | |||
@@ -1,8 +1,58 @@ | |||
1 | use ra_text_edit::AtomTextEdit; | 1 | use ra_text_edit::AtomTextEdit; |
2 | use ra_syntax::{TextUnit, TextRange}; | 2 | use ra_syntax::{TextUnit, TextRange}; |
3 | use crate::{LineIndex, LineCol}; | 3 | use crate::{LineIndex, LineCol, line_index::Utf16Char}; |
4 | use superslice::Ext; | 4 | use superslice::Ext; |
5 | 5 | ||
6 | #[derive(Debug, Clone)] | ||
7 | enum Step { | ||
8 | Newline(TextUnit), | ||
9 | Utf16Char(TextRange), | ||
10 | } | ||
11 | |||
12 | struct LineIndexStepIter<'a> { | ||
13 | line_index: &'a LineIndex, | ||
14 | newlines: std::slice::Iter<'a, TextUnit>, | ||
15 | next_newline_idx: usize, | ||
16 | utf16_chars: Option<std::slice::Iter<'a, Utf16Char>>, | ||
17 | } | ||
18 | |||
19 | impl<'a> LineIndexStepIter<'a> { | ||
20 | fn from(line_index: &LineIndex) -> LineIndexStepIter { | ||
21 | let mut x = LineIndexStepIter { | ||
22 | line_index, | ||
23 | newlines: line_index.newlines().iter(), | ||
24 | next_newline_idx: 0, | ||
25 | utf16_chars: None, | ||
26 | }; | ||
27 | // skip first newline since it's not real | ||
28 | x.next(); | ||
29 | x | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl<'a> Iterator for LineIndexStepIter<'a> { | ||
34 | type Item = Step; | ||
35 | fn next(&mut self) -> Option<Step> { | ||
36 | self.utf16_chars | ||
37 | .as_mut() | ||
38 | .and_then(|x| { | ||
39 | None | ||
40 | // TODO Enable | ||
41 | // let x = x.next()?; | ||
42 | // Some(Step::Utf16Char(TextRange::from_to(x.start, x.end))) | ||
43 | }) | ||
44 | .or_else(|| { | ||
45 | self.utf16_chars = self | ||
46 | .line_index | ||
47 | .utf16_chars(self.next_newline_idx) | ||
48 | .map(|x| x.iter()); | ||
49 | self.next_newline_idx += 1; | ||
50 | let x = self.newlines.next()?; | ||
51 | Some(Step::Newline(*x)) | ||
52 | }) | ||
53 | } | ||
54 | } | ||
55 | |||
6 | #[derive(Debug)] | 56 | #[derive(Debug)] |
7 | struct OffsetNewlineIter<'a> { | 57 | struct OffsetNewlineIter<'a> { |
8 | text: &'a str, | 58 | text: &'a str, |
@@ -10,16 +60,35 @@ struct OffsetNewlineIter<'a> { | |||
10 | } | 60 | } |
11 | 61 | ||
12 | impl<'a> Iterator for OffsetNewlineIter<'a> { | 62 | impl<'a> Iterator for OffsetNewlineIter<'a> { |
13 | type Item = TextUnit; | 63 | type Item = Step; |
14 | fn next(&mut self) -> Option<TextUnit> { | 64 | fn next(&mut self) -> Option<Step> { |
15 | let next_idx = self | 65 | let (next, next_offset) = self |
16 | .text | 66 | .text |
17 | .char_indices() | 67 | .char_indices() |
18 | .filter_map(|(i, c)| if c == '\n' { Some(i + 1) } else { None }) | 68 | .filter_map(|(i, c)| { |
69 | if c == '\n' { | ||
70 | let next_offset = self.offset + TextUnit::from_usize(i + 1); | ||
71 | let next = Step::Newline(next_offset); | ||
72 | Some((next, next_offset)) | ||
73 | } else { | ||
74 | None | ||
75 | // TODO enable | ||
76 | // let char_len = TextUnit::of_char(c); | ||
77 | // if char_len.to_usize() > 1 { | ||
78 | // let start = self.offset + TextUnit::from_usize(i); | ||
79 | // let end = start + char_len; | ||
80 | // let next = Step::Utf16Char(TextRange::from_to(start, end)); | ||
81 | // let next_offset = end; | ||
82 | // Some((next, next_offset)) | ||
83 | // } else { | ||
84 | // None | ||
85 | // } | ||
86 | } | ||
87 | }) | ||
19 | .next()?; | 88 | .next()?; |
20 | let next = self.offset + TextUnit::from_usize(next_idx); | 89 | let next_idx = (next_offset - self.offset).to_usize(); |
21 | self.text = &self.text[next_idx..]; | 90 | self.text = &self.text[next_idx..]; |
22 | self.offset = next; | 91 | self.offset = next_offset; |
23 | Some(next) | 92 | Some(next) |
24 | } | 93 | } |
25 | } | 94 | } |
@@ -83,12 +152,16 @@ impl<'a, 'b> Edits<'a, 'b> { | |||
83 | res | 152 | res |
84 | } | 153 | } |
85 | 154 | ||
86 | fn next_newlines(&mut self, candidate: TextUnit) -> NextNewlines { | 155 | fn next_step(&mut self, step: &Step) -> NextNewlines { |
156 | let step_pos = match step { | ||
157 | &Step::Newline(n) => n, | ||
158 | &Step::Utf16Char(r) => unimplemented!(), | ||
159 | }; | ||
87 | let res = match &mut self.current { | 160 | let res = match &mut self.current { |
88 | Some(edit) => { | 161 | Some(edit) => { |
89 | if candidate <= edit.delete.start() { | 162 | if step_pos <= edit.delete.start() { |
90 | NextNewlines::Use | 163 | NextNewlines::Use |
91 | } else if candidate <= edit.delete.end() { | 164 | } else if step_pos <= edit.delete.end() { |
92 | let iter = OffsetNewlineIter { | 165 | let iter = OffsetNewlineIter { |
93 | offset: edit.delete.start(), | 166 | offset: edit.delete.start(), |
94 | text: &edit.insert, | 167 | text: &edit.insert, |
@@ -129,6 +202,17 @@ impl<'a, 'b> Edits<'a, 'b> { | |||
129 | TextUnit::from((x.to_usize() as i64 + self.acc_diff) as u32) | 202 | TextUnit::from((x.to_usize() as i64 + self.acc_diff) as u32) |
130 | } | 203 | } |
131 | } | 204 | } |
205 | |||
206 | fn translate_step(&self, x: &Step) -> Step { | ||
207 | if self.acc_diff == 0 { | ||
208 | x.clone() | ||
209 | } else { | ||
210 | match x { | ||
211 | &Step::Newline(n) => Step::Newline(self.translate(n)), | ||
212 | &Step::Utf16Char(r) => Step::Utf16Char(self.translate_range(r)), | ||
213 | } | ||
214 | } | ||
215 | } | ||
132 | } | 216 | } |
133 | 217 | ||
134 | pub fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTextEdit]) -> u32 { | 218 | pub fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTextEdit]) -> u32 { |
@@ -143,33 +227,38 @@ pub fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTex | |||
143 | 227 | ||
144 | let mut lines: u32 = 0; | 228 | let mut lines: u32 = 0; |
145 | 229 | ||
146 | macro_rules! test_newline { | 230 | macro_rules! test_step { |
147 | ($x:ident) => { | 231 | ($x:ident) => { |
148 | if offset < $x { | 232 | match &$x { |
149 | return lines; | 233 | Step::Newline(n) => { |
150 | } else { | 234 | if offset < *n { |
151 | lines += 1; | 235 | return lines; |
236 | } else { | ||
237 | lines += 1; | ||
238 | } | ||
239 | } | ||
240 | Step::Utf16Char(x) => unimplemented!(), | ||
152 | } | 241 | } |
153 | }; | 242 | }; |
154 | } | 243 | } |
155 | 244 | ||
156 | for &orig_newline in line_index.newlines() { | 245 | for orig_step in LineIndexStepIter::from(line_index) { |
157 | loop { | 246 | loop { |
158 | let translated_newline = state.translate(orig_newline); | 247 | let translated_newline = state.translate_step(&orig_step); |
159 | match state.next_newlines(translated_newline) { | 248 | match state.next_step(&translated_newline) { |
160 | NextNewlines::Use => { | 249 | NextNewlines::Use => { |
161 | test_newline!(translated_newline); | 250 | test_step!(translated_newline); |
162 | break; | 251 | break; |
163 | } | 252 | } |
164 | NextNewlines::ReplaceMany(ns) => { | 253 | NextNewlines::ReplaceMany(ns) => { |
165 | for n in ns { | 254 | for n in ns { |
166 | test_newline!(n); | 255 | test_step!(n); |
167 | } | 256 | } |
168 | break; | 257 | break; |
169 | } | 258 | } |
170 | NextNewlines::AddMany(ns) => { | 259 | NextNewlines::AddMany(ns) => { |
171 | for n in ns { | 260 | for n in ns { |
172 | test_newline!(n); | 261 | test_step!(n); |
173 | } | 262 | } |
174 | } | 263 | } |
175 | } | 264 | } |
@@ -181,7 +270,7 @@ pub fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTex | |||
181 | None => break, | 270 | None => break, |
182 | Some(ns) => { | 271 | Some(ns) => { |
183 | for n in ns { | 272 | for n in ns { |
184 | test_newline!(n); | 273 | test_step!(n); |
185 | } | 274 | } |
186 | } | 275 | } |
187 | } | 276 | } |