aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorBernardo <[email protected]>2018-12-22 11:59:48 +0000
committerBernardo <[email protected]>2018-12-25 19:03:14 +0000
commit36f2b1f3b9c36ace65852d971f998a090cf9b5d5 (patch)
tree7844f2e759fe477f69b8ba449490a6e4fca58977 /crates
parent1c44ba0f04a0997617d517111d0a08245f0dacac (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.rs14
-rw-r--r--crates/ra_editor/src/line_index_utils.rs133
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)]
18struct Utf16Char { 18pub(crate) struct Utf16Char {
19 start: TextUnit, 19 pub(crate) start: TextUnit,
20 end: TextUnit, 20 pub(crate) end: TextUnit,
21} 21}
22 22
23impl Utf16Char { 23impl 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 @@
1use ra_text_edit::AtomTextEdit; 1use ra_text_edit::AtomTextEdit;
2use ra_syntax::{TextUnit, TextRange}; 2use ra_syntax::{TextUnit, TextRange};
3use crate::{LineIndex, LineCol}; 3use crate::{LineIndex, LineCol, line_index::Utf16Char};
4use superslice::Ext; 4use superslice::Ext;
5 5
6#[derive(Debug, Clone)]
7enum Step {
8 Newline(TextUnit),
9 Utf16Char(TextRange),
10}
11
12struct 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
19impl<'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
33impl<'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)]
7struct OffsetNewlineIter<'a> { 57struct OffsetNewlineIter<'a> {
8 text: &'a str, 58 text: &'a str,
@@ -10,16 +60,35 @@ struct OffsetNewlineIter<'a> {
10} 60}
11 61
12impl<'a> Iterator for OffsetNewlineIter<'a> { 62impl<'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
134pub fn count_newlines(offset: TextUnit, line_index: &LineIndex, edits: &[AtomTextEdit]) -> u32 { 218pub 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 }