diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 90226c53..15ccc247 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -247,6 +247,7 @@ impl MappableCommand { search_selection, "Use current selection as search pattern", global_search, "Global Search in workspace folder", extend_line, "Select current line, if already selected, extend to next line", + extend_line_above, "Select current line, if already selected, extend to previous line", extend_to_line_bounds, "Extend selection to line bounds (line-wise selection)", delete_selection, "Delete selection", delete_selection_noyank, "Delete selection, without yanking", @@ -1854,7 +1855,20 @@ fn global_search(cx: &mut Context) { cx.jobs.callback(show_picker); } +enum Extend { + Above, + Below, +} + fn extend_line(cx: &mut Context) { + extend_line_impl(cx, Extend::Below); +} + +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); @@ -1863,13 +1877,22 @@ fn extend_line(cx: &mut Context) { let (start_line, end_line) = range.line_range(text.slice(..)); let start = text.line_to_char(start_line); - let mut end = text.line_to_char((end_line + count).min(text.len_lines())); + let end = text.line_to_char((end_line + count).min(text.len_lines())); - // go to next line if current line is selected - if range.from() == start && range.to() == end { - end = text.line_to_char((end_line + count + 1).min(text.len_lines())); - } - Range::new(start, end) + // extend to previous/next line if current line is selected + let (anchor, head) = if range.from() == start && range.to() == end { + match extend { + Extend::Above => (end, text.line_to_char(start_line.saturating_sub(1))), + Extend::Below => ( + start, + text.line_to_char((end_line + count + 1).min(text.len_lines())), + ), + } + } else { + (start, end) + }; + + Range::new(anchor, head) }); doc.set_selection(view.id, selection);