aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/commands.rs
diff options
context:
space:
mode:
authorEmi2024-03-17 22:06:24 +0000
committerGitHub2024-03-17 22:06:24 +0000
commit761df60077bf33cb1077eb4cb019885ea3dd6ae7 (patch)
tree5341b0623b3ad45317d243b1a7840c3d92da9b90 /helix-term/src/commands.rs
parent6fea7876a47df8627a4b40361a6fc0f692c6601f (diff)
Keybind for Extend/shrink selection up and down (#9080)
* implement another selection modifying command * Selection feels more ergonomic in case of swapping the direction. This also fixes a problem when starting at an empty line. * rename select_line_up/down to select_line_above/below * apply clippy suggestion of using cmp instead of if-chain * revert `Extent` implementing `Clone/Copy` * move select_line functions below extend_line implementations * implement help add function, which saturates at the number of text lines --------- Co-authored-by: Emi <emanuel.boehm@gmail.com>
Diffstat (limited to 'helix-term/src/commands.rs')
-rw-r--r--helix-term/src/commands.rs57
1 files changed, 56 insertions, 1 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 4ac2496e..133f2d54 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -57,6 +57,7 @@ use crate::{
use crate::job::{self, Jobs};
use std::{
+ cmp::Ordering,
collections::{HashMap, HashSet},
fmt,
future::Future,
@@ -300,6 +301,8 @@ impl MappableCommand {
extend_line, "Select current line, if already selected, extend to another line based on the anchor",
extend_line_below, "Select current line, if already selected, extend to next line",
extend_line_above, "Select current line, if already selected, extend to previous line",
+ select_line_above, "Select current line, if already selected, extend or shrink line above based on the anchor",
+ select_line_below, "Select current line, if already selected, extend or shrink line below based on the anchor",
extend_to_line_bounds, "Extend selection to line bounds",
shrink_to_line_bounds, "Shrink selection to line bounds",
delete_selection, "Delete selection",
@@ -2435,7 +2438,6 @@ fn extend_line_below(cx: &mut Context) {
fn extend_line_above(cx: &mut Context) {
extend_line_impl(cx, Extend::Above);
}
-
fn extend_line_impl(cx: &mut Context, extend: Extend) {
let count = cx.count();
let (view, doc) = current!(cx.editor);
@@ -2474,6 +2476,59 @@ fn extend_line_impl(cx: &mut Context, extend: Extend) {
doc.set_selection(view.id, selection);
}
+fn select_line_below(cx: &mut Context) {
+ select_line_impl(cx, Extend::Below);
+}
+fn select_line_above(cx: &mut Context) {
+ select_line_impl(cx, Extend::Above);
+}
+fn select_line_impl(cx: &mut Context, extend: Extend) {
+ let mut count = cx.count();
+ let (view, doc) = current!(cx.editor);
+ let text = doc.text();
+ let saturating_add = |a: usize, b: usize| (a + b).min(text.len_lines());
+ let selection = doc.selection(view.id).clone().transform(|range| {
+ let (start_line, end_line) = range.line_range(text.slice(..));
+ let start = text.line_to_char(start_line);
+ let end = text.line_to_char(saturating_add(end_line, 1));
+ let direction = range.direction();
+
+ // Extending to line bounds is counted as one step
+ if range.from() != start || range.to() != end {
+ count = count.saturating_sub(1)
+ }
+ let (anchor_line, head_line) = match (&extend, direction) {
+ (Extend::Above, Direction::Forward) => (start_line, end_line.saturating_sub(count)),
+ (Extend::Above, Direction::Backward) => (end_line, start_line.saturating_sub(count)),
+ (Extend::Below, Direction::Forward) => (start_line, saturating_add(end_line, count)),
+ (Extend::Below, Direction::Backward) => (end_line, saturating_add(start_line, count)),
+ };
+ let (anchor, head) = match anchor_line.cmp(&head_line) {
+ Ordering::Less => (
+ text.line_to_char(anchor_line),
+ text.line_to_char(saturating_add(head_line, 1)),
+ ),
+ Ordering::Equal => match extend {
+ Extend::Above => (
+ text.line_to_char(saturating_add(anchor_line, 1)),
+ text.line_to_char(head_line),
+ ),
+ Extend::Below => (
+ text.line_to_char(head_line),
+ text.line_to_char(saturating_add(anchor_line, 1)),
+ ),
+ },
+
+ Ordering::Greater => (
+ text.line_to_char(saturating_add(anchor_line, 1)),
+ text.line_to_char(head_line),
+ ),
+ };
+ Range::new(anchor, head)
+ });
+
+ doc.set_selection(view.id, selection);
+}
fn extend_to_line_bounds(cx: &mut Context) {
let (view, doc) = current!(cx.editor);