diff --git a/book/src/generated/static-cmd.md b/book/src/generated/static-cmd.md index af7515b8e..f6a82020f 100644 --- a/book/src/generated/static-cmd.md +++ b/book/src/generated/static-cmd.md @@ -126,8 +126,10 @@ | `add_newline_below` | Add newline below | normal: `` ] ``, select: `` ] `` | | `goto_type_definition` | Goto type definition | normal: `` gy ``, select: `` gy `` | | `goto_implementation` | Goto implementation | normal: `` gi ``, select: `` gi `` | -| `goto_file_start` | Goto line number else file start | normal: `` gg ``, select: `` gg `` | +| `goto_file_start` | Goto line number else file start | normal: `` gg `` | | `goto_file_end` | Goto file end | | +| `extend_to_file_start` | Extend to line number else file start | select: `` gg `` | +| `extend_to_file_end` | Extend to file end | | | `goto_file` | Goto files/URLs in selections | normal: `` gf ``, select: `` gf `` | | `goto_file_hsplit` | Goto files in selections (hsplit) | normal: `` f ``, `` wf ``, select: `` f ``, `` wf `` | | `goto_file_vsplit` | Goto files in selections (vsplit) | normal: `` F ``, `` wF ``, select: `` F ``, `` wF `` | @@ -139,7 +141,8 @@ | `goto_last_modified_file` | Goto last modified file | normal: `` gm ``, select: `` gm `` | | `goto_last_modification` | Goto last modification | normal: `` g. ``, select: `` g. `` | | `goto_line` | Goto line | normal: `` G ``, select: `` G `` | -| `goto_last_line` | Goto last line | normal: `` ge ``, select: `` ge `` | +| `goto_last_line` | Goto last line | normal: `` ge `` | +| `extend_to_last_line` | Extend to last line | select: `` ge `` | | `goto_first_diag` | Goto first diagnostic | normal: `` [D ``, select: `` [D `` | | `goto_last_diag` | Goto last diagnostic | normal: `` ]D ``, select: `` ]D `` | | `goto_next_diag` | Goto next diagnostic | normal: `` ]d ``, select: `` ]d `` | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2e15dcdcc..f80c277b2 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -426,6 +426,8 @@ impl MappableCommand { goto_implementation, "Goto implementation", goto_file_start, "Goto line number else file start", goto_file_end, "Goto file end", + extend_to_file_start, "Extend to line number else file start", + extend_to_file_end, "Extend to file end", goto_file, "Goto files/URLs in selections", goto_file_hsplit, "Goto files in selections (hsplit)", goto_file_vsplit, "Goto files in selections (vsplit)", @@ -438,6 +440,7 @@ impl MappableCommand { goto_last_modification, "Goto last modification", goto_line, "Goto line", goto_last_line, "Goto last line", + extend_to_last_line, "Extend to last line", goto_first_diag, "Goto first diagnostic", goto_last_diag, "Goto last diagnostic", goto_next_diag, "Goto next diagnostic", @@ -1253,28 +1256,44 @@ fn goto_next_paragraph(cx: &mut Context) { } fn goto_file_start(cx: &mut Context) { + goto_file_start_impl(cx, Movement::Move); +} + +fn extend_to_file_start(cx: &mut Context) { + goto_file_start_impl(cx, Movement::Extend); +} + +fn goto_file_start_impl(cx: &mut Context, movement: Movement) { if cx.count.is_some() { - goto_line(cx); + goto_line_impl(cx, movement); } else { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, 0, cx.editor.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, 0, movement == Movement::Extend)); push_jump(view, doc); doc.set_selection(view.id, selection); } } fn goto_file_end(cx: &mut Context) { + goto_file_end_impl(cx, Movement::Move); +} + +fn extend_to_file_end(cx: &mut Context) { + goto_file_end_impl(cx, Movement::Extend) +} + +fn goto_file_end_impl(cx: &mut Context, movement: Movement) { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let pos = doc.text().len_chars(); let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, pos, cx.editor.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, pos, movement == Movement::Extend)); push_jump(view, doc); doc.set_selection(view.id, selection); } @@ -3746,15 +3765,23 @@ fn push_jump(view: &mut View, doc: &Document) { } fn goto_line(cx: &mut Context) { + goto_line_impl(cx, Movement::Move); +} + +fn goto_line_impl(cx: &mut Context, movement: Movement) { if cx.count.is_some() { let (view, doc) = current!(cx.editor); push_jump(view, doc); - goto_line_without_jumplist(cx.editor, cx.count); + goto_line_without_jumplist(cx.editor, cx.count, movement); } } -fn goto_line_without_jumplist(editor: &mut Editor, count: Option) { +fn goto_line_without_jumplist( + editor: &mut Editor, + count: Option, + movement: Movement, +) { if let Some(count) = count { let (view, doc) = current!(editor); let text = doc.text().slice(..); @@ -3769,13 +3796,21 @@ fn goto_line_without_jumplist(editor: &mut Editor, count: Option) let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, pos, editor.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, pos, movement == Movement::Extend)); doc.set_selection(view.id, selection); } } fn goto_last_line(cx: &mut Context) { + goto_last_line_impl(cx, Movement::Move) +} + +fn extend_to_last_line(cx: &mut Context) { + goto_last_line_impl(cx, Movement::Extend) +} + +fn goto_last_line_impl(cx: &mut Context, movement: Movement) { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); let line_idx = if text.line(text.len_lines() - 1).len_chars() == 0 { @@ -3788,7 +3823,7 @@ fn goto_last_line(cx: &mut Context) { let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, pos, cx.editor.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, pos, movement == Movement::Extend)); push_jump(view, doc); doc.set_selection(view.id, selection); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 4e912127c..a7d1c5f03 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1880,7 +1880,15 @@ fn update_goto_line_number_preview(cx: &mut compositor::Context, args: Args) -> let scrolloff = cx.editor.config().scrolloff; let line = args[0].parse::()?; - goto_line_without_jumplist(cx.editor, NonZeroUsize::new(line)); + goto_line_without_jumplist( + cx.editor, + NonZeroUsize::new(line), + if cx.editor.mode == Mode::Select { + Movement::Extend + } else { + Movement::Move + }, + ); let (view, doc) = current!(cx.editor); view.ensure_cursor_in_view(doc, scrolloff); diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index e160b2246..b9189eb30 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -367,6 +367,8 @@ pub fn default() -> HashMap { "v" => normal_mode, "g" => { "Goto" + "g" => extend_to_file_start, + "e" => extend_to_last_line, "k" => extend_line_up, "j" => extend_line_down, "w" => extend_to_word,