Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keybind for Extend/shrink selection up and down #9080

Merged
merged 7 commits into from
Mar 17, 2024
63 changes: 63 additions & 0 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ use crate::{
use crate::job::{self, Jobs};
use futures_util::{stream::FuturesUnordered, TryStreamExt};
use std::{
cmp::Ordering,
collections::{HashMap, HashSet},
fmt,
future::Future,
Expand Down Expand Up @@ -298,6 +299,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",
Expand Down Expand Up @@ -2392,6 +2395,7 @@ fn global_search(cx: &mut Context) {
);
}

#[derive(Clone, Copy)]
the-mikedavis marked this conversation as resolved.
Show resolved Hide resolved
enum Extend {
Above,
Below,
Expand All @@ -2413,7 +2417,66 @@ fn extend_line_below(cx: &mut Context) {
fn extend_line_above(cx: &mut Context) {
extend_line_impl(cx, Extend::Above);
}
the-mikedavis marked this conversation as resolved.
Show resolved Hide resolved
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 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(
(end_line + 1) // newline of end_line
.min(text.len_lines()),
);
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, (end_line + count).min(text.len_lines()))
the-mikedavis marked this conversation as resolved.
Show resolved Hide resolved
}
(Extend::Below, Direction::Backward) => {
(end_line, (start_line + count).min(text.len_lines()))
}
};
let (anchor, head) = match anchor_line.cmp(&head_line) {
Ordering::Less => (
text.line_to_char(anchor_line),
text.line_to_char((head_line + 1).min(text.len_lines())),
),
Ordering::Equal => match extend {
Extend::Above => (
text.line_to_char((anchor_line + 1).min(text.len_lines())),
text.line_to_char(head_line),
),
Extend::Below => (
text.line_to_char(head_line),
text.line_to_char((anchor_line + 1).min(text.len_lines())),
),
},

Ordering::Greater => (
text.line_to_char((anchor_line + 1).min(text.len_lines())),
text.line_to_char(head_line),
),
};
Range::new(anchor, head)
});

doc.set_selection(view.id, selection);
}
fn extend_line_impl(cx: &mut Context, extend: Extend) {
let count = cx.count();
let (view, doc) = current!(cx.editor);
Expand Down
Loading