From c79fdf6dd53c807e433a3b8ab7adac59b5614c5f Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Sun, 11 Jun 2023 18:58:44 +0200 Subject: [PATCH 1/9] auto indent change if selection begin by a whole line --- helix-term/src/commands.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 99f27c0099eb..60bfe944fcae 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2315,10 +2315,27 @@ enum Operation { Change, } +fn begin_by_a_whole_line(selection: &Selection, text: &Rope) -> bool { + if selection.ranges().len() == 1 { + let range = selection.ranges()[0]; + // If at least a full line is selected (strange require 2). + if range.slice(text.slice(..)).len_lines() >= 2 { + // If in the begin of the selection is at the begining of a line. + let (start_line, _) = range.line_range(text.slice(..)); + let start = text.line_to_char(start_line); + if start == range.anchor { + return true; + } + } + } + false +} + fn delete_selection_impl(cx: &mut Context, op: Operation) { let (view, doc) = current!(cx.editor); let selection = doc.selection(view.id); + let begin_by_a_whole_line = begin_by_a_whole_line(selection, doc.text()); if cx.register != Some('_') { // first yank the selection @@ -2339,7 +2356,11 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { exit_select_mode(cx); } Operation::Change => { - enter_insert_mode(cx); + if begin_by_a_whole_line { + open_above(cx); + } else { + enter_insert_mode(cx); + } } } } From a597d4e48b588daf25d43a4345a36f5d3372264d Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Mon, 12 Jun 2023 19:20:15 +0200 Subject: [PATCH 2/9] add support for multi cursor --- helix-term/src/commands.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 60bfe944fcae..1a8fcd001df2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2316,8 +2316,7 @@ enum Operation { } fn begin_by_a_whole_line(selection: &Selection, text: &Rope) -> bool { - if selection.ranges().len() == 1 { - let range = selection.ranges()[0]; + for range in selection.ranges() { // If at least a full line is selected (strange require 2). if range.slice(text.slice(..)).len_lines() >= 2 { // If in the begin of the selection is at the begining of a line. From e3253107fe4f5a815f42f73839ccdaa3926a90fe Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Mon, 12 Jun 2023 19:54:04 +0200 Subject: [PATCH 3/9] selection must match the start and the end of a line --- helix-term/src/commands.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 1a8fcd001df2..563faecf1843 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2319,10 +2319,11 @@ fn begin_by_a_whole_line(selection: &Selection, text: &Rope) -> bool { for range in selection.ranges() { // If at least a full line is selected (strange require 2). if range.slice(text.slice(..)).len_lines() >= 2 { - // If in the begin of the selection is at the begining of a line. - let (start_line, _) = range.line_range(text.slice(..)); + // If the start of the selection is at the start of a line and the end at the end of a line. + let (start_line, end_line) = range.line_range(text.slice(..)); let start = text.line_to_char(start_line); - if start == range.anchor { + let end = text.line_to_char((end_line + 1).min(text.len_lines())); + if start == range.anchor && end == range.head { return true; } } From 8471463ff65c20f0d713987f46731138a85709de Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Mon, 12 Jun 2023 20:13:36 +0200 Subject: [PATCH 4/9] refactor: functional style and renaming --- helix-term/src/commands.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 563faecf1843..ff6d0d3445b6 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2315,27 +2315,25 @@ enum Operation { Change, } -fn begin_by_a_whole_line(selection: &Selection, text: &Rope) -> bool { - for range in selection.ranges() { - // If at least a full line is selected (strange require 2). - if range.slice(text.slice(..)).len_lines() >= 2 { - // If the start of the selection is at the start of a line and the end at the end of a line. - let (start_line, end_line) = range.line_range(text.slice(..)); - let start = text.line_to_char(start_line); - let end = text.line_to_char((end_line + 1).min(text.len_lines())); - if start == range.anchor && end == range.head { - return true; - } +fn only_whole_lines(selection: &Selection, text: &Rope) -> bool { + selection.ranges().into_iter().all(|range| { + // If not at least a full line is selected (strange require 2). + if range.slice(text.slice(..)).len_lines() < 2 { + return false; } - } - false + // If the start of the selection is at the start of a line and the end at the end of a line. + let (start_line, end_line) = range.line_range(text.slice(..)); + let start = text.line_to_char(start_line); + let end = text.line_to_char((end_line + 1).min(text.len_lines())); + start == range.anchor && end == range.head + }) } fn delete_selection_impl(cx: &mut Context, op: Operation) { let (view, doc) = current!(cx.editor); let selection = doc.selection(view.id); - let begin_by_a_whole_line = begin_by_a_whole_line(selection, doc.text()); + let only_whole_lines = only_whole_lines(selection, doc.text()); if cx.register != Some('_') { // first yank the selection @@ -2356,7 +2354,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { exit_select_mode(cx); } Operation::Change => { - if begin_by_a_whole_line { + if only_whole_lines { open_above(cx); } else { enter_insert_mode(cx); From c05c8aca7438fa6b3a3daacd33d79dc761f5427b Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Mon, 12 Jun 2023 20:43:33 +0200 Subject: [PATCH 5/9] use from() and to() instead of anchor and head for range --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ff6d0d3445b6..a9f0952021ba 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2325,7 +2325,7 @@ fn only_whole_lines(selection: &Selection, text: &Rope) -> bool { let (start_line, end_line) = range.line_range(text.slice(..)); let start = text.line_to_char(start_line); let end = text.line_to_char((end_line + 1).min(text.len_lines())); - start == range.anchor && end == range.head + start == range.from() && end == range.to() }) } From 9868b02b80fb7955aac24f512de15a79d306fc5c Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Mon, 12 Jun 2023 22:25:57 +0200 Subject: [PATCH 6/9] fix clippy --- helix-term/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index a9f0952021ba..81cf0163e69c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2316,7 +2316,7 @@ enum Operation { } fn only_whole_lines(selection: &Selection, text: &Rope) -> bool { - selection.ranges().into_iter().all(|range| { + selection.ranges().iter().all(|range| { // If not at least a full line is selected (strange require 2). if range.slice(text.slice(..)).len_lines() < 2 { return false; From 7192f2027d594809655839197c66bacf841f148b Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Wed, 14 Jun 2023 19:55:53 +0200 Subject: [PATCH 7/9] Implement as a new command --- helix-term/src/commands.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 81cf0163e69c..48e0d2e3a5a7 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -296,6 +296,8 @@ impl MappableCommand { delete_selection, "Delete selection", delete_selection_noyank, "Delete selection without yanking", change_selection, "Change selection", + change_selection_with_indent, "Change selection and place the cursor at the appropriated indent", + change_selection_with_indent_noyank, "Change selection without yanking and place the cursor at the appropriated indent", change_selection_noyank, "Change selection without yanking", collapse_selection, "Collapse selection into single cursor", flip_selections, "Flip selection cursor and anchor", @@ -2313,6 +2315,7 @@ fn shrink_to_line_bounds(cx: &mut Context) { enum Operation { Delete, Change, + ChangeWithIndent, } fn only_whole_lines(selection: &Selection, text: &Rope) -> bool { @@ -2354,6 +2357,9 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { exit_select_mode(cx); } Operation::Change => { + enter_insert_mode(cx); + } + Operation::ChangeWithIndent => { if only_whole_lines { open_above(cx); } else { @@ -2427,6 +2433,15 @@ fn change_selection_noyank(cx: &mut Context) { delete_selection_impl(cx, Operation::Change); } +fn change_selection_with_indent(cx: &mut Context) { + delete_selection_impl(cx, Operation::ChangeWithIndent); +} + +fn change_selection_with_indent_noyank(cx: &mut Context) { + cx.register = Some('_'); + delete_selection_impl(cx, Operation::ChangeWithIndent); +} + fn collapse_selection(cx: &mut Context) { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); From 0a7b0a8d8016b4b08c37fb6cbcea59b07960c11c Mon Sep 17 00:00:00 2001 From: Tudyx Date: Wed, 21 Jun 2023 00:34:34 +0200 Subject: [PATCH 8/9] Revert "Implement as a new command" This reverts commit 7192f2027d594809655839197c66bacf841f148b. --- helix-term/src/commands.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 48e0d2e3a5a7..81cf0163e69c 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -296,8 +296,6 @@ impl MappableCommand { delete_selection, "Delete selection", delete_selection_noyank, "Delete selection without yanking", change_selection, "Change selection", - change_selection_with_indent, "Change selection and place the cursor at the appropriated indent", - change_selection_with_indent_noyank, "Change selection without yanking and place the cursor at the appropriated indent", change_selection_noyank, "Change selection without yanking", collapse_selection, "Collapse selection into single cursor", flip_selections, "Flip selection cursor and anchor", @@ -2315,7 +2313,6 @@ fn shrink_to_line_bounds(cx: &mut Context) { enum Operation { Delete, Change, - ChangeWithIndent, } fn only_whole_lines(selection: &Selection, text: &Rope) -> bool { @@ -2357,9 +2354,6 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { exit_select_mode(cx); } Operation::Change => { - enter_insert_mode(cx); - } - Operation::ChangeWithIndent => { if only_whole_lines { open_above(cx); } else { @@ -2433,15 +2427,6 @@ fn change_selection_noyank(cx: &mut Context) { delete_selection_impl(cx, Operation::Change); } -fn change_selection_with_indent(cx: &mut Context) { - delete_selection_impl(cx, Operation::ChangeWithIndent); -} - -fn change_selection_with_indent_noyank(cx: &mut Context) { - cx.register = Some('_'); - delete_selection_impl(cx, Operation::ChangeWithIndent); -} - fn collapse_selection(cx: &mut Context) { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); From 8ad04031bfb3ea6ed07da3778741e3e5053910a2 Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Tue, 11 Jul 2023 20:14:05 +0200 Subject: [PATCH 9/9] renaming and refactoring --- helix-term/src/commands.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 81cf0163e69c..96d83fc215ec 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2315,14 +2315,14 @@ enum Operation { Change, } -fn only_whole_lines(selection: &Selection, text: &Rope) -> bool { +fn selection_is_linewise(selection: &Selection, text: &Rope) -> bool { selection.ranges().iter().all(|range| { - // If not at least a full line is selected (strange require 2). - if range.slice(text.slice(..)).len_lines() < 2 { + let text = text.slice(..); + if range.slice(text).len_lines() < 2 { return false; } // If the start of the selection is at the start of a line and the end at the end of a line. - let (start_line, end_line) = range.line_range(text.slice(..)); + let (start_line, end_line) = range.line_range(text); let start = text.line_to_char(start_line); let end = text.line_to_char((end_line + 1).min(text.len_lines())); start == range.from() && end == range.to() @@ -2333,7 +2333,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { let (view, doc) = current!(cx.editor); let selection = doc.selection(view.id); - let only_whole_lines = only_whole_lines(selection, doc.text()); + let only_whole_lines = selection_is_linewise(selection, doc.text()); if cx.register != Some('_') { // first yank the selection