@@ -373,15 +373,16 @@ fn goto_line_end(cx: &mut Context) {
373373
374374 let selection = doc.selection(view.id).clone().transform(|range| {
375375 let line = range.head_line(text);
376+ let line_start = text.line_to_char(line);
376377
377− let mut pos = line_end_char_index(&text, line);
378− if doc.mode != Mode::Select {
379− pos = graphemes::prev_grapheme_boundary(text, pos);
380− }
381−
382− pos = range.head.max(pos).max(text.line_to_char(line));
378+ let pos = graphemes::prev_grapheme_boundary(text, line_end_char_index(&text, line))
379+ .max(line_start);
383380
384− range.put(text, pos, doc.mode == Mode::Select)
381+ if doc.mode == Mode::Select {
382+ range.move_head(text, pos, true)
383+ } else {
384+ Range::point(pos)
385+ }
385386 });
386387 doc.set_selection(view.id, selection);
387388}
@@ -392,12 +393,13 @@ fn goto_line_end_newline(cx: &mut Context) {
392393
393394 let selection = doc.selection(view.id).clone().transform(|range| {
394395 let line = range.head_line(text);
396+ let pos = line_end_char_index(&text, line);
395397
396− let mut pos = text.line_to_char((line + 1).min(text.len_lines()));
397− if doc.mode != Mode::Select {
398− pos = graphemes::prev_grapheme_boundary(text, pos);
398+ if doc.mode == Mode::Select {
399+ range.move_head(text, pos, true)
400+ } else {
401+ Range::point(pos)
399402 }
400− range.put(text, pos, doc.mode == Mode::Select)
401403 });
402404 doc.set_selection(view.id, selection);
403405}
@@ -411,7 +413,11 @@ fn goto_line_start(cx: &mut Context) {
411413
412414 // adjust to start of the line
413415 let pos = text.line_to_char(line);
414− range.put(text, pos, doc.mode == Mode::Select)
416+ if doc.mode == Mode::Select {
417+ range.move_head(text, pos, true)
418+ } else {
419+ Range::point(pos)
420+ }
415421 });
416422 doc.set_selection(view.id, selection);
417423}
@@ -425,7 +431,11 @@ fn goto_first_nonwhitespace(cx: &mut Context) {
425431
426432 if let Some(pos) = find_first_non_whitespace_char(text.line(line)) {
427433 let pos = pos + text.line_to_char(line);
428− range.put(text, pos, doc.mode == Mode::Select)
434+ if doc.mode == Mode::Select {
435+ range.move_head(text, pos, true)
436+ } else {
437+ Range::point(pos)
438+ }
429439 } else {
430440 range
431441 }
@@ -569,8 +579,8 @@ fn extend_next_word_start(cx: &mut Context) {
569579 .min_width_1(text)
570580 .transform(|range| {
571581 let word = movement::move_next_word_start(text, range, count);
572− let pos = word.head;
573− range.put(text, pos, true)
582+ let pos = graphemes::prev_grapheme_boundary(text, word.head);
583+ range.move_head(text, pos, true)
574584 });
575585 doc.set_selection(view.id, selection);
576586}
@@ -587,7 +597,7 @@ fn extend_prev_word_start(cx: &mut Context) {
587597 .transform(|range| {
588598 let word = movement::move_prev_word_start(text, range, count);
589599 let pos = word.head;
590− range.put(text, pos, true)
600+ range.move_head(text, pos, true)
591601 });
592602 doc.set_selection(view.id, selection);
593603}
@@ -603,8 +613,8 @@ fn extend_next_word_end(cx: &mut Context) {
603613 .min_width_1(text)
604614 .transform(|range| {
605615 let word = movement::move_next_word_end(text, range, count);
606− let pos = word.head;
607− range.put(text, pos, true)
616+ let pos = graphemes::prev_grapheme_boundary(text, word.head);
617+ range.move_head(text, pos, true)
608618 });
609619 doc.set_selection(view.id, selection);
610620}
@@ -652,11 +662,17 @@ where
652662 let text = doc.text().slice(..);
653663
654664 let selection = doc.selection(view.id).clone().transform(|range| {
665+ let range = if range.anchor < range.head {
666+ // For 1-width cursor semantics.
667+ Range::new(range.anchor, range.head - 1)
668+ } else {
669+ range
670+ };
655671 search_fn(text, ch, range.head, count, inclusive).map_or(range, |pos| {
656672 if extend {
657− range.put(text, pos, true)
673+ range.move_head(text, pos, true)
658674 } else {
659− range.put(text, pos.saturating_sub(1), false)
675+ Range::point(pos)
660676 }
661677 })
662678 });
@@ -664,10 +680,39 @@ where
664680 })
665681}
666682
683+fn find_next_char_impl(
684+ text: RopeSlice,
685+ ch: char,
686+ pos: usize,
687+ n: usize,
688+ inclusive: bool,
689+) -> Option<usize> {
690+ let pos = (pos + 1).min(text.len_chars());
691+ if inclusive {
692+ search::find_nth_next(text, ch, pos, n)
693+ } else {
694+ search::find_nth_next(text, ch, pos, n).map(|n| n.saturating_sub(1))
695+ }
696+}
697+
698+fn find_prev_char_impl(
699+ text: RopeSlice,
700+ ch: char,
701+ pos: usize,
702+ n: usize,
703+ inclusive: bool,
704+) -> Option<usize> {
705+ if inclusive {
706+ search::find_nth_prev(text, ch, pos, n)
707+ } else {
708+ search::find_nth_prev(text, ch, pos, n).map(|n| (n + 1).min(text.len_chars()))
709+ }
710+}
711+
667712fn find_till_char(cx: &mut Context) {
668713 find_char_impl(
669714 cx,
670− search::find_nth_next,
715+ find_next_char_impl,
671716 false, /* inclusive */
672717 false, /* extend */
673718 )
@@ -676,7 +721,7 @@ fn find_till_char(cx: &mut Context) {
676721fn find_next_char(cx: &mut Context) {
677722 find_char_impl(
678723 cx,
679− search::find_nth_next,
724+ find_next_char_impl,
680725 true, /* inclusive */
681726 false, /* extend */
682727 )
@@ -685,7 +730,7 @@ fn find_next_char(cx: &mut Context) {
685730fn extend_till_char(cx: &mut Context) {
686731 find_char_impl(
687732 cx,
688− search::find_nth_next,
733+ find_next_char_impl,
689734 false, /* inclusive */
690735 true, /* extend */
691736 )
@@ -694,7 +739,7 @@ fn extend_till_char(cx: &mut Context) {
694739fn extend_next_char(cx: &mut Context) {
695740 find_char_impl(
696741 cx,
697− search::find_nth_next,
742+ find_next_char_impl,
698743 true, /* inclusive */
699744 true, /* extend */
700745 )
@@ -703,7 +748,7 @@ fn extend_next_char(cx: &mut Context) {
703748fn till_prev_char(cx: &mut Context) {
704749 find_char_impl(
705750 cx,
706− search::find_nth_prev,
751+ find_prev_char_impl,
707752 false, /* inclusive */
708753 false, /* extend */
709754 )
@@ -712,7 +757,7 @@ fn till_prev_char(cx: &mut Context) {
712757fn find_prev_char(cx: &mut Context) {
713758 find_char_impl(
714759 cx,
715− search::find_nth_prev,
760+ find_prev_char_impl,
716761 true, /* inclusive */
717762 false, /* extend */
718763 )
@@ -721,7 +766,7 @@ fn find_prev_char(cx: &mut Context) {
721766fn extend_till_prev_char(cx: &mut Context) {
722767 find_char_impl(
723768 cx,
724− search::find_nth_prev,
769+ find_prev_char_impl,
725770 false, /* inclusive */
726771 true, /* extend */
727772 )
@@ -730,7 +775,7 @@ fn extend_till_prev_char(cx: &mut Context) {
730775fn extend_prev_char(cx: &mut Context) {
731776 find_char_impl(
732777 cx,
733− search::find_nth_prev,
778+ find_prev_char_impl,
734779 true, /* inclusive */
735780 true, /* extend */
736781 )