on master help sign in
Move things out of state.rs.
dbcc099Blaž Hrastnik
helix-core/src/lib.rs+2−1
@@ -5,6 +5,7 @@ pub mod graphemes;
5mod history;
5mod history;
6pub mod indent;
6pub mod indent;
7pub mod macros;
7pub mod macros;
8+pub mod movement;
8pub mod object;
9pub mod object;
9mod position;
10mod position;
10pub mod register;
11pub mod register;
@@ -48,7 +49,7 @@ pub use tendril::StrTendril as Tendril;
48#[doc(inline)]
49#[doc(inline)]
49pub use {regex, tree_sitter};
50pub use {regex, tree_sitter};
50
51
51−pub use position::Position;
52+pub use position::{coords_at_pos, pos_at_coords, Position};
52pub use selection::Range;
53pub use selection::Range;
53pub use selection::Selection;
54pub use selection::Selection;
54pub use syntax::Syntax;
55pub use syntax::Syntax;
helix-core/src/movement.rsnew file+157
@@ -0,0 +1,157 @@
1+use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary, RopeGraphemes};
2+use crate::{coords_at_pos, pos_at_coords, ChangeSet, Position, Range, Rope, RopeSlice, Selection};
3+
4+pub fn move_next_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
5+ for _ in 0..count {
6+ if pos + 1 == slice.len_chars() {
7+ return pos;
8+ }
9+
10+ let mut ch = slice.char(pos);
11+ let next = slice.char(pos + 1);
12+
13+ // if we're at the end of a word, or on whitespce right before new one
14+ if categorize(ch) != categorize(next) {
15+ pos += 1;
16+ ch = next;
17+ }
18+
19+ if is_word(ch) {
20+ skip_over_next(slice, &mut pos, is_word);
21+ } else if ch.is_ascii_punctuation() {
22+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
23+ }
24+
25+ // TODO: don't include newline?
26+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
27+ }
28+
29+ pos
30+}
31+
32+pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
33+ for _ in 0..count {
34+ if pos == 0 {
35+ return pos;
36+ }
37+
38+ let ch = slice.char(pos);
39+ let prev = slice.char(pos - 1);
40+
41+ if categorize(ch) != categorize(prev) {
42+ pos -= 1;
43+ }
44+
45+ // match (category c1, category c2) => {
46+ // if c1 != c2 {
47+ // }
48+ // }
49+
50+ // TODO: skip while eol
51+
52+ // TODO: don't include newline?
53+ skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_whitespace());
54+
55+ // refetch
56+ let ch = slice.char(pos);
57+
58+ if is_word(ch) {
59+ skip_over_prev(slice, &mut pos, is_word);
60+ } else if ch.is_ascii_punctuation() {
61+ skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_punctuation());
62+ }
63+ pos = pos.saturating_add(1)
64+ }
65+
66+ pos
67+}
68+
69+pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
70+ for _ in 0..count {
71+ if pos + 1 == slice.len_chars() {
72+ return pos;
73+ }
74+
75+ let ch = slice.char(pos);
76+ let next = slice.char(pos + 1);
77+
78+ if categorize(ch) != categorize(next) {
79+ pos += 1;
80+ }
81+
82+ // TODO: don't include newline?
83+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
84+
85+ // refetch
86+ let ch = slice.char(pos);
87+
88+ if is_word(ch) {
89+ skip_over_next(slice, &mut pos, is_word);
90+ } else if ch.is_ascii_punctuation() {
91+ skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
92+ }
93+ pos -= 1
94+ }
95+
96+ pos
97+}
98+
99+// ---- util ------------
100+
101+// used for by-word movement
102+
103+fn is_word(ch: char) -> bool {
104+ ch.is_alphanumeric() || ch == '_'
105+}
106+
107+#[derive(Debug, Eq, PartialEq)]
108+enum Category {
109+ Whitespace,
110+ Eol,
111+ Word,
112+ Punctuation,
113+}
114+fn categorize(ch: char) -> Category {
115+ if ch == '\n' {
116+ Category::Eol
117+ } else if ch.is_ascii_whitespace() {
118+ Category::Whitespace
119+ } else if ch.is_ascii_punctuation() {
120+ Category::Punctuation
121+ } else if ch.is_ascii_alphanumeric() {
122+ Category::Word
123+ } else {
124+ unreachable!()
125+ }
126+}
127+
128+#[inline]
129+pub fn skip_over_next<F>(slice: RopeSlice, pos: &mut usize, fun: F)
130+where
131+ F: Fn(char) -> bool,
132+{
133+ let mut chars = slice.chars_at(*pos);
134+
135+ for ch in chars {
136+ if !fun(ch) {
137+ break;
138+ }
139+ *pos += 1;
140+ }
141+}
142+
143+#[inline]
144+pub fn skip_over_prev<F>(slice: RopeSlice, pos: &mut usize, fun: F)
145+where
146+ F: Fn(char) -> bool,
147+{
148+ // need to +1 so that prev() includes current char
149+ let mut chars = slice.chars_at(*pos + 1);
150+
151+ while let Some(ch) = chars.prev() {
152+ if !fun(ch) {
153+ break;
154+ }
155+ *pos = pos.saturating_sub(1);
156+ }
157+}
helix-core/src/position.rs+74
@@ -1,3 +1,8 @@
1+use crate::{
2+ graphemes::{nth_next_grapheme_boundary, RopeGraphemes},
3+ Rope, RopeSlice,
4+};
5+
1/// Represents a single point in a text buffer. Zero indexed.
6/// Represents a single point in a text buffer. Zero indexed.
2#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
3pub struct Position {
8pub struct Position {
@@ -44,6 +49,21 @@ impl From<Position> for tree_sitter::Point {
44 Self::new(pos.row, pos.col)
49 Self::new(pos.row, pos.col)
45 }
50 }
46}
51}
52+/// Convert a character index to (line, column) coordinates.
53+pub fn coords_at_pos(text: RopeSlice, pos: usize) -> Position {
54+ let line = text.char_to_line(pos);
55+ let line_start = text.line_to_char(line);
56+ let col = RopeGraphemes::new(text.slice(line_start..pos)).count();
57+ Position::new(line, col)
58+}
59+
60+/// Convert (line, column) coordinates to a character index.
61+pub fn pos_at_coords(text: RopeSlice, coords: Position) -> usize {
62+ let Position { row, col } = coords;
63+ let line_start = text.line_to_char(row);
64+ // line_start + col
65+ nth_next_grapheme_boundary(text, line_start, col)
66+}
47
67
48#[cfg(test)]
68#[cfg(test)]
49mod test {
69mod test {
@@ -54,4 +74,58 @@ mod test {
54 // (0, 5) is less than (1, 0)
74 // (0, 5) is less than (1, 0)
55 assert!(Position::new(0, 5) < Position::new(1, 0));
75 assert!(Position::new(0, 5) < Position::new(1, 0));
56 }
76 }
77+
78+ #[test]
79+ fn test_coords_at_pos() {
80+ let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
81+ let slice = text.slice(..);
82+ // assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
83+ // assert_eq!(coords_at_pos(slice, 5), (0, 5).into()); // position on \n
84+ // assert_eq!(coords_at_pos(slice, 6), (1, 0).into()); // position on w
85+ // assert_eq!(coords_at_pos(slice, 7), (1, 1).into()); // position on o
86+ // assert_eq!(coords_at_pos(slice, 10), (1, 4).into()); // position on d
87+
88+ // test with grapheme clusters
89+ let text = Rope::from("a̐éö̲\r\n");
90+ let slice = text.slice(..);
91+ assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
92+ assert_eq!(coords_at_pos(slice, 2), (0, 1).into());
93+ assert_eq!(coords_at_pos(slice, 4), (0, 2).into());
94+ assert_eq!(coords_at_pos(slice, 7), (0, 3).into());
95+
96+ let text = Rope::from("किमपि");
97+ let slice = text.slice(..);
98+ assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
99+ assert_eq!(coords_at_pos(slice, 2), (0, 1).into());
100+ assert_eq!(coords_at_pos(slice, 3), (0, 2).into());
101+ assert_eq!(coords_at_pos(slice, 5), (0, 3).into());
102+ }
103+
104+ #[test]
105+ fn test_pos_at_coords() {
106+ let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
107+ let slice = text.slice(..);
108+ assert_eq!(pos_at_coords(slice, (0, 0).into()), 0);
109+ assert_eq!(pos_at_coords(slice, (0, 5).into()), 5); // position on \n
110+ assert_eq!(pos_at_coords(slice, (1, 0).into()), 6); // position on w
111+ assert_eq!(pos_at_coords(slice, (1, 1).into()), 7); // position on o
112+ assert_eq!(pos_at_coords(slice, (1, 4).into()), 10); // position on d
113+
114+ // test with grapheme clusters
115+ let text = Rope::from("a̐éö̲\r\n");
116+ let slice = text.slice(..);
117+ assert_eq!(pos_at_coords(slice, (0, 0).into()), 0);
118+ assert_eq!(pos_at_coords(slice, (0, 1).into()), 2);
119+ assert_eq!(pos_at_coords(slice, (0, 2).into()), 4);
120+ assert_eq!(pos_at_coords(slice, (0, 3).into()), 7); // \r\n is one char here
121+ assert_eq!(pos_at_coords(slice, (0, 4).into()), 9);
122+ let text = Rope::from("किमपि");
123+ // 2 - 1 - 2 codepoints
124+ // TODO: delete handling as per https://news.ycombinator.com/item?id=20058454
125+ let slice = text.slice(..);
126+ assert_eq!(pos_at_coords(slice, (0, 0).into()), 0);
127+ assert_eq!(pos_at_coords(slice, (0, 1).into()), 2);
128+ assert_eq!(pos_at_coords(slice, (0, 2).into()), 3);
129+ assert_eq!(pos_at_coords(slice, (0, 3).into()), 5); // eol
130+ }
57}
131}
helix-core/src/state.rs+1−221
@@ -1,7 +1,5 @@
1use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary, RopeGraphemes};
1use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary, RopeGraphemes};
2−use crate::syntax::LOADER;
3−use crate::{ChangeSet, Diagnostic, Position, Range, Rope, RopeSlice, Selection, Syntax};
2+use crate::{coords_at_pos, pos_at_coords, ChangeSet, Position, Range, Rope, RopeSlice, Selection};
4−use anyhow::Error;
5
3
6/// A state represents the current editor state of a single buffer.
4/// A state represents the current editor state of a single buffer.
7#[derive(Clone)]
5#[derive(Clone)]
@@ -83,96 +81,6 @@ impl State {
83 Range::new(if extend { range.anchor } else { pos }, pos)
81 Range::new(if extend { range.anchor } else { pos }, pos)
84 }
82 }
85
83
86− pub fn move_next_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
87− for _ in 0..count {
88− if pos + 1 == slice.len_chars() {
89− return pos;
90− }
91−
92− let mut ch = slice.char(pos);
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
96− if categorize(ch) != categorize(next) {
97− pos += 1;
98− ch = next;
99− }
100−
101− if is_word(ch) {
102− skip_over_next(slice, &mut pos, is_word);
103− } else if ch.is_ascii_punctuation() {
104− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
105− }
106−
107− // TODO: don't include newline?
108− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
109− }
110−
111− pos
112− }
113−
114− pub fn move_prev_word_start(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
115− for _ in 0..count {
116− if pos == 0 {
117− return pos;
118− }
119−
120− let ch = slice.char(pos);
121− let prev = slice.char(pos - 1);
122−
123− if categorize(ch) != categorize(prev) {
124− pos -= 1;
125− }
126−
127− // TODO: skip while eol
128−
129− // TODO: don't include newline?
130− skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_whitespace());
131−
132− // refetch
133− let ch = slice.char(pos);
134−
135− if is_word(ch) {
136− skip_over_prev(slice, &mut pos, is_word);
137− } else if ch.is_ascii_punctuation() {
138− skip_over_prev(slice, &mut pos, |ch| ch.is_ascii_punctuation());
139− }
140− pos = pos.saturating_add(1)
141− }
142−
143− pos
144− }
145−
146− pub fn move_next_word_end(slice: RopeSlice, mut pos: usize, count: usize) -> usize {
147− for _ in 0..count {
148− if pos + 1 == slice.len_chars() {
149− return pos;
150− }
151−
152− let ch = slice.char(pos);
153− let next = slice.char(pos + 1);
154−
155− if categorize(ch) != categorize(next) {
156− pos += 1;
157− }
158−
159− // TODO: don't include newline?
160− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_whitespace());
161−
162− // refetch
163− let ch = slice.char(pos);
164−
165− if is_word(ch) {
166− skip_over_next(slice, &mut pos, is_word);
167− } else if ch.is_ascii_punctuation() {
168− skip_over_next(slice, &mut pos, |ch| ch.is_ascii_punctuation());
169− }
170− pos -= 1
171− }
172−
173− pos
174− }
175−
176 pub fn move_selection(
84 pub fn move_selection(
177 &self,
85 &self,
178 dir: Direction,
86 dir: Direction,
@@ -194,22 +102,6 @@ impl State {
194 }
102 }
195}
103}
196
104
197−/// Convert a character index to (line, column) coordinates.
198−pub fn coords_at_pos(text: RopeSlice, pos: usize) -> Position {
199− let line = text.char_to_line(pos);
200− let line_start = text.line_to_char(line);
201− let col = RopeGraphemes::new(text.slice(line_start..pos)).count();
202− Position::new(line, col)
203−}
204−
205−/// Convert (line, column) coordinates to a character index.
206−pub fn pos_at_coords(text: RopeSlice, coords: Position) -> usize {
207− let Position { row, col } = coords;
208− let line_start = text.line_to_char(row);
209− // line_start + col
210− nth_next_grapheme_boundary(text, line_start, col)
211−}
212−
213fn move_vertically(
105fn move_vertically(
214 text: RopeSlice,
106 text: RopeSlice,
215 dir: Direction,
107 dir: Direction,
@@ -238,122 +130,10 @@ fn move_vertically(
238 range
130 range
239}
131}
240
132
241−// used for by-word movement
242−
243−fn is_word(ch: char) -> bool {
244− ch.is_alphanumeric() || ch == '_'
245−}
246−
247−#[derive(Debug, Eq, PartialEq)]
248−enum Category {
249− Whitespace,
250− Eol,
251− Word,
252− Punctuation,
253−}
254−fn categorize(ch: char) -> Category {
255− if ch == '\n' {
256− Category::Eol
257− } else if ch.is_ascii_whitespace() {
258− Category::Whitespace
259− } else if ch.is_ascii_punctuation() {
260− Category::Punctuation
261− } else if ch.is_ascii_alphanumeric() {
262− Category::Word
263− } else {
264− unreachable!()
265− }
266−}
267−
268−#[inline]
269−pub fn skip_over_next<F>(slice: RopeSlice, pos: &mut usize, fun: F)
270−where
271− F: Fn(char) -> bool,
272−{
273− let mut chars = slice.chars_at(*pos);
274−
275− for ch in chars {
276− if !fun(ch) {
277− break;
278− }
279− *pos += 1;
280− }
281−}
282−
283−#[inline]
284−pub fn skip_over_prev<F>(slice: RopeSlice, pos: &mut usize, fun: F)
285−where
286− F: Fn(char) -> bool,
287−{
288− // need to +1 so that prev() includes current char
289− let mut chars = slice.chars_at(*pos + 1);
290−
291− while let Some(ch) = chars.prev() {
292− if !fun(ch) {
293− break;
294− }
295− *pos = pos.saturating_sub(1);
296− }
297−}
298−
299#[cfg(test)]
133#[cfg(test)]
300mod test {
134mod test {
301 use super::*;
135 use super::*;
302
136
303− #[test]
304− fn test_coords_at_pos() {
305− let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
306− let slice = text.slice(..);
307− // assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
308− // assert_eq!(coords_at_pos(slice, 5), (0, 5).into()); // position on \n
309− // assert_eq!(coords_at_pos(slice, 6), (1, 0).into()); // position on w
310− // assert_eq!(coords_at_pos(slice, 7), (1, 1).into()); // position on o
311− // assert_eq!(coords_at_pos(slice, 10), (1, 4).into()); // position on d
312−
313− // test with grapheme clusters
314− let text = Rope::from("a̐éö̲\r\n");
315− let slice = text.slice(..);
316− assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
317− assert_eq!(coords_at_pos(slice, 2), (0, 1).into());
318− assert_eq!(coords_at_pos(slice, 4), (0, 2).into());
319− assert_eq!(coords_at_pos(slice, 7), (0, 3).into());
320−
321− let text = Rope::from("किमपि");
322− let slice = text.slice(..);
323− assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
324− assert_eq!(coords_at_pos(slice, 2), (0, 1).into());
325− assert_eq!(coords_at_pos(slice, 3), (0, 2).into());
326− assert_eq!(coords_at_pos(slice, 5), (0, 3).into());
327− }
328−
329− #[test]
330− fn test_pos_at_coords() {
331− let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
332− let slice = text.slice(..);
333− assert_eq!(pos_at_coords(slice, (0, 0).into()), 0);
334− assert_eq!(pos_at_coords(slice, (0, 5).into()), 5); // position on \n
335− assert_eq!(pos_at_coords(slice, (1, 0).into()), 6); // position on w
336− assert_eq!(pos_at_coords(slice, (1, 1).into()), 7); // position on o
337− assert_eq!(pos_at_coords(slice, (1, 4).into()), 10); // position on d
338−
339− // test with grapheme clusters
340− let text = Rope::from("a̐éö̲\r\n");
341− let slice = text.slice(..);
342− assert_eq!(pos_at_coords(slice, (0, 0).into()), 0);
343− assert_eq!(pos_at_coords(slice, (0, 1).into()), 2);
344− assert_eq!(pos_at_coords(slice, (0, 2).into()), 4);
345− assert_eq!(pos_at_coords(slice, (0, 3).into()), 7); // \r\n is one char here
346− assert_eq!(pos_at_coords(slice, (0, 4).into()), 9);
347− let text = Rope::from("किमपि");
348− // 2 - 1 - 2 codepoints
349− // TODO: delete handling as per https://news.ycombinator.com/item?id=20058454
350− let slice = text.slice(..);
351− assert_eq!(pos_at_coords(slice, (0, 0).into()), 0);
352− assert_eq!(pos_at_coords(slice, (0, 1).into()), 2);
353− assert_eq!(pos_at_coords(slice, (0, 2).into()), 3);
354− assert_eq!(pos_at_coords(slice, (0, 3).into()), 5); // eol
355− }
356−
357 #[test]
137 #[test]
358 fn test_vertical_move() {
138 fn test_vertical_move() {
359 let text = Rope::from("abcd\nefg\nwrs");
139 let text = Rope::from("abcd\nefg\nwrs");
helix-core/src/syntax.rs+1−1
@@ -355,7 +355,7 @@ pub struct LanguageLayer {
355 pub(crate) tree: Option<Tree>,
355 pub(crate) tree: Option<Tree>,
356}
356}
357
357
358−use crate::state::coords_at_pos;
358+use crate::coords_at_pos;
359use crate::transaction::{ChangeSet, Operation};
359use crate::transaction::{ChangeSet, Operation};
360use crate::Tendril;
360use crate::Tendril;
361
361
helix-term/src/commands.rs+10−10
@@ -1,10 +1,10 @@
1use helix_core::{
1use helix_core::{
2− comment, graphemes,
2+ comment, coords_at_pos, graphemes,
3 indent::TAB_WIDTH,
3 indent::TAB_WIDTH,
4− object,
4+ movement, object, pos_at_coords,
5 regex::{self, Regex},
5 regex::{self, Regex},
6 register, search, selection,
6 register, search, selection,
7− state::{coords_at_pos, pos_at_coords, Direction, Granularity, State},
7+ state::{Direction, Granularity, State},
8 Change, ChangeSet, Position, Range, RopeSlice, Selection, Tendril, Transaction,
8 Change, ChangeSet, Position, Range, RopeSlice, Selection, Tendril, Transaction,
9};
9};
10
10
@@ -152,7 +152,7 @@ pub fn move_next_word_start(cx: &mut Context) {
152 let text = doc.text().slice(..);
152 let text = doc.text().slice(..);
153
153
154 let selection = doc.selection().transform(|range| {
154 let selection = doc.selection().transform(|range| {
155− let pos = State::move_next_word_start(text, range.head, count);
155+ let pos = movement::move_next_word_start(text, range.head, count);
156 Range::new(pos, pos)
156 Range::new(pos, pos)
157 });
157 });
158
158
@@ -165,7 +165,7 @@ pub fn move_prev_word_start(cx: &mut Context) {
165 let text = doc.text().slice(..);
165 let text = doc.text().slice(..);
166
166
167 let selection = doc.selection().transform(|range| {
167 let selection = doc.selection().transform(|range| {
168− let pos = State::move_prev_word_start(text, range.head, count);
168+ let pos = movement::move_prev_word_start(text, range.head, count);
169 Range::new(pos, pos)
169 Range::new(pos, pos)
170 });
170 });
171
171
@@ -178,7 +178,7 @@ pub fn move_next_word_end(cx: &mut Context) {
178 let text = doc.text().slice(..);
178 let text = doc.text().slice(..);
179
179
180 let selection = doc.selection().transform(|range| {
180 let selection = doc.selection().transform(|range| {
181− let pos = State::move_next_word_end(text, range.head, count);
181+ let pos = movement::move_next_word_end(text, range.head, count);
182 Range::new(pos, pos)
182 Range::new(pos, pos)
183 });
183 });
184
184
@@ -207,7 +207,7 @@ pub fn extend_next_word_start(cx: &mut Context) {
207 let text = doc.text().slice(..);
207 let text = doc.text().slice(..);
208
208
209 let selection = doc.selection().transform(|mut range| {
209 let selection = doc.selection().transform(|mut range| {
210− let pos = State::move_next_word_start(text, range.head, count);
210+ let pos = movement::move_next_word_start(text, range.head, count);
211 Range::new(range.anchor, pos)
211 Range::new(range.anchor, pos)
212 });
212 });
213
213
@@ -220,7 +220,7 @@ pub fn extend_prev_word_start(cx: &mut Context) {
220 let text = doc.text().slice(..);
220 let text = doc.text().slice(..);
221
221
222 let selection = doc.selection().transform(|mut range| {
222 let selection = doc.selection().transform(|mut range| {
223− let pos = State::move_prev_word_start(text, range.head, count);
223+ let pos = movement::move_prev_word_start(text, range.head, count);
224 Range::new(range.anchor, pos)
224 Range::new(range.anchor, pos)
225 });
225 });
226 doc.set_selection(selection);
226 doc.set_selection(selection);
@@ -232,7 +232,7 @@ pub fn extend_next_word_end(cx: &mut Context) {
232 let text = doc.text().slice(..);
232 let text = doc.text().slice(..);
233
233
234 let selection = doc.selection().transform(|mut range| {
234 let selection = doc.selection().transform(|mut range| {
235− let pos = State::move_next_word_end(text, range.head, count);
235+ let pos = movement::move_next_word_end(text, range.head, count);
236 Range::new(range.anchor, pos)
236 Range::new(range.anchor, pos)
237 });
237 });
238
238
@@ -1199,7 +1199,7 @@ pub fn format_selections(cx: &mut Context) {
1199}
1199}
1200
1200
1201pub fn join_selections(cx: &mut Context) {
1201pub fn join_selections(cx: &mut Context) {
1202− use helix_core::state::skip_over_next;
1202+ use movement::skip_over_next;
1203 let doc = cx.doc();
1203 let doc = cx.doc();
1204 let text = doc.text();
1204 let text = doc.text();
1205 let slice = doc.text().slice(..);
1205 let slice = doc.text().slice(..);