From 00041d0e64274eddff59c74965414aab9c10f0bd Mon Sep 17 00:00:00 2001 From: Ethan Conneely Date: Mon, 30 Dec 2024 00:39:08 +0000 Subject: [PATCH] copy_or_interrupt action --- src/Surface.zig | 65 +++++++++++++++++++++++++++++++++---------- src/input/Binding.zig | 3 ++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 053dec3fd..5efcb8b0a 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -3870,22 +3870,35 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool }, .copy_to_clipboard => { - // We can read from the renderer state without holding - // the lock because only we will write to this field. - if (self.io.terminal.screen.selection) |sel| { - const buf = self.io.terminal.screen.selectionString(self.alloc, .{ - .sel = sel, - .trim = self.config.clipboard_trim_trailing_spaces, - }) catch |err| { - log.err("error reading selection string err={}", .{err}); - return true; - }; + if (copyToClipboard(self)) { + return true; + } + }, + + .copy_or_interrupt => { + if (copyToClipboard(self)) { + return true; + } else { + const buf = try self.alloc.alloc(u8, 1); defer self.alloc.free(buf); - self.rt_surface.setClipboardString(buf, .standard, false) catch |err| { - log.err("error setting clipboard string err={}", .{err}); - return true; - }; + buf[0] = 3; + + self.io.queueMessage(try termio.Message.writeReq( + self.alloc, + buf, + ), .unlocked); + + // Text triggers a scroll. + { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + self.scrollToBottom() catch |err| { + log.warn("error scrolling to bottom err={}", .{err}); + }; + } + + return true; } }, @@ -4206,6 +4219,30 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool return true; } +fn copyToClipboard(self: *Surface) bool { + // We can read from the renderer state without holding + // the lock because only we will write to this field. + if (self.io.terminal.screen.selection) |sel| { + const buf = self.io.terminal.screen.selectionString(self.alloc, .{ + .sel = sel, + .trim = self.config.clipboard_trim_trailing_spaces, + }) catch |err| { + log.err("error reading selection string err={}", .{err}); + return false; + }; + defer self.alloc.free(buf); + + self.rt_surface.setClipboardString(buf, .standard, false) catch |err| { + log.err("error setting clipboard string err={}", .{err}); + return false; + }; + + return true; + } + + return false; +} + /// Returns true if performing the given action result in closing /// the surface. This is used to determine if our self pointer is /// still valid after performing some binding action. diff --git a/src/input/Binding.zig b/src/input/Binding.zig index 85721339d..54154eee7 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -229,6 +229,7 @@ pub const Action = union(enum) { /// Copy and paste. copy_to_clipboard: void, + copy_or_interrupt: void, paste_from_clipboard: void, paste_from_selection: void, @@ -638,6 +639,7 @@ pub const Action = union(enum) { .cursor_key, .reset, .copy_to_clipboard, + .copy_or_interrupt, .paste_from_clipboard, .paste_from_selection, .increase_font_size, @@ -889,6 +891,7 @@ pub const Action = union(enum) { // with include/ghostty.h. pub const Key = enum(c_int) { copy_to_clipboard, + copy_or_interrupt, paste_from_clipboard, new_tab, new_window,