on master help sign in
prevent selection collapse when inserting a newline (#2414)
e0b5cdfMichael Davis
helix-term/src/commands.rs+23−9
@@ -2777,14 +2777,14 @@ pub mod insert {
2777 let text = doc.text().slice(..);
2777 let text = doc.text().slice(..);
2778
2778
2779 let contents = doc.text();
2779 let contents = doc.text();
2780− let selection = doc.selection(view.id).clone().cursors(text);
2780+ let selection = doc.selection(view.id).clone();
2781 let mut ranges = SmallVec::with_capacity(selection.len());
2781 let mut ranges = SmallVec::with_capacity(selection.len());
2782
2782
2783 // TODO: this is annoying, but we need to do it to properly calculate pos after edits
2783 // TODO: this is annoying, but we need to do it to properly calculate pos after edits
2784− let mut offs = 0;
2784+ let mut global_offs = 0;
2785
2785
2786 let mut transaction = Transaction::change_by_selection(contents, &selection, |range| {
2786 let mut transaction = Transaction::change_by_selection(contents, &selection, |range| {
2787− let pos = range.head;
2787+ let pos = range.cursor(text);
2788
2788
2789 let prev = if pos == 0 {
2789 let prev = if pos == 0 {
2790 ' '
2790 ' '
@@ -2814,27 +2814,41 @@ pub mod insert {
2814 .and_then(|pair| if pair.close == curr { Some(pair) } else { None })
2814 .and_then(|pair| if pair.close == curr { Some(pair) } else { None })
2815 .is_some();
2815 .is_some();
2816
2816
2817− let new_head_pos = if on_auto_pair {
2817+ let local_offs = if on_auto_pair {
2818 let inner_indent = indent.clone() + doc.indent_style.as_str();
2818 let inner_indent = indent.clone() + doc.indent_style.as_str();
2819 text.reserve_exact(2 + indent.len() + inner_indent.len());
2819 text.reserve_exact(2 + indent.len() + inner_indent.len());
2820 text.push_str(doc.line_ending.as_str());
2820 text.push_str(doc.line_ending.as_str());
2821 text.push_str(&inner_indent);
2821 text.push_str(&inner_indent);
2822− let new_head_pos = pos + offs + text.chars().count();
2822+ let local_offs = text.chars().count();
2823 text.push_str(doc.line_ending.as_str());
2823 text.push_str(doc.line_ending.as_str());
2824 text.push_str(&indent);
2824 text.push_str(&indent);
2825− new_head_pos
2825+ local_offs
2826 } else {
2826 } else {
2827 text.reserve_exact(1 + indent.len());
2827 text.reserve_exact(1 + indent.len());
2828 text.push_str(doc.line_ending.as_str());
2828 text.push_str(doc.line_ending.as_str());
2829 text.push_str(&indent);
2829 text.push_str(&indent);
2830− pos + offs + text.chars().count()
2830+ text.chars().count()
2831+ };
2832+
2833+ let new_range = if doc.restore_cursor {
2834+ // when appending, extend the range by local_offs
2835+ Range::new(
2836+ range.anchor + global_offs,
2837+ range.head + local_offs + global_offs,
2838+ )
2839+ } else {
2840+ // when inserting, slide the range by local_offs
2841+ Range::new(
2842+ range.anchor + local_offs + global_offs,
2843+ range.head + local_offs + global_offs,
2844+ )
2831 };
2845 };
2832
2846
2833 // TODO: range replace or extend
2847 // TODO: range replace or extend
2834 // range.replace(|range| range.is_empty(), head); -> fn extend if cond true, new head pos
2848 // range.replace(|range| range.is_empty(), head); -> fn extend if cond true, new head pos
2835 // can be used with cx.mode to do replace or extend on most changes
2849 // can be used with cx.mode to do replace or extend on most changes
2836− ranges.push(Range::new(new_head_pos, new_head_pos));
2850+ ranges.push(new_range);
2837− offs += text.chars().count();
2851+ global_offs += text.chars().count();
2838
2852
2839 (pos, pos, Some(text.into()))
2853 (pos, pos, Some(text.into()))
2840 });
2854 });