mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
Merge pull request #1864 from SkamDart/text-selection-keybinds
feat: keybinds for text selection on copy mode
This commit is contained in:
@ -1364,54 +1364,6 @@ pub fn keyCallback(
|
||||
}
|
||||
}
|
||||
|
||||
// Expand selection if one exists and event is shift + <arrows, home, end, pg up/down>
|
||||
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,48 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
|
||||
},
|
||||
|
||||
.quit => try self.app.setQuit(),
|
||||
|
||||
.adjust_selection => |direction| adjust_selection: {
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
|
||||
const screen = &self.io.terminal.screen;
|
||||
const sel = if (screen.selection) |*sel| sel else break :adjust_selection;
|
||||
sel.adjust(screen, switch (direction) {
|
||||
.left => .left,
|
||||
.right => .right,
|
||||
.up => .up,
|
||||
.down => .down,
|
||||
.page_up => .page_up,
|
||||
.page_down => .page_down,
|
||||
.home => .home,
|
||||
.end => .end,
|
||||
});
|
||||
|
||||
// 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
|
||||
screen.dirty.selection = true;
|
||||
try self.queueRender();
|
||||
},
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1325,6 +1325,48 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config {
|
||||
.{ .write_scrollback_file = {} },
|
||||
);
|
||||
|
||||
// Expand Selection
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .left }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .left },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .right }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .right },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .up }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .up },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .down }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .down },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .page_up }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .page_up },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .page_down }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .page_down },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .home }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .home },
|
||||
);
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .{ .translated = .end }, .mods = .{ .shift = true } },
|
||||
.{ .adjust_selection = .end },
|
||||
);
|
||||
|
||||
// Windowing
|
||||
if (comptime !builtin.target.isDarwin()) {
|
||||
try result.keybind.set.put(
|
||||
|
@ -195,6 +195,10 @@ pub const Action = union(enum) {
|
||||
scroll_page_fractional: f32,
|
||||
scroll_page_lines: i16,
|
||||
|
||||
/// Adjust an existing selection in a given direction. This action
|
||||
/// does nothing if there is no active selection.
|
||||
adjust_selection: AdjustSelection,
|
||||
|
||||
/// Jump the viewport forward or back by prompt. Positive number is the
|
||||
/// number of prompts to jump forward, negative is backwards.
|
||||
jump_to_prompt: i16,
|
||||
@ -277,6 +281,17 @@ pub const Action = union(enum) {
|
||||
application: []const u8,
|
||||
};
|
||||
|
||||
pub const AdjustSelection = enum {
|
||||
left,
|
||||
right,
|
||||
up,
|
||||
down,
|
||||
page_up,
|
||||
page_down,
|
||||
home,
|
||||
end,
|
||||
};
|
||||
|
||||
pub const SplitDirection = enum {
|
||||
right,
|
||||
down,
|
||||
|
Reference in New Issue
Block a user