on master help sign in
state.rs cleanup
9c55b3eBlaž Hrastnik
helix-core/src/state.rs+26−61
@@ -31,26 +31,6 @@ impl State {
31 }
31 }
32 }
32 }
33
33
34− // TODO: doc/selection accessors
35−
36− // TODO: be able to take either Rope or RopeSlice
37− // #[inline]
38− // pub fn doc(&self) -> &Rope {
39− // &self.doc
40− // }
41−
42− // #[inline]
43− // pub fn selection(&self) -> &Selection {
44− // &self.selection
45− // }
46−
47− // pub fn doc<R>(&self, range: R) -> RopeSlice
48− // where
49− // R: std::ops::RangeBounds<usize>,
50− // {
51− // self.doc.slice(range)
52− // }
53−
54 // update/transact:
34 // update/transact:
55 // update(desc) => transaction ? transaction.doc() for applied doc
35 // update(desc) => transaction ? transaction.doc() for applied doc
56 // transaction.apply(doc)
36 // transaction.apply(doc)
@@ -74,17 +54,6 @@ impl State {
74 // foldable
54 // foldable
75 // changeFilter/transactionFilter
55 // changeFilter/transactionFilter
76
56
77− // TODO: move that accepts a boundary matcher fn/list, we keep incrementing until we hit
78− // a boundary
79−
80− // TODO: edits, does each keypress trigger a full command? I guess it's adding to the same
81− // transaction
82− // There should be three pieces of the state: current transaction, the original doc, "preview"
83− // of the new state.
84− // 1. apply the newly generated keypress as a transaction
85− // 2. compose onto a ongoing transaction
86− // 3. on insert mode leave, that transaction gets stored into undo history
87−
88 pub fn move_range(
57 pub fn move_range(
89 &self,
58 &self,
90 range: Range,
59 range: Range,
@@ -93,47 +62,42 @@ impl State {
93 count: usize,
62 count: usize,
94 extend: bool,
63 extend: bool,
95 ) -> Range {
64 ) -> Range {
96− let text = &self.doc;
65+ let text = self.doc.slice(..);
97 let pos = range.head;
66 let pos = range.head;
67+ let line = text.char_to_line(pos);
68+ // TODO: we can optimize clamping by passing in RopeSlice limited to current line. that way
69+ // we stop calculating past start/end of line.
98− match (dir, granularity) {
70+ let pos = match (dir, granularity) {
99 (Direction::Backward, Granularity::Character) => {
71 (Direction::Backward, Granularity::Character) => {
100− // Clamp to line
101− let line = text.char_to_line(pos);
102 let start = text.line_to_char(line);
72 let start = text.line_to_char(line);
103− let pos = std::cmp::max(
104− nth_prev_grapheme_boundary(text.slice(..), pos, count),
73+ nth_prev_grapheme_boundary(text, pos, count).max(start)
105− start,
106− );
107− Range::new(if extend { range.anchor } else { pos }, pos)
108 }
74 }
109 (Direction::Forward, Granularity::Character) => {
75 (Direction::Forward, Granularity::Character) => {
110− // Clamp to line
111− let line = text.char_to_line(pos);
112 // Line end is pos at the start of next line - 1
76 // Line end is pos at the start of next line - 1
113 // subtract another 1 because the line ends with \n
77 // subtract another 1 because the line ends with \n
114 let end = text.line_to_char(line + 1).saturating_sub(2);
78 let end = text.line_to_char(line + 1).saturating_sub(2);
115− let pos =
116− std::cmp::min(nth_next_grapheme_boundary(text.slice(..), pos, count), end);
79+ nth_next_grapheme_boundary(text, pos, count).min(end)
117− Range::new(if extend { range.anchor } else { pos }, pos)
118 }
80 }
119− (_, Granularity::Line) => move_vertically(text.slice(..), dir, range, count, extend),
81+ (_, Granularity::Line) => return move_vertically(text, dir, range, count, extend),
120− }
82+ };
83+ Range::new(if extend { range.anchor } else { pos }, pos)
121 }
84 }
122
85
123 pub fn move_next_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
86 pub fn move_next_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
124− // TODO: confirm it's fine without using graphemes, I think it should be
125 for _ in 0..count {
87 for _ in 0..count {
88+ if pos + 1 == slice.len_chars() {
126− // TODO: if end return end
89+ return pos;
90+ }
127
91
128− let ch = slice.char(pos);
92+ let mut ch = slice.char(pos);
129− let next = slice.char(pos.saturating_add(1));
93+ let next = slice.char(pos + 1);
94+
95+ // if we're at the end of a word, or on whitespce right before new one
130 if categorize(ch) != categorize(next) {
96 if categorize(ch) != categorize(next) {
131 pos += 1;
97 pos += 1;
98+ ch = next;
132 }
99 }
133
100
134− // refetch
135− let ch = slice.char(pos);
136−
137 if is_word(ch) {
101 if is_word(ch) {
138 skip_over_next(slice, &mut pos, is_word);
102 skip_over_next(slice, &mut pos, is_word);
139 } else if ch.is_ascii_punctuation() {
103 } else if ch.is_ascii_punctuation() {
@@ -148,7 +112,6 @@ impl State {
148 }
112 }
149
113
150 pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
114 pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
151− // TODO: confirm it's fine without using graphemes, I think it should be
152 for _ in 0..count {
115 for _ in 0..count {
153 if pos == 0 {
116 if pos == 0 {
154 return pos;
117 return pos;
@@ -182,11 +145,13 @@ impl State {
182
145
183 pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
146 pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
184 for _ in 0..count {
147 for _ in 0..count {
148+ if pos + 1 == slice.len_chars() {
185− // TODO: if end return end
149+ return pos;
150+ }
186
151
187− // TODO: confirm it's fine without using graphemes, I think it should be
188 let ch = slice.char(pos);
152 let ch = slice.char(pos);
189− let next = slice.char(pos.saturating_add(1));
153+ let next = slice.char(pos + 1);
154+
190 if categorize(ch) != categorize(next) {
155 if categorize(ch) != categorize(next) {
191 pos += 1;
156 pos += 1;
192 }
157 }
@@ -202,7 +167,7 @@ impl State {
202 } else if ch.is_ascii_punctuation() {
167 } else if ch.is_ascii_punctuation() {
203 skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
168 skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
204 }
169 }
205− pos = pos.saturating_sub(1)
170+ pos -= 1
206 }
171 }
207
172
208 pos
173 pos
@@ -311,7 +276,7 @@ where
311 if !fun(ch) {
276 if !fun(ch) {
312 break;
277 break;
313 }
278 }
314− *pos += 1; // TODO: can go 1 over end of doc
279+ *pos += 1;
315 }
280 }
316}
281}
317
282
@@ -327,7 +292,7 @@ where
327 if !fun(ch) {
292 if !fun(ch) {
328 break;
293 break;
329 }
294 }
330− *pos -= pos.saturating_sub(1);
295+ *pos = pos.saturating_sub(1);
331 }
296 }
332}
297}
333
298