From dfccdb2d4dfdfa9da14664ae06f56f3db923d1e2 Mon Sep 17 00:00:00 2001 From: "Mohammad H. AlShami" Date: Thu, 7 May 2026 01:25:51 +0300 Subject: [PATCH] Implement needed modifications for issue #12600 For middle-click-action * Kept the option "primary-paste" instead of "paste-primary" to keep backwards compatibility * Added the option "clipboard-paste" For copy-on-select * Added the both, none and primary options Updated config documentation Run zig fmt Move true/false options for copy-on-select to the compatibility handler Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/Surface.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/Surface.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/config/Config.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/Surface.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Update src/Surface.zig Co-authored-by: kat <65649991+00-kat@users.noreply.github.com> Reorder switch items Apply comment from kat Remove redundent code --- src/Surface.zig | 56 ++++++++++++---------------- src/config/Config.zig | 87 +++++++++++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 55 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 8eddc14c8..5e3f84884 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -2378,31 +2378,29 @@ fn setSelection(self: *Surface, sel_: ?terminal.Selection) !void { fn setSelectionAndCopy(self: *Surface, sel: terminal.Selection) !void { try self.setSelection(sel); - // If copy on select is false then exit early. - if (self.config.copy_on_select == .false) return; - switch (self.config.copy_on_select) { - .false => unreachable, // handled above with an early exit + .none => {}, + + // The selection clipboard is set if supported, otherwise nothing is copied. + .primary => try self.copySelectionToClipboards( + sel, + &.{.selection}, + .mixed, + ), + + // Only the standard clipboard is set. + .clipboard => try self.copySelectionToClipboards( + sel, + &.{.standard}, + .mixed, + ), // Both standard and selection clipboards are set. - .clipboard => try self.copySelectionToClipboards( + .both => try self.copySelectionToClipboards( sel, &.{ .standard, .selection }, .mixed, ), - - // The selection clipboard is set if supported, otherwise the standard. - .true => { - const clipboard: apprt.Clipboard = if (self.rt_surface.supportsClipboard(.selection)) - .selection - else - .standard; - try self.copySelectionToClipboards( - sel, - &.{clipboard}, - .mixed, - ); - }, } } @@ -3891,7 +3889,7 @@ pub fn mouseButtonCallback( // The selection clipboard is only updated for left-click drag when // the left button is released. This is to avoid the clipboard // being updated on every mouse move which would be noisy. - if (self.config.copy_on_select != .false) { + if (self.config.copy_on_select != .none) { const prev_ = self.io.terminal.screens.active.selection; if (prev_) |prev| { try self.setSelectionAndCopy(terminal.Selection.init( @@ -4049,22 +4047,16 @@ pub fn mouseButtonCallback( } } - // Middle-click paste source follows copy-on-select: when copy-on-select - // targets the selection clipboard, middle-click reads from it; when - // copy-on-select targets the system clipboard, middle-click reads from - // that instead. Falls back to the standard clipboard on platforms that - // do not support the selection clipboard. + // Middle-click action, either ignore, or paste from clipboard or paste from the selection clipboard if supported. if (button == .middle and action == .press) switch (self.config.middle_click_action) { .ignore => {}, + .@"clipboard-paste" => { + _ = try self.startClipboardRequest(.standard, .{ .paste = {} }); + }, .@"primary-paste" => { - const clipboard: apprt.Clipboard = switch (self.config.copy_on_select) { - .clipboard => .standard, - .true, .false => if (self.rt_surface.supportsClipboard(.selection)) - .selection - else - .standard, - }; - _ = try self.startClipboardRequest(clipboard, .{ .paste = clipboard }); + if (self.rt_surface.supportsClipboard(.selection)) { + _ = try self.startClipboardRequest(.selection, .{ .paste = {} }); + } }, }; diff --git a/src/config/Config.zig b/src/config/Config.zig index f40614a39..bf4e75f86 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -100,6 +100,12 @@ pub const compatibility = std.StaticStringMap( // Ghostty 1.4 renamed `scrollback-limit` to `scrollback-limit-bytes` // when `scrollback-limit-lines` was added so the units are explicit. .{ "scrollback-limit", cli.compatibilityRenamed(Config, "scrollback-limit-bytes") }, + + // Ghostty 1.4 updated "copy-on-select", allow copying to the selection + // clipboard (on supported operating systems), the system clipboard, or + // both. The semantics also changed but this is the correct mapping. + // See: https://github.com/ghostty-org/ghostty/pull/12604 + .{ "copy-on-select", compatCopyOnSelect }, }); /// Set Ghostty's graphical user interface language to a language other than the @@ -2517,25 +2523,28 @@ keybind: Keybinds = .{}, /// limit per surface is double. @"image-storage-limit": u32 = 320 * 1000 * 1000, -/// Whether to automatically copy selected text to the clipboard. `true` -/// will prefer to copy to the selection clipboard, otherwise it will copy to -/// the system clipboard. +/// Whether to automatically copy selected text to the clipboard. /// -/// The value `clipboard` will always copy text to the selection clipboard -/// as well as the system clipboard. +/// Valid values: /// -/// Middle-click primary paste (see `middle-click-action`) is enabled by -/// default even if this is `false`. The clipboard it pastes from follows -/// this setting: with `true` (or `false`) it reads from the selection -/// clipboard (falling back to the system clipboard on platforms without a -/// selection clipboard); with `clipboard` it reads from the system -/// clipboard. +/// * `none` - Do not copy selected text automatically. /// -/// The default value is true on Linux and macOS. +/// * `primary` - On Linux, copy to the selection clipboard only. This has no +/// effect on macOS. (Available since: 1.4.0) +/// +/// * `clipboard` - Copy text to the system clipboard only. +/// +/// * `both` - Copy to both clipboards on Linux, and only the system clipboard +/// on macOS. (Available since: 1.4.0) +/// +/// For backward compatibility and convenience, a value of `true` is the same as +/// `primary` on Linux and `clipboard` on macOS, and `false` is an alias for +/// `none`. +/// +/// The default value is `primary` on Linux and `none` otherwise. @"copy-on-select": CopyOnSelect = switch (builtin.os.tag) { - .linux => .true, - .macos => .true, - else => .false, + .linux => .primary, + else => .none, }, /// The action to take when the user right-clicks on the terminal surface. @@ -2554,8 +2563,9 @@ keybind: Keybinds = .{}, /// The action to take when the user middle-clicks on the terminal surface. /// /// Valid values: -/// * `primary-paste` - Paste from the selection (or system) clipboard per -/// `copy-on-select`. +/// * `primary-paste` - Paste from the selection clipboard on Linux. +/// Does nothing on macOS. +/// * `clipboard-paste` - Paste from the system clipboard. /// * `ignore` - Do nothing, ignore the middle click. /// /// The default value is `primary-paste`. @@ -5047,6 +5057,31 @@ fn compatMacOSDockDropBehavior( return false; } +fn compatCopyOnSelect( + self: *Config, + alloc: Allocator, + key: []const u8, + value: ?[]const u8, +) bool { + _ = alloc; + assert(std.mem.eql(u8, key, "copy-on-select")); + + if (std.mem.eql(u8, value orelse "", "true")) { + self.@"copy-on-select" = switch (builtin.os.tag) { + .linux, .freebsd => .primary, + else => .clipboard, + }; + return true; + } + + if (std.mem.eql(u8, value orelse "", "false")) { + self.@"copy-on-select" = .none; + return true; + } + + return false; +} + /// Add a diagnostic message to the config with the given string. /// This is always added with a location of "none". pub fn addDiagnosticFmt( @@ -8728,16 +8763,20 @@ pub const RepeatableLink = struct { /// Options for copy on select behavior. pub const CopyOnSelect = enum { - /// Disables copy on select entirely. - false, + /// Disables copy on select entirely. This is the default on macOS. + none, /// Copy on select is enabled, but goes to the selection clipboard. - /// This is not supported on platforms such as macOS. This is the default. - true, + /// This is not supported on platforms such as macOS. This is the default + /// on Linux. + primary, + + /// Copy on select is enabled and goes to the system clipboard. + clipboard, /// Copy on select is enabled and goes to both the system clipboard /// and the selection clipboard (for Linux). - clipboard, + both, }; /// Options for right-click actions. @@ -8761,8 +8800,10 @@ pub const RightClickAction = enum { /// Options for middle-click actions. pub const MiddleClickAction = enum { - /// Paste from the selection/standard clipboard per `copy-on-select`. + /// Paste from the selection clipboard. @"primary-paste", + /// Paste from the standard clipboard. + @"clipboard-paste", /// No action is taken on middle click. ignore,