@@ -483,7 +483,6 @@ fn move_next_word_start(cx: &mut Context) {
483 let selection = doc
483 let selection = doc
484 .selection(view.id)
484 .selection(view.id)
487 .transform(|range| movement::move_next_word_start(text, range, count));
486 .transform(|range| movement::move_next_word_start(text, range, count));
488 doc.set_selection(view.id, selection);
487 doc.set_selection(view.id, selection);
@@ -496,7 +495,6 @@ fn move_prev_word_start(cx: &mut Context) {
496 let selection = doc
495 let selection = doc
497 .selection(view.id)
496 .selection(view.id)
500 .transform(|range| movement::move_prev_word_start(text, range, count));
498 .transform(|range| movement::move_prev_word_start(text, range, count));
501 doc.set_selection(view.id, selection);
499 doc.set_selection(view.id, selection);
@@ -509,7 +507,6 @@ fn move_next_word_end(cx: &mut Context) {
509 let selection = doc
507 let selection = doc
510 .selection(view.id)
508 .selection(view.id)
513 .transform(|range| movement::move_next_word_end(text, range, count));
510 .transform(|range| movement::move_next_word_end(text, range, count));
514 doc.set_selection(view.id, selection);
511 doc.set_selection(view.id, selection);
@@ -522,7 +519,6 @@ fn move_next_long_word_start(cx: &mut Context) {
522 let selection = doc
519 let selection = doc
523 .selection(view.id)
520 .selection(view.id)
526 .transform(|range| movement::move_next_long_word_start(text, range, count));
522 .transform(|range| movement::move_next_long_word_start(text, range, count));
527 doc.set_selection(view.id, selection);
523 doc.set_selection(view.id, selection);
@@ -535,7 +531,6 @@ fn move_prev_long_word_start(cx: &mut Context) {
535 let selection = doc
531 let selection = doc
536 .selection(view.id)
532 .selection(view.id)
539 .transform(|range| movement::move_prev_long_word_start(text, range, count));
534 .transform(|range| movement::move_prev_long_word_start(text, range, count));
540 doc.set_selection(view.id, selection);
535 doc.set_selection(view.id, selection);
@@ -548,7 +543,6 @@ fn move_next_long_word_end(cx: &mut Context) {
548 let selection = doc
543 let selection = doc
549 .selection(view.id)
544 .selection(view.id)
552 .transform(|range| movement::move_next_long_word_end(text, range, count));
546 .transform(|range| movement::move_next_long_word_end(text, range, count));
553 doc.set_selection(view.id, selection);
547 doc.set_selection(view.id, selection);
@@ -574,15 +568,11 @@ fn extend_next_word_start(cx: &mut Context) {
574 let (view, doc) = current!(cx.editor);
568 let (view, doc) = current!(cx.editor);
575 let text = doc.text().slice(..);
569 let text = doc.text().slice(..);
577− let selection = doc
571+ let selection = doc.selection(view.id).clone().transform(|range| {
581− .transform(|range| {
582− let word = movement::move_next_word_start(text, range, count);
572+ let word = movement::move_next_word_start(text, range, count);
583− let pos = word.cursor(text);
573+ let pos = word.cursor(text);
584− range.put_cursor(text, pos, true)
574+ range.put_cursor(text, pos, true)
586 doc.set_selection(view.id, selection);
576 doc.set_selection(view.id, selection);
@@ -591,15 +581,11 @@ fn extend_prev_word_start(cx: &mut Context) {
591 let (view, doc) = current!(cx.editor);
581 let (view, doc) = current!(cx.editor);
592 let text = doc.text().slice(..);
582 let text = doc.text().slice(..);
594− let selection = doc
584+ let selection = doc.selection(view.id).clone().transform(|range| {
598− .transform(|range| {
599− let word = movement::move_prev_word_start(text, range, count);
585+ let word = movement::move_prev_word_start(text, range, count);
600− let pos = word.cursor(text);
586+ let pos = word.cursor(text);
601− range.put_cursor(text, pos, true)
587+ range.put_cursor(text, pos, true)
603 doc.set_selection(view.id, selection);
589 doc.set_selection(view.id, selection);
@@ -608,15 +594,11 @@ fn extend_next_word_end(cx: &mut Context) {
608 let (view, doc) = current!(cx.editor);
594 let (view, doc) = current!(cx.editor);
609 let text = doc.text().slice(..);
595 let text = doc.text().slice(..);
611− let selection = doc
597+ let selection = doc.selection(view.id).clone().transform(|range| {
615− .transform(|range| {
616− let word = movement::move_next_word_end(text, range, count);
598+ let word = movement::move_next_word_end(text, range, count);
617− let pos = word.cursor(text);
599+ let pos = word.cursor(text);
618− range.put_cursor(text, pos, true)
600+ range.put_cursor(text, pos, true)
620 doc.set_selection(view.id, selection);
602 doc.set_selection(view.id, selection);
@@ -663,13 +645,16 @@ where
663 let text = doc.text().slice(..);
645 let text = doc.text().slice(..);
665 let selection = doc.selection(view.id).clone().transform(|range| {
647 let selection = doc.selection(view.id).clone().transform(|range| {
648+ // TODO: use `Range::cursor()` here instead. However, that works in terms of
649+ // graphemes, wheras this function does yet. So we're doing the same logic
650+ // here, but just in terms of chars instead.
666− let range = if range.anchor < range.head {
651+ let search_start_pos = if range.anchor < range.head {
667− // For block-cursor semantics.
668− Range::new(range.anchor, range.head - 1)
652+ range.head - 1
670− range
654+ range.head
672− search_fn(text, ch, range.head, count, inclusive)
657+ search_fn(text, ch, search_start_pos, count, inclusive)
673 .map_or(range, |pos| range.put_cursor(text, pos, extend))
658 .map_or(range, |pos| range.put_cursor(text, pos, extend))
675 doc.set_selection(view.id, selection);
660 doc.set_selection(view.id, selection);
@@ -795,11 +780,10 @@ fn replace(cx: &mut Context) {
795 _ => None,
780 _ => None,
798− let text = doc.text().slice(..);
799− let selection = doc.selection(view.id).clone().min_width_1(text);
783+ let selection = doc.selection(view.id);
801 if let Some(ch) = ch {
785 if let Some(ch) = ch {
802− let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
786+ let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
803 if !range.is_empty() {
787 if !range.is_empty() {
804 let text: String =
788 let text: String =
805 RopeGraphemes::new(doc.text().slice(range.from()..range.to()))
789 RopeGraphemes::new(doc.text().slice(range.from()..range.to()))
@@ -828,11 +812,8 @@ fn replace(cx: &mut Context) {
829fn switch_case(cx: &mut Context) {
813fn switch_case(cx: &mut Context) {
830 let (view, doc) = current!(cx.editor);
814 let (view, doc) = current!(cx.editor);
831− let selection = doc
815+ let selection = doc.selection(view.id);
834− .min_width_1(doc.text().slice(..));
835− let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
816+ let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
836 let text: Tendril = range
817 let text: Tendril = range
837 .fragment(doc.text().slice(..))
818 .fragment(doc.text().slice(..))
@@ -856,11 +837,8 @@ fn switch_case(cx: &mut Context) {
857fn switch_to_uppercase(cx: &mut Context) {
838fn switch_to_uppercase(cx: &mut Context) {
858 let (view, doc) = current!(cx.editor);
839 let (view, doc) = current!(cx.editor);
859− let selection = doc
840+ let selection = doc.selection(view.id);
862− .min_width_1(doc.text().slice(..));
863− let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
841+ let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
864 let text: Tendril = range.fragment(doc.text().slice(..)).to_uppercase().into();
842 let text: Tendril = range.fragment(doc.text().slice(..)).to_uppercase().into();
866 (range.from(), range.to(), Some(text))
844 (range.from(), range.to(), Some(text))
@@ -872,11 +850,8 @@ fn switch_to_uppercase(cx: &mut Context) {
873fn switch_to_lowercase(cx: &mut Context) {
851fn switch_to_lowercase(cx: &mut Context) {
874 let (view, doc) = current!(cx.editor);
852 let (view, doc) = current!(cx.editor);
875− let selection = doc
853+ let selection = doc.selection(view.id);
878− .min_width_1(doc.text().slice(..));
879− let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
854+ let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
880 let text: Tendril = range.fragment(doc.text().slice(..)).to_lowercase().into();
855 let text: Tendril = range.fragment(doc.text().slice(..)).to_lowercase().into();
882 (range.from(), range.to(), Some(text))
857 (range.from(), range.to(), Some(text))
@@ -1040,15 +1015,9 @@ fn split_selection_on_newline(cx: &mut Context) {
1040fn search_impl(doc: &mut Document, view: &mut View, contents: &str, regex: &Regex, extend: bool) {
1015fn search_impl(doc: &mut Document, view: &mut View, contents: &str, regex: &Regex, extend: bool) {
1041 let text = doc.text().slice(..);
1016 let text = doc.text().slice(..);
1042 let selection = doc.selection(view.id);
1017 let selection = doc.selection(view.id);
1044− // Get the right side of the block cursor.
1019+ // Get the right side of the primary block cursor.
1045− let range = selection.primary();
1046− if range.anchor < range.head {
1049− graphemes::next_grapheme_boundary(text, range.head)
1020+ let start = graphemes::next_grapheme_boundary(text, selection.primary().cursor(text));
1053 // use find_at to find the next match after the cursor, loop around the end
1022 // use find_at to find the next match after the cursor, loop around the end
1054 // Careful, `Regex` uses `bytes` as offsets, not character indices!
1023 // Careful, `Regex` uses `bytes` as offsets, not character indices!
@@ -1132,7 +1101,7 @@ fn extend_line(cx: &mut Context) {
1132 let (view, doc) = current!(cx.editor);
1101 let (view, doc) = current!(cx.editor);
1134 let text = doc.text();
1103 let text = doc.text();
1135− let range = doc.selection(view.id).primary().min_width_1(text.slice(..));
1104+ let range = doc.selection(view.id).primary();
1137 let (start_line, end_line) = range.line_range(text.slice(..));
1106 let (start_line, end_line) = range.line_range(text.slice(..));
1138 let start = text.line_to_char(start_line);
1107 let start = text.line_to_char(start_line);
@@ -1168,14 +1137,14 @@ fn extend_to_line_bounds(cx: &mut Context) {
1169fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId) {
1138fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId) {
1170 let text = doc.text().slice(..);
1139 let text = doc.text().slice(..);
1171− let selection = doc.selection(view_id).clone().min_width_1(text);
1140+ let selection = doc.selection(view_id);
1173 // first yank the selection
1142 // first yank the selection
1174 let values: Vec<String> = selection.fragments(text).map(Cow::into_owned).collect();
1143 let values: Vec<String> = selection.fragments(text).map(Cow::into_owned).collect();
1175 reg.write(values);
1144 reg.write(values);
1177 // then delete
1146 // then delete
1178− let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
1147+ let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
1179 (range.from(), range.to(), None)
1148 (range.from(), range.to(), None)
1181 doc.apply(&transaction, view_id);
1150 doc.apply(&transaction, view_id);
@@ -1247,12 +1216,10 @@ fn append_mode(cx: &mut Context) {
1247 doc.restore_cursor = true;
1216 doc.restore_cursor = true;
1248 let text = doc.text().slice(..);
1217 let text = doc.text().slice(..);
1250− let selection = doc.selection(view.id).clone().min_width_1(text);
1252 // Make sure there's room at the end of the document if the last
1219 // Make sure there's room at the end of the document if the last
1253 // selection butts up against it.
1220 // selection butts up against it.
1254 let end = text.len_chars();
1221 let end = text.len_chars();
1255− let last_range = selection.iter().last().unwrap();
1222+ let last_range = doc.selection(view.id).iter().last().unwrap();
1256 if !last_range.is_empty() && last_range.head == end {
1223 if !last_range.is_empty() && last_range.head == end {
1257 let transaction = Transaction::change(
1224 let transaction = Transaction::change(
1258 doc.text(),
1225 doc.text(),
@@ -1261,7 +1228,7 @@ fn append_mode(cx: &mut Context) {
1261 doc.apply(&transaction, view.id);
1228 doc.apply(&transaction, view.id);
1264− let selection = selection.transform(|range| {
1231+ let selection = doc.selection(view.id).clone().transform(|range| {
1265 Range::new(
1232 Range::new(
1266 range.from(),
1233 range.from(),
1267 graphemes::next_grapheme_boundary(doc.text().slice(..), range.to()),
1234 graphemes::next_grapheme_boundary(doc.text().slice(..), range.to()),
@@ -1689,10 +1656,7 @@ mod cmd {
1690 match cx.editor.clipboard_provider.get_contents() {
1657 match cx.editor.clipboard_provider.get_contents() {
1691 Ok(contents) => {
1658 Ok(contents) => {
1692− let selection = doc
1659+ let selection = doc.selection(view.id);
1693− .selection(view.id)
1695− .min_width_1(doc.text().slice(..));
1696 let transaction =
1660 let transaction =
1697 Transaction::change_by_selection(doc.text(), &selection, |range| {
1661 Transaction::change_by_selection(doc.text(), &selection, |range| {
1698 (range.from(), range.to(), Some(contents.as_str().into()))
1662 (range.from(), range.to(), Some(contents.as_str().into()))
@@ -2471,7 +2435,7 @@ fn select_mode(cx: &mut Context) {
2471 let (view, doc) = current!(cx.editor);
2435 let (view, doc) = current!(cx.editor);
2472 let text = doc.text().slice(..);
2436 let text = doc.text().slice(..);
2474− // Make sure all selections are at least 1-wide.
2438+ // Make sure end-of-document selections are also 1-width.
2475 // (With the exception of being in an empty document, of course.)
2439 // (With the exception of being in an empty document, of course.)
2476 let selection = doc.selection(view.id).clone().transform(|range| {
2440 let selection = doc.selection(view.id).clone().transform(|range| {
2477 if range.is_empty() && range.head == text.len_chars() {
2441 if range.is_empty() && range.head == text.len_chars() {
@@ -2480,7 +2444,7 @@ fn select_mode(cx: &mut Context) {
2480 range.head,
2444 range.head,
2482 } else {
2446 } else {
2483− range.min_width_1(text)
2447+ range
2486 doc.set_selection(view.id, selection);
2450 doc.set_selection(view.id, selection);
@@ -3037,9 +3001,10 @@ pub mod insert {
3037 let text = doc.text().slice(..);
3001 let text = doc.text().slice(..);
3038 let transaction =
3002 let transaction =
3039 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
3003 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
3004+ let pos = range.cursor(text);
3041− graphemes::nth_prev_grapheme_boundary(text, range.head, count),
3006+ graphemes::nth_prev_grapheme_boundary(text, pos, count),
3042− range.head,
3007+ pos,
@@ -3052,9 +3017,10 @@ pub mod insert {
3052 let text = doc.text().slice(..);
3017 let text = doc.text().slice(..);
3053 let transaction =
3018 let transaction =
3054 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
3019 Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
3020+ let pos = range.cursor(text);
3056− range.head,
3022+ pos,
3057− graphemes::nth_next_grapheme_boundary(text, range.head, count),
3023+ graphemes::nth_next_grapheme_boundary(text, pos, count),
@@ -3100,8 +3066,6 @@ fn yank(cx: &mut Context) {
3101 let values: Vec<String> = doc
3067 let values: Vec<String> = doc
3102 .selection(view.id)
3068 .selection(view.id)
3105 .fragments(text)
3069 .fragments(text)
3106 .map(Cow::into_owned)
3070 .map(Cow::into_owned)
3107 .collect();
3071 .collect();
@@ -3125,8 +3089,6 @@ fn yank_joined_to_clipboard_impl(editor: &mut Editor, separator: &str) -> anyhow
3126 let values: Vec<String> = doc
3090 let values: Vec<String> = doc
3127 .selection(view.id)
3091 .selection(view.id)
3130 .fragments(text)
3092 .fragments(text)
3131 .map(Cow::into_owned)
3093 .map(Cow::into_owned)
3132 .collect();
3094 .collect();
@@ -3157,11 +3119,7 @@ fn yank_main_selection_to_clipboard_impl(editor: &mut Editor) -> anyhow::Result<
3157 let (view, doc) = current!(editor);
3119 let (view, doc) = current!(editor);
3158 let text = doc.text().slice(..);
3120 let text = doc.text().slice(..);
3161− .selection(view.id)
3122+ let value = doc.selection(view.id).primary().fragment(text);
3166 if let Err(e) = editor.clipboard_provider.set_contents(value.into_owned()) {
3124 if let Err(e) = editor.clipboard_provider.set_contents(value.into_owned()) {
3167 bail!("Couldn't set system clipboard content: {:?}", e);
3125 bail!("Couldn't set system clipboard content: {:?}", e);
@@ -3202,9 +3160,9 @@ fn paste_impl(
3202 let mut values = values.iter().cloned().map(Tendril::from).chain(repeat);
3160 let mut values = values.iter().cloned().map(Tendril::from).chain(repeat);
3204 let text = doc.text();
3162 let text = doc.text();
3205− let selection = doc.selection(view.id).clone().min_width_1(text.slice(..));
3163+ let selection = doc.selection(view.id);
3207− let transaction = Transaction::change_by_selection(text, &selection, |range| {
3165+ let transaction = Transaction::change_by_selection(text, selection, |range| {
3208 let pos = match (action, linewise) {
3166 let pos = match (action, linewise) {
3209 // paste linewise before
3167 // paste linewise before
3210 (Paste::Before, true) => text.line_to_char(text.char_to_line(range.from())),
3168 (Paste::Before, true) => text.line_to_char(text.char_to_line(range.from())),
@@ -3257,11 +3215,8 @@ fn replace_with_yanked(cx: &mut Context) {
3258 if let Some(values) = registers.read(reg_name) {
3216 if let Some(values) = registers.read(reg_name) {
3259 if let Some(yank) = values.first() {
3217 if let Some(yank) = values.first() {
3260− let selection = doc
3218+ let selection = doc.selection(view.id);
3261− .selection(view.id)
3263− .min_width_1(doc.text().slice(..));
3264− let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
3219+ let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
3265 if !range.is_empty() {
3220 if !range.is_empty() {
3266 (range.from(), range.to(), Some(yank.as_str().into()))
3221 (range.from(), range.to(), Some(yank.as_str().into()))
3267 } else {
3222 } else {
@@ -3280,11 +3235,8 @@ fn replace_selections_with_clipboard_impl(editor: &mut Editor) -> anyhow::Result
3281 match editor.clipboard_provider.get_contents() {
3236 match editor.clipboard_provider.get_contents() {
3282 Ok(contents) => {
3237 Ok(contents) => {
3283− let selection = doc
3238+ let selection = doc.selection(view.id);
3284− .selection(view.id)
3286− .min_width_1(doc.text().slice(..));
3287− let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
3239+ let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
3288 (range.from(), range.to(), Some(contents.as_str().into()))
3240 (range.from(), range.to(), Some(contents.as_str().into()))
@@ -3857,8 +3809,7 @@ fn surround_add(cx: &mut Context) {
3857 } = event
3809 } = event
3859 let (view, doc) = current!(cx.editor);
3811 let (view, doc) = current!(cx.editor);
3860− let text = doc.text().slice(..);
3861− let selection = doc.selection(view.id).clone().min_width_1(text);
3812+ let selection = doc.selection(view.id);
3862 let (open, close) = surround::get_pair(ch);
3813 let (open, close) = surround::get_pair(ch);
3864 let mut changes = Vec::new();
3815 let mut changes = Vec::new();
@@ -3890,9 +3841,9 @@ fn surround_replace(cx: &mut Context) {
3891 let (view, doc) = current!(cx.editor);
3842 let (view, doc) = current!(cx.editor);
3892 let text = doc.text().slice(..);
3843 let text = doc.text().slice(..);
3893− let selection = doc.selection(view.id).clone().min_width_1(text);
3844+ let selection = doc.selection(view.id);
3895− let change_pos = match surround::get_surround_pos(text, &selection, from, count)
3846+ let change_pos = match surround::get_surround_pos(text, selection, from, count)
3897 Some(c) => c,
3848 Some(c) => c,
3898 None => return,
3849 None => return,
@@ -3927,9 +3878,9 @@ fn surround_delete(cx: &mut Context) {
3928 let (view, doc) = current!(cx.editor);
3879 let (view, doc) = current!(cx.editor);
3929 let text = doc.text().slice(..);
3880 let text = doc.text().slice(..);
3930− let selection = doc.selection(view.id).clone().min_width_1(text);
3881+ let selection = doc.selection(view.id);
3932− let change_pos = match surround::get_surround_pos(text, &selection, ch, count) {
3883+ let change_pos = match surround::get_surround_pos(text, selection, ch, count) {
3933 Some(c) => c,
3884 Some(c) => c,
3934 None => return,
3885 None => return,