on master help sign in
Refactor copy selection vertically
0793841Blaž Hrastnik
helix-term/src/commands.rs+61−19
@@ -960,32 +960,74 @@ fn extend_char_right(cx: &mut Context) {
960 doc.set_selection(view.id, selection);
960 doc.set_selection(view.id, selection);
961}
961}
962
962
963−fn copy_selection_on_prev_line(cx: &mut Context) {
963+fn copy_selection_on_line(cx: &mut Context, direction: Direction) {
964 let count = cx.count();
964 let count = cx.count();
965 let (view, doc) = current!(cx.editor);
965 let (view, doc) = current!(cx.editor);
966 let text = doc.text().slice(..);
966 let text = doc.text().slice(..);
967− let old_selection = doc.selection(view.id).clone();
967+ let selection = doc.selection(view.id);
968− let mut ranges: SmallVec<_> = old_selection.ranges().into();
968+ let mut ranges = SmallVec::with_capacity(selection.ranges().len() * (count + 1));
969− for r in old_selection.iter() {
969+ ranges.extend_from_slice(selection.ranges());
970+ let mut primary_index = 0;
971+ for range in selection.iter() {
972+ let is_primary = *range == selection.primary();
973+ let head_pos = coords_at_pos(text, range.head);
974+ let anchor_pos = coords_at_pos(text, range.anchor);
975+ let height = std::cmp::max(head_pos.row, anchor_pos.row)
976+ - std::cmp::min(head_pos.row, anchor_pos.row)
977+ + 1;
978+
979+ if is_primary {
980+ primary_index = ranges.len();
981+ }
982+ ranges.push(*range);
983+
984+ let mut sels = 0;
985+ let mut i = 0;
986+ while sels < count {
987+ let offset = (i + 1) * height;
988+
989+ let anchor_row = match direction {
990+ Direction::Forward => anchor_pos.row + offset,
991+ Direction::Backward => anchor_pos.row.saturating_sub(offset),
992+ };
993+
994+ let head_row = match direction {
995+ Direction::Forward => head_pos.row + offset,
996+ Direction::Backward => head_pos.row.saturating_sub(offset),
997+ };
998+
999+ if anchor_row >= text.len_lines() || head_row >= text.len_lines() {
1000+ break;
1001+ }
1002+
1003+ let anchor = pos_at_coords(text, Position::new(anchor_row, anchor_pos.col), true);
1004+ let head = pos_at_coords(text, Position::new(head_row, head_pos.col), true);
1005+
1006+ // skip lines that are too short
1007+ if coords_at_pos(text, anchor).col == anchor_pos.col
1008+ && coords_at_pos(text, head).col == head_pos.col
1009+ {
1010+ if is_primary {
1011+ primary_index = ranges.len();
1012+ }
970− ranges.push(Range::point(
1013+ ranges.push(Range::new(anchor, head));
971− movement::move_vertically(text, *r, Direction::Backward, count, Movement::Extend).head,
1014+ sels += 1;
972− ));
1015+ }
1016+
1017+ i += 1;
1018+ }
973 }
1019 }
1020+
1021+ let selection = Selection::new(ranges, primary_index);
974− doc.set_selection(view.id, Selection::new(ranges, old_selection.cursor()));
1022+ doc.set_selection(view.id, selection);
1023+}
1024+
1025+fn copy_selection_on_prev_line(cx: &mut Context) {
1026+ copy_selection_on_line(cx, Direction::Backward)
975}
1027}
976
1028
977fn copy_selection_on_next_line(cx: &mut Context) {
1029fn copy_selection_on_next_line(cx: &mut Context) {
978− let count = cx.count();
1030+ copy_selection_on_line(cx, Direction::Forward)
979− let (view, doc) = current!(cx.editor);
980− let text = doc.text().slice(..);
981− let old_selection = doc.selection(view.id).clone();
982− let mut ranges: SmallVec<_> = old_selection.ranges().into();
983− for r in old_selection.iter() {
984− ranges.push(Range::point(
985− movement::move_vertically(text, *r, Direction::Forward, count, Movement::Extend).head,
986− ));
987− }
988− doc.set_selection(view.id, Selection::new(ranges, old_selection.cursor()));
989}
1031}
990
1032
991fn extend_line_up(cx: &mut Context) {
1033fn extend_line_up(cx: &mut Context) {
helix-term/src/keymap.rs+1−1
@@ -388,7 +388,7 @@ impl Default for Keymaps {
388 // TODO: also change delete without yanking
388 // TODO: also change delete without yanking
389
389
390 "C" => copy_selection_on_next_line,
390 "C" => copy_selection_on_next_line,
391− "alt-C" => copy_selection_on_prev_line,
391+ "A-C" => copy_selection_on_prev_line,
392
392
393
393
394 "s" => select_regex,
394 "s" => select_regex,