on master help sign in
Collect some common patterns into methods on `Range`.
0883b4fNathan Vegdahl
helix-core/src/movement.rs+11−39
@@ -31,15 +31,7 @@ pub fn move_horizontally(
31 count: usize,
31 count: usize,
32 behaviour: Movement,
32 behaviour: Movement,
33) -> Range {
33) -> Range {
34− use Movement::Extend;
35−
36− // Shift back one grapheme if needed, to account for
37− // the cursor being visually 1-width.
38− let pos = if range.head > range.anchor {
34+ let pos = range.cursor(slice);
39− prev_grapheme_boundary(slice, range.head)
40− } else {
41− range.head
42− };
43
35
44 // Compute the new position.
36 // Compute the new position.
45 let new_pos = if dir == Direction::Backward {
37 let new_pos = if dir == Direction::Backward {
@@ -49,11 +41,7 @@ pub fn move_horizontally(
49 };
41 };
50
42
51 // Compute the final new range.
43 // Compute the final new range.
52− if behaviour == Extend {
53− range.move_head(slice, new_pos, true)
44+ range.put_cursor(slice, new_pos, behaviour == Movement::Extend)
54− } else {
55− Range::point(new_pos)
56− }
57}
45}
58
46
59pub fn move_vertically(
47pub fn move_vertically(
@@ -63,13 +51,7 @@ pub fn move_vertically(
63 count: usize,
51 count: usize,
64 behaviour: Movement,
52 behaviour: Movement,
65) -> Range {
53) -> Range {
66− // Shift back one grapheme if needed, to account for
67− // the cursor being visually 1-width.
68− let pos = if range.head > range.anchor {
54+ let pos = range.cursor(slice);
69− prev_grapheme_boundary(slice, range.head)
70− } else {
71− range.head
72− };
73
55
74 // Compute the current position's 2d coordinates.
56 // Compute the current position's 2d coordinates.
75 let Position { row, col } = coords_at_pos(slice, pos);
57 let Position { row, col } = coords_at_pos(slice, pos);
@@ -89,24 +71,14 @@ pub fn move_vertically(
89 )
71 )
90 };
72 };
91
73
92− // Compute the new range according to the type of movement.
74+ // Special-case to avoid moving to the end of the last non-empty line.
93− match behaviour {
94− Movement::Move => Range {
95− anchor: new_pos,
96− head: new_pos,
97− horiz: Some(horiz),
98− },
99−
100− Movement::Extend => {
101− if slice.line(new_row).len_chars() > 0 {
75+ if behaviour == Movement::Extend && slice.line(new_row).len_chars() == 0 {
102− let mut new_range = range.move_head(slice, new_pos, true);
76+ return range;
103− new_range.horiz = Some(horiz);
104− new_range
105− } else {
106− range
107− }
108− }
109 }
77 }
78+
79+ let mut new_range = range.put_cursor(slice, new_pos, behaviour == Movement::Extend);
80+ new_range.horiz = Some(horiz);
81+ new_range
110}
82}
111
83
112pub fn move_next_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
84pub fn move_next_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
@@ -153,7 +125,7 @@ fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTar
153 // Prepare the range appropriately based on the target movement
125 // Prepare the range appropriately based on the target movement
154 // direction. This is addressing two things at once:
126 // direction. This is addressing two things at once:
155 //
127 //
156− // 1. 1-width range sementics.
128+ // 1. Block-cursor semantics.
157 // 2. The anchor position being irrelevant to the output result.
129 // 2. The anchor position being irrelevant to the output result.
158 #[allow(clippy::collapsible_else_if)] // Makes the structure clearer in this case.
130 #[allow(clippy::collapsible_else_if)] // Makes the structure clearer in this case.
159 let start_range = if is_prev {
131 let start_range = if is_prev {
helix-core/src/selection.rs+35−45
@@ -73,16 +73,11 @@ impl Range {
73 std::cmp::max(self.anchor, self.head)
73 std::cmp::max(self.anchor, self.head)
74 }
74 }
75
75
76− /// The line number that the head is on (using 1-width semantics).
76+ /// The line number that the block-cursor is on.
77 #[inline]
77 #[inline]
78 #[must_use]
78 #[must_use]
79− pub fn head_line(&self, text: RopeSlice) -> usize {
79+ pub fn cursor_line(&self, text: RopeSlice) -> usize {
80− let head = if self.anchor < self.head {
81− prev_grapheme_boundary(text, self.head)
82− } else {
83− self.head
84− };
85− text.char_to_line(head)
80+ text.char_to_line(self.cursor(text))
86 }
81 }
87
82
88 /// The (inclusive) range of lines that the range overlaps.
83 /// The (inclusive) range of lines that the range overlaps.
@@ -248,29 +243,44 @@ impl Range {
248 }
243 }
249 }
244 }
250
245
251− /// Moves the head of the `Range` to `char_idx`, adjusting the anchor
246+ /// Gets the left-side position of the block cursor.
252− /// as needed to preserve 1-width range semantics.
247+ #[must_use]
248+ #[inline]
249+ pub fn cursor(self, text: RopeSlice) -> usize {
250+ if self.head > self.anchor {
251+ prev_grapheme_boundary(text, self.head)
252+ } else {
253+ self.head
254+ }
255+ }
256+
257+ /// Puts the left side of the block cursor at `char_idx`, optionally extending.
253 ///
258 ///
254− /// `block_cursor` specifies whether it should treat `char_idx` as a block
259+ /// This follows "1-width" semantics, and therefore does a combination of anchor
255− /// cursor position or as a range-end position.
260+ /// and head moves to behave as if both the front and back of the range are 1-width
261+ /// blocks
256 ///
262 ///
257 /// This method assumes that the range and `char_idx` are already properly
263 /// This method assumes that the range and `char_idx` are already properly
258 /// grapheme-aligned.
264 /// grapheme-aligned.
259 #[must_use]
265 #[must_use]
260 #[inline]
266 #[inline]
261− pub fn move_head(self, text: RopeSlice, char_idx: usize, block_cursor: bool) -> Range {
267+ pub fn put_cursor(self, text: RopeSlice, char_idx: usize, extend: bool) -> Range {
268+ if extend {
262− let anchor = if self.head >= self.anchor && char_idx < self.anchor {
269+ let anchor = if self.head >= self.anchor && char_idx < self.anchor {
263− next_grapheme_boundary(text, self.anchor)
270+ next_grapheme_boundary(text, self.anchor)
264− } else if self.head < self.anchor && char_idx >= self.anchor {
271+ } else if self.head < self.anchor && char_idx >= self.anchor {
265− prev_grapheme_boundary(text, self.anchor)
272+ prev_grapheme_boundary(text, self.anchor)
266− } else {
273+ } else {
267− self.anchor
274+ self.anchor
268− };
275+ };
269
276
270− if block_cursor && anchor <= char_idx {
277+ if anchor <= char_idx {
271− Range::new(anchor, next_grapheme_boundary(text, char_idx))
278+ Range::new(anchor, next_grapheme_boundary(text, char_idx))
279+ } else {
280+ Range::new(anchor, char_idx)
281+ }
272 } else {
282 } else {
273− Range::new(anchor, char_idx)
283+ Range::point(char_idx)
274 }
284 }
275 }
285 }
276
286
@@ -309,18 +319,6 @@ impl Selection {
309 self.ranges[self.primary_index]
319 self.ranges[self.primary_index]
310 }
320 }
311
321
312− #[must_use]
313− pub fn cursor(&self, text: RopeSlice) -> usize {
314− let range = self.primary();
315−
316− // For 1-width cursor semantics.
317− if range.anchor < range.head {
318− prev_grapheme_boundary(text, range.head).max(range.anchor)
319− } else {
320− range.head
321− }
322− }
323−
324 /// Ensure selection containing only the primary selection.
322 /// Ensure selection containing only the primary selection.
325 pub fn into_single(self) -> Self {
323 pub fn into_single(self) -> Self {
326 if self.ranges.len() == 1 {
324 if self.ranges.len() == 1 {
@@ -452,17 +450,9 @@ impl Selection {
452 }
450 }
453
451
454 /// Transforms the selection into all of the left-side head positions,
452 /// Transforms the selection into all of the left-side head positions,
455− /// using 1-width semantics.
453+ /// using block-cursor semantics.
456 pub fn cursors(self, text: RopeSlice) -> Self {
454 pub fn cursors(self, text: RopeSlice) -> Self {
457− self.transform(|range| {
455+ self.transform(|range| Range::point(range.cursor(text)))
458− // For 1-width cursor semantics.
459− let pos = if range.anchor < range.head {
460− prev_grapheme_boundary(text, range.head).max(range.anchor)
461− } else {
462− range.head
463− };
464− Range::new(pos, pos)
465− })
466 }
456 }
467
457
468 pub fn fragments<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = Cow<str>> + 'a {
458 pub fn fragments<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = Cow<str>> + 'a {
helix-core/src/textobject.rs+5−10
@@ -59,17 +59,12 @@ pub fn textobject_word(
59 textobject: TextObject,
59 textobject: TextObject,
60 _count: usize,
60 _count: usize,
61) -> Range {
61) -> Range {
62− // For 1-width cursor semantics.
62+ let pos = range.cursor(slice);
63− let head = if range.head > range.anchor {
64− prev_grapheme_boundary(slice, range.head)
65− } else {
66− range.head
67− };
68
63
69− let word_start = find_word_boundary(slice, head, Direction::Backward);
64+ let word_start = find_word_boundary(slice, pos, Direction::Backward);
70− let word_end = match slice.get_char(head).map(categorize_char) {
65+ let word_end = match slice.get_char(pos).map(categorize_char) {
71− None | Some(CharCategory::Whitespace | CharCategory::Eol) => head,
66+ None | Some(CharCategory::Whitespace | CharCategory::Eol) => pos,
72− _ => find_word_boundary(slice, head + 1, Direction::Forward),
67+ _ => find_word_boundary(slice, pos + 1, Direction::Forward),
73 };
68 };
74
69
75 // Special case.
70 // Special case.
helix-term/src/commands.rs+65−59
@@ -121,7 +121,10 @@ enum Align {
121}
121}
122
122
123fn align_view(doc: &Document, view: &mut View, align: Align) {
123fn align_view(doc: &Document, view: &mut View, align: Align) {
124+ let pos = doc
125+ .selection(view.id)
126+ .primary()
124− let pos = doc.selection(view.id).cursor(doc.text().slice(..));
127+ .cursor(doc.text().slice(..));
125 let line = doc.text().char_to_line(pos);
128 let line = doc.text().char_to_line(pos);
126
129
127 let relative = match align {
130 let relative = match align {
@@ -372,17 +375,13 @@ fn goto_line_end(cx: &mut Context) {
372 let text = doc.text().slice(..);
375 let text = doc.text().slice(..);
373
376
374 let selection = doc.selection(view.id).clone().transform(|range| {
377 let selection = doc.selection(view.id).clone().transform(|range| {
375− let line = range.head_line(text);
378+ let line = range.cursor_line(text);
376 let line_start = text.line_to_char(line);
379 let line_start = text.line_to_char(line);
377
380
378 let pos = graphemes::prev_grapheme_boundary(text, line_end_char_index(&text, line))
381 let pos = graphemes::prev_grapheme_boundary(text, line_end_char_index(&text, line))
379 .max(line_start);
382 .max(line_start);
380
383
381− if doc.mode == Mode::Select {
384+ range.put_cursor(text, pos, doc.mode == Mode::Select)
382− range.move_head(text, pos, true)
383− } else {
384− Range::point(pos)
385− }
386 });
385 });
387 doc.set_selection(view.id, selection);
386 doc.set_selection(view.id, selection);
388}
387}
@@ -392,14 +391,10 @@ fn goto_line_end_newline(cx: &mut Context) {
392 let text = doc.text().slice(..);
391 let text = doc.text().slice(..);
393
392
394 let selection = doc.selection(view.id).clone().transform(|range| {
393 let selection = doc.selection(view.id).clone().transform(|range| {
395− let line = range.head_line(text);
394+ let line = range.cursor_line(text);
396 let pos = line_end_char_index(&text, line);
395 let pos = line_end_char_index(&text, line);
397
396
398− if doc.mode == Mode::Select {
397+ range.put_cursor(text, pos, doc.mode == Mode::Select)
399− range.move_head(text, pos, true)
400− } else {
401− Range::point(pos)
402− }
403 });
398 });
404 doc.set_selection(view.id, selection);
399 doc.set_selection(view.id, selection);
405}
400}
@@ -409,15 +404,11 @@ fn goto_line_start(cx: &mut Context) {
409 let text = doc.text().slice(..);
404 let text = doc.text().slice(..);
410
405
411 let selection = doc.selection(view.id).clone().transform(|range| {
406 let selection = doc.selection(view.id).clone().transform(|range| {
412− let line = range.head_line(text);
407+ let line = range.cursor_line(text);
413
408
414 // adjust to start of the line
409 // adjust to start of the line
415 let pos = text.line_to_char(line);
410 let pos = text.line_to_char(line);
416− if doc.mode == Mode::Select {
411+ range.put_cursor(text, pos, doc.mode == Mode::Select)
417− range.move_head(text, pos, true)
418− } else {
419− Range::point(pos)
420− }
421 });
412 });
422 doc.set_selection(view.id, selection);
413 doc.set_selection(view.id, selection);
423}
414}
@@ -427,15 +418,11 @@ fn goto_first_nonwhitespace(cx: &mut Context) {
427 let text = doc.text().slice(..);
418 let text = doc.text().slice(..);
428
419
429 let selection = doc.selection(view.id).clone().transform(|range| {
420 let selection = doc.selection(view.id).clone().transform(|range| {
430− let line = range.head_line(text);
421+ let line = range.cursor_line(text);
431
422
432 if let Some(pos) = find_first_non_whitespace_char(text.line(line)) {
423 if let Some(pos) = find_first_non_whitespace_char(text.line(line)) {
433 let pos = pos + text.line_to_char(line);
424 let pos = pos + text.line_to_char(line);
434− if doc.mode == Mode::Select {
425+ range.put_cursor(text, pos, doc.mode == Mode::Select)
435− range.move_head(text, pos, true)
436− } else {
437− Range::point(pos)
438− }
439 } else {
426 } else {
440 range
427 range
441 }
428 }
@@ -579,8 +566,8 @@ fn extend_next_word_start(cx: &mut Context) {
579 .min_width_1(text)
566 .min_width_1(text)
580 .transform(|range| {
567 .transform(|range| {
581 let word = movement::move_next_word_start(text, range, count);
568 let word = movement::move_next_word_start(text, range, count);
582− let pos = graphemes::prev_grapheme_boundary(text, word.head);
569+ let pos = word.cursor(text);
583− range.move_head(text, pos, true)
570+ range.put_cursor(text, pos, true)
584 });
571 });
585 doc.set_selection(view.id, selection);
572 doc.set_selection(view.id, selection);
586}
573}
@@ -596,8 +583,8 @@ fn extend_prev_word_start(cx: &mut Context) {
596 .min_width_1(text)
583 .min_width_1(text)
597 .transform(|range| {
584 .transform(|range| {
598 let word = movement::move_prev_word_start(text, range, count);
585 let word = movement::move_prev_word_start(text, range, count);
599− let pos = word.head;
586+ let pos = word.cursor(text);
600− range.move_head(text, pos, true)
587+ range.put_cursor(text, pos, true)
601 });
588 });
602 doc.set_selection(view.id, selection);
589 doc.set_selection(view.id, selection);
603}
590}
@@ -613,8 +600,8 @@ fn extend_next_word_end(cx: &mut Context) {
613 .min_width_1(text)
600 .min_width_1(text)
614 .transform(|range| {
601 .transform(|range| {
615 let word = movement::move_next_word_end(text, range, count);
602 let word = movement::move_next_word_end(text, range, count);
616− let pos = graphemes::prev_grapheme_boundary(text, word.head);
603+ let pos = word.cursor(text);
617− range.move_head(text, pos, true)
604+ range.put_cursor(text, pos, true)
618 });
605 });
619 doc.set_selection(view.id, selection);
606 doc.set_selection(view.id, selection);
620}
607}
@@ -663,18 +650,13 @@ where
663
650
664 let selection = doc.selection(view.id).clone().transform(|range| {
651 let selection = doc.selection(view.id).clone().transform(|range| {
665 let range = if range.anchor < range.head {
652 let range = if range.anchor < range.head {
666− // For 1-width cursor semantics.
653+ // For block-cursor semantics.
667 Range::new(range.anchor, range.head - 1)
654 Range::new(range.anchor, range.head - 1)
668 } else {
655 } else {
669 range
656 range
670 };
657 };
671− search_fn(text, ch, range.head, count, inclusive).map_or(range, |pos| {
658+ search_fn(text, ch, range.head, count, inclusive)
672− if extend {
659+ .map_or(range, |pos| range.put_cursor(text, pos, extend))
673− range.move_head(text, pos, true)
674− } else {
675− Range::point(pos)
676− }
677− })
678 });
660 });
679 doc.set_selection(view.id, selection);
661 doc.set_selection(view.id, selection);
680 })
662 })
@@ -895,7 +877,9 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
895 let (view, doc) = current!(cx.editor);
877 let (view, doc) = current!(cx.editor);
896 let cursor = coords_at_pos(
878 let cursor = coords_at_pos(
897 doc.text().slice(..),
879 doc.text().slice(..),
898− doc.selection(view.id).cursor(doc.text().slice(..)),
880+ doc.selection(view.id)
881+ .primary()
882+ .cursor(doc.text().slice(..)),
899 );
883 );
900 let doc_last_line = doc.text().len_lines() - 1;
884 let doc_last_line = doc.text().len_lines() - 1;
901
885
@@ -1220,12 +1204,7 @@ fn collapse_selection(cx: &mut Context) {
1220 let text = doc.text().slice(..);
1204 let text = doc.text().slice(..);
1221
1205
1222 let selection = doc.selection(view.id).clone().transform(|range| {
1206 let selection = doc.selection(view.id).clone().transform(|range| {
1223− let pos = if range.head > range.anchor {
1207+ let pos = range.cursor(text);
1224− // For 1-width cursor semantics.
1225− graphemes::prev_grapheme_boundary(text, range.head)
1226− } else {
1227− range.head
1228− };
1229 Range::new(pos, pos)
1208 Range::new(pos, pos)
1230 });
1209 });
1231 doc.set_selection(view.id, selection);
1210 doc.set_selection(view.id, selection);
@@ -2203,7 +2182,7 @@ fn append_to_line(cx: &mut Context) {
2203
2182
2204 let selection = doc.selection(view.id).clone().transform(|range| {
2183 let selection = doc.selection(view.id).clone().transform(|range| {
2205 let text = doc.text().slice(..);
2184 let text = doc.text().slice(..);
2206− let line = range.head_line(text);
2185+ let line = range.cursor_line(text);
2207 let pos = line_end_char_index(&text, line);
2186 let pos = line_end_char_index(&text, line);
2208 Range::new(pos, pos)
2187 Range::new(pos, pos)
2209 });
2188 });
@@ -2264,7 +2243,7 @@ fn open(cx: &mut Context, open: Open) {
2264 let mut offs = 0;
2243 let mut offs = 0;
2265
2244
2266 let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
2245 let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
2267− let line = range.head_line(text);
2246+ let line = range.cursor_line(text);
2268
2247
2269 let line = match open {
2248 let line = match open {
2270 // adjust position to the end of the line (next line - 1)
2249 // adjust position to the end of the line (next line - 1)
@@ -2472,7 +2451,9 @@ fn goto_definition(cx: &mut Context) {
2472
2451
2473 let pos = pos_to_lsp_pos(
2452 let pos = pos_to_lsp_pos(
2474 doc.text(),
2453 doc.text(),
2475− doc.selection(view.id).cursor(doc.text().slice(..)),
2454+ doc.selection(view.id)
2455+ .primary()
2456+ .cursor(doc.text().slice(..)),
2476 offset_encoding,
2457 offset_encoding,
2477 );
2458 );
2478
2459
@@ -2513,7 +2494,9 @@ fn goto_type_definition(cx: &mut Context) {
2513
2494
2514 let pos = pos_to_lsp_pos(
2495 let pos = pos_to_lsp_pos(
2515 doc.text(),
2496 doc.text(),
2516− doc.selection(view.id).cursor(doc.text().slice(..)),
2497+ doc.selection(view.id)
2498+ .primary()
2499+ .cursor(doc.text().slice(..)),
2517 offset_encoding,
2500 offset_encoding,
2518 );
2501 );
2519
2502
@@ -2554,7 +2537,9 @@ fn goto_implementation(cx: &mut Context) {
2554
2537
2555 let pos = pos_to_lsp_pos(
2538 let pos = pos_to_lsp_pos(
2556 doc.text(),
2539 doc.text(),
2557− doc.selection(view.id).cursor(doc.text().slice(..)),
2540+ doc.selection(view.id)
2541+ .primary()
2542+ .cursor(doc.text().slice(..)),
2558 offset_encoding,
2543 offset_encoding,
2559 );
2544 );
2560
2545
@@ -2595,7 +2580,9 @@ fn goto_reference(cx: &mut Context) {
2595
2580
2596 let pos = pos_to_lsp_pos(
2581 let pos = pos_to_lsp_pos(
2597 doc.text(),
2582 doc.text(),
2598− doc.selection(view.id).cursor(doc.text().slice(..)),
2583+ doc.selection(view.id)
2584+ .primary()
2585+ .cursor(doc.text().slice(..)),
2599 offset_encoding,
2586 offset_encoding,
2600 );
2587 );
2601
2588
@@ -2656,7 +2643,10 @@ fn goto_next_diag(cx: &mut Context) {
2656 let editor = &mut cx.editor;
2643 let editor = &mut cx.editor;
2657 let (view, doc) = current!(editor);
2644 let (view, doc) = current!(editor);
2658
2645
2646+ let cursor_pos = doc
2647+ .selection(view.id)
2648+ .primary()
2659− let cursor_pos = doc.selection(view.id).cursor(doc.text().slice(..));
2649+ .cursor(doc.text().slice(..));
2660 let diag = if let Some(diag) = doc
2650 let diag = if let Some(diag) = doc
2661 .diagnostics()
2651 .diagnostics()
2662 .iter()
2652 .iter()
@@ -2677,7 +2667,10 @@ fn goto_prev_diag(cx: &mut Context) {
2677 let editor = &mut cx.editor;
2667 let editor = &mut cx.editor;
2678 let (view, doc) = current!(editor);
2668 let (view, doc) = current!(editor);
2679
2669
2670+ let cursor_pos = doc
2671+ .selection(view.id)
2672+ .primary()
2680− let cursor_pos = doc.selection(view.id).cursor(doc.text().slice(..));
2673+ .cursor(doc.text().slice(..));
2681 let diag = if let Some(diag) = doc
2674 let diag = if let Some(diag) = doc
2682 .diagnostics()
2675 .diagnostics()
2683 .iter()
2676 .iter()
@@ -2705,7 +2698,9 @@ fn signature_help(cx: &mut Context) {
2705
2698
2706 let pos = pos_to_lsp_pos(
2699 let pos = pos_to_lsp_pos(
2707 doc.text(),
2700 doc.text(),
2708− doc.selection(view.id).cursor(doc.text().slice(..)),
2701+ doc.selection(view.id)
2702+ .primary()
2703+ .cursor(doc.text().slice(..)),
2709 language_server.offset_encoding(),
2704 language_server.offset_encoding(),
2710 );
2705 );
2711
2706
@@ -3457,7 +3452,10 @@ fn completion(cx: &mut Context) {
3457 };
3452 };
3458
3453
3459 let offset_encoding = language_server.offset_encoding();
3454 let offset_encoding = language_server.offset_encoding();
3455+ let cursor = doc
3456+ .selection(view.id)
3457+ .primary()
3460− let cursor = doc.selection(view.id).cursor(doc.text().slice(..));
3458+ .cursor(doc.text().slice(..));
3461
3459
3462 let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding);
3460 let pos = pos_to_lsp_pos(doc.text(), cursor, offset_encoding);
3463
3461
@@ -3514,7 +3512,9 @@ fn hover(cx: &mut Context) {
3514
3512
3515 let pos = pos_to_lsp_pos(
3513 let pos = pos_to_lsp_pos(
3516 doc.text(),
3514 doc.text(),
3517− doc.selection(view.id).cursor(doc.text().slice(..)),
3515+ doc.selection(view.id)
3516+ .primary()
3517+ .cursor(doc.text().slice(..)),
3518 language_server.offset_encoding(),
3518 language_server.offset_encoding(),
3519 );
3519 );
3520
3520
@@ -3580,7 +3580,10 @@ fn match_brackets(cx: &mut Context) {
3580 let (view, doc) = current!(cx.editor);
3580 let (view, doc) = current!(cx.editor);
3581
3581
3582 if let Some(syntax) = doc.syntax() {
3582 if let Some(syntax) = doc.syntax() {
3583+ let pos = doc
3584+ .selection(view.id)
3585+ .primary()
3583− let pos = doc.selection(view.id).cursor(doc.text().slice(..));
3586+ .cursor(doc.text().slice(..));
3584 if let Some(pos) = match_brackets::find(syntax, doc.text(), pos) {
3587 if let Some(pos) = match_brackets::find(syntax, doc.text(), pos) {
3585 let selection = Selection::point(pos);
3588 let selection = Selection::point(pos);
3586 doc.set_selection(view.id, selection);
3589 doc.set_selection(view.id, selection);
@@ -3684,7 +3687,10 @@ fn align_view_bottom(cx: &mut Context) {
3684
3687
3685fn align_view_middle(cx: &mut Context) {
3688fn align_view_middle(cx: &mut Context) {
3686 let (view, doc) = current!(cx.editor);
3689 let (view, doc) = current!(cx.editor);
3690+ let pos = doc
3691+ .selection(view.id)
3692+ .primary()
3687− let pos = doc.selection(view.id).cursor(doc.text().slice(..));
3693+ .cursor(doc.text().slice(..));
3688 let pos = coords_at_pos(doc.text().slice(..), pos);
3694 let pos = coords_at_pos(doc.text().slice(..), pos);
3689
3695
3690 const OFFSET: usize = 7; // gutters
3696 const OFFSET: usize = 7; // gutters
helix-term/src/ui/completion.rs+16−4
@@ -86,7 +86,10 @@ impl Completion {
86 let item = item.unwrap();
86 let item = item.unwrap();
87
87
88 // if more text was entered, remove it
88 // if more text was entered, remove it
89+ let cursor = doc
90+ .selection(view.id)
91+ .primary()
89− let cursor = doc.selection(view.id).cursor(doc.text().slice(..));
92+ .cursor(doc.text().slice(..));
90 if trigger_offset < cursor {
93 if trigger_offset < cursor {
91 let remove = Transaction::change(
94 let remove = Transaction::change(
92 doc.text(),
95 doc.text(),
@@ -109,7 +112,10 @@ impl Completion {
109 )
112 )
110 } else {
113 } else {
111 let text = item.insert_text.as_ref().unwrap_or(&item.label);
114 let text = item.insert_text.as_ref().unwrap_or(&item.label);
115+ let cursor = doc
116+ .selection(view.id)
117+ .primary()
112− let cursor = doc.selection(view.id).cursor(doc.text().slice(..));
118+ .cursor(doc.text().slice(..));
113 Transaction::change(
119 Transaction::change(
114 doc.text(),
120 doc.text(),
115 vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
121 vec![(cursor, cursor, Some(text.as_str().into()))].into_iter(),
@@ -155,7 +161,10 @@ impl Completion {
155 // TODO: hooks should get processed immediately so maybe do it after select!(), before
161 // TODO: hooks should get processed immediately so maybe do it after select!(), before
156 // looping?
162 // looping?
157
163
164+ let cursor = doc
165+ .selection(view.id)
166+ .primary()
158− let cursor = doc.selection(view.id).cursor(doc.text().slice(..));
167+ .cursor(doc.text().slice(..));
159 if self.trigger_offset <= cursor {
168 if self.trigger_offset <= cursor {
160 let fragment = doc.text().slice(self.trigger_offset..cursor);
169 let fragment = doc.text().slice(self.trigger_offset..cursor);
161 let text = Cow::from(fragment);
170 let text = Cow::from(fragment);
@@ -212,7 +221,10 @@ impl Component for Completion {
212 .language()
221 .language()
213 .and_then(|scope| scope.strip_prefix("source."))
222 .and_then(|scope| scope.strip_prefix("source."))
214 .unwrap_or("");
223 .unwrap_or("");
224+ let cursor_pos = doc
225+ .selection(view.id)
226+ .primary()
215− let cursor_pos = doc.selection(view.id).cursor(doc.text().slice(..));
227+ .cursor(doc.text().slice(..));
216 let cursor_pos = (helix_core::coords_at_pos(doc.text().slice(..), cursor_pos).row
228 let cursor_pos = (helix_core::coords_at_pos(doc.text().slice(..), cursor_pos).row
217 - view.first_line) as u16;
229 - view.first_line) as u16;
218
230
helix-term/src/ui/editor.rs+11−3
@@ -406,7 +406,10 @@ impl EditorView {
406 // TODO: set cursor position for IME
406 // TODO: set cursor position for IME
407 if let Some(syntax) = doc.syntax() {
407 if let Some(syntax) = doc.syntax() {
408 use helix_core::match_brackets;
408 use helix_core::match_brackets;
409+ let pos = doc
410+ .selection(view.id)
411+ .primary()
409− let pos = doc.selection(view.id).cursor(doc.text().slice(..));
412+ .cursor(doc.text().slice(..));
410 let pos = match_brackets::find(syntax, doc.text(), pos)
413 let pos = match_brackets::find(syntax, doc.text(), pos)
411 .and_then(|pos| view.screen_coords_at_pos(doc, text, pos));
414 .and_then(|pos| view.screen_coords_at_pos(doc, text, pos));
412
415
@@ -451,7 +454,10 @@ impl EditorView {
451 widgets::{Paragraph, Widget},
454 widgets::{Paragraph, Widget},
452 };
455 };
453
456
457+ let cursor = doc
458+ .selection(view.id)
459+ .primary()
454− let cursor = doc.selection(view.id).cursor(doc.text().slice(..));
460+ .cursor(doc.text().slice(..));
455
461
456 let diagnostics = doc.diagnostics().iter().filter(|diagnostic| {
462 let diagnostics = doc.diagnostics().iter().filter(|diagnostic| {
457 diagnostic.range.start <= cursor && diagnostic.range.end >= cursor
463 diagnostic.range.start <= cursor && diagnostic.range.end >= cursor
@@ -565,7 +571,9 @@ impl EditorView {
565 let position_info = {
571 let position_info = {
566 let pos = coords_at_pos(
572 let pos = coords_at_pos(
567 doc.text().slice(..),
573 doc.text().slice(..),
568− doc.selection(view.id).cursor(doc.text().slice(..)),
574+ doc.selection(view.id)
575+ .primary()
576+ .cursor(doc.text().slice(..)),
569 );
577 );
570 format!("{}:{}", pos.row + 1, pos.col + 1) // convert to 1-indexing
578 format!("{}:{}", pos.row + 1, pos.col + 1) // convert to 1-indexing
571 };
579 };
helix-view/src/editor.rs+8−2
@@ -145,7 +145,10 @@ impl Editor {
145 .entry(view.id)
145 .entry(view.id)
146 .or_insert_with(|| Selection::point(0));
146 .or_insert_with(|| Selection::point(0));
147 // TODO: reuse align_view
147 // TODO: reuse align_view
148+ let pos = doc
149+ .selection(view.id)
150+ .primary()
148− let pos = doc.selection(view.id).cursor(doc.text().slice(..));
151+ .cursor(doc.text().slice(..));
149 let line = doc.text().char_to_line(pos);
152 let line = doc.text().char_to_line(pos);
150 view.first_line = line.saturating_sub(view.area.height as usize / 2);
153 view.first_line = line.saturating_sub(view.area.height as usize / 2);
151
154
@@ -295,7 +298,10 @@ impl Editor {
295 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
298 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
296 let view = view!(self);
299 let view = view!(self);
297 let doc = &self.documents[view.doc];
300 let doc = &self.documents[view.doc];
301+ let cursor = doc
302+ .selection(view.id)
303+ .primary()
298− let cursor = doc.selection(view.id).cursor(doc.text().slice(..));
304+ .cursor(doc.text().slice(..));
299 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
305 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
300 pos.col += view.area.x as usize + OFFSET as usize;
306 pos.col += view.area.x as usize + OFFSET as usize;
301 pos.row += view.area.y as usize;
307 pos.row += view.area.y as usize;
helix-view/src/view.rs+4−1
@@ -84,7 +84,10 @@ impl View {
84 }
84 }
85
85
86 pub fn ensure_cursor_in_view(&mut self, doc: &Document) {
86 pub fn ensure_cursor_in_view(&mut self, doc: &Document) {
87+ let cursor = doc
88+ .selection(self.id)
89+ .primary()
87− let cursor = doc.selection(self.id).cursor(doc.text().slice(..));
90+ .cursor(doc.text().slice(..));
88 let pos = coords_at_pos(doc.text().slice(..), cursor);
91 let pos = coords_at_pos(doc.text().slice(..), cursor);
89 let line = pos.row;
92 let line = pos.row;
90 let col = pos.col;
93 let col = pos.col;