From cdeeeb9f88229124d7cb6a13f08219412bfc39c3 Mon Sep 17 00:00:00 2001 From: Cameron Dart <8763518+SkamDart@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:00:19 -0700 Subject: [PATCH] feat: keybinds for text selection on copy mode --- src/Surface.zig | 89 ++++++++++++++++++++----------------------- src/config/Config.zig | 42 ++++++++++++++++++++ src/input/Binding.zig | 9 +++++ 3 files changed, 92 insertions(+), 48 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 9c4431ddc..4068834f0 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1364,54 +1364,6 @@ pub fn keyCallback( } } - // Expand selection if one exists and event is shift + - if (event.mods.shift) adjust_selection: { - self.renderer_state.mutex.lock(); - defer self.renderer_state.mutex.unlock(); - var screen = &self.io.terminal.screen; - const sel = if (screen.selection) |*sel| sel else break :adjust_selection; - - // Silently consume key releases. We only want to process selection - // adjust on press. - if (event.action != .press and event.action != .repeat) return .consumed; - - sel.adjust(screen, switch (event.key) { - .left => .left, - .right => .right, - .up => .up, - .down => .down, - .page_up => .page_up, - .page_down => .page_down, - .home => .home, - .end => .end, - else => break :adjust_selection, - }); - - // If the selection endpoint is outside of the current viewpoint, - // scroll it in to view. Note we always specifically use sel.end - // because that is what adjust modifies. - scroll: { - const viewport_tl = screen.pages.getTopLeft(.viewport); - const viewport_br = screen.pages.getBottomRight(.viewport).?; - if (sel.end().isBetween(viewport_tl, viewport_br)) - break :scroll; - - // Our end point is not within the viewport. If the end - // point is after the br then we need to adjust the end so - // that it is at the bottom right of the viewport. - const target = if (sel.end().before(viewport_tl)) - sel.end() - else - sel.end().up(screen.pages.rows - 1) orelse sel.end(); - - screen.scroll(.{ .pin = target }); - } - - // Queue a render so its shown - try self.queueRender(); - return .consumed; - } - // If we allow KAM and KAM is enabled then we do nothing. if (self.config.vt_kam_allowed) { self.renderer_state.mutex.lock(); @@ -3535,6 +3487,47 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool }, .quit => try self.app.setQuit(), + + .selection_navigation_left, .selection_navigation_right, .selection_navigation_up, .selection_navigation_down => { + alter_navigation: { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + var screen = &self.io.terminal.screen; + const sel = if (screen.selection) |*sel| sel else break :alter_navigation; + sel.adjust(screen, switch (action) { + .selection_navigation_left => .left, + .selection_navigation_right => .right, + .selection_navigation_up => .up, + .selection_navigation_down => .down, + .selection_navigation_page_up => .page_up, + .selection_navigation_page_down => .page_down, + .selection_natigation_home => .home, + .selection_natigation_end => .end, + else => break :alter_navigation, + }); + // If the selection endpoint is outside of the current viewpoint, + // scroll it in to view. Note we always specifically use sel.end + // because that is what adjust modifies. + scroll: { + const viewport_tl = screen.pages.getTopLeft(.viewport); + const viewport_br = screen.pages.getBottomRight(.viewport).?; + if (sel.end().isBetween(viewport_tl, viewport_br)) + break :scroll; + + // Our end point is not within the viewport. If the end + // point is after the br then we need to adjust the end so + // that it is at the bottom right of the viewport. + const target = if (sel.end().before(viewport_tl)) + sel.end() + else + sel.end().up(screen.pages.rows - 1) orelse sel.end(); + + screen.scroll(.{ .pin = target }); + } + } + // Queue a render so its shown + try self.queueRender(); + }, } return true; diff --git a/src/config/Config.zig b/src/config/Config.zig index e95a2ba8e..9ff941805 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -1494,6 +1494,48 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config { .{ .key = .{ .translated = .insert }, .mods = .{ .shift = true } }, .{ .paste_from_selection = {} }, ); + + // Selection Navigation + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .left }, .mods = .{ .shift = true } }, + .{ .selection_navigation_left = {} }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .right }, .mods = .{ .shift = true } }, + .{ .selection_navigation_right = {} }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .up }, .mods = .{ .shift = true } }, + .{ .selection_navigation_up = {} }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .down }, .mods = .{ .shift = true } }, + .{ .selection_navigation_down = {} }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .page_up }, .mods = .{ .shift = true } }, + .{ .selection_navigation_page_up = {} }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .page_down }, .mods = .{ .shift = true } }, + .{ .selection_navigation_page_down = {} }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .home }, .mods = .{ .shift = true } }, + .{ .selection_navigation_home = {} }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .{ .translated = .end }, .mods = .{ .shift = true } }, + .{ .selection_navigation_end = {} }, + ); } { // Cmd+N for goto tab N diff --git a/src/input/Binding.zig b/src/input/Binding.zig index 27c620f15..40b064742 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -169,6 +169,15 @@ pub const Action = union(enum) { /// enter after to get a new prompt. reset: void, + selection_navigation_left: void, + selection_navigation_right: void, + selection_navigation_up: void, + selection_navigation_down: void, + selection_navigation_page_up: void, + selection_navigation_page_down: void, + selection_natigation_home: void, + selection_natigation_end: void, + /// Copy and paste. copy_to_clipboard: void, paste_from_clipboard: void,