diff --git a/src/config.zig b/src/config.zig index a6f4113f0..4fda2e5b5 100644 --- a/src/config.zig +++ b/src/config.zig @@ -9,6 +9,7 @@ pub const Keybinds = Config.Keybinds; pub const MouseShiftCapture = Config.MouseShiftCapture; pub const NonNativeFullscreen = Config.NonNativeFullscreen; pub const OptionAsAlt = Config.OptionAsAlt; +pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures; // Alternate APIs pub const CAPI = @import("config/CAPI.zig"); diff --git a/src/config/Config.zig b/src/config/Config.zig index 3e92888ff..7eb11e6d4 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -532,12 +532,23 @@ keybind: Keybinds = .{}, /// configure your shell to enable the integration. /// * "detect" - Detect the shell based on the filename. /// * "fish", "zsh" - Use this specific shell injection scheme. -/// * "no-cursor" - Detect the shell as in 'detect', but doesn't set cursor -/// shapes /// /// The default value is "detect". @"shell-integration": ShellIntegration = .detect, +/// Shell integration features to enable if shell integration itself is enabled. +/// The format of this is a list of features to enable separated by commas. +/// If you prefix a feature with "no-" then it is disabled. If you omit +/// a feature, its default value is used, so you must explicitly disable +/// features you don't want. +/// +/// Available features: +/// +/// - "cursor" - Set the cursor to a blinking bar at the prompt. +/// +/// Example: "cursor", "no-cursor" +@"shell-integration-features": ShellIntegrationFeatures = .{}, + /// Sets the reporting format for OSC sequences that request color information. /// Ghostty currently supports OSC 10 (foreground) and OSC 11 (background) queries, /// and by default the reported values are scaled-up RGB values, where each component @@ -2184,7 +2195,6 @@ pub const ShellIntegration = enum { detect, fish, zsh, - @"no-cursor", }; /// Shell integration features diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index caa188a7d..f48dbca0d 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -812,13 +812,6 @@ const Subprocess = struct { .detect => null, .fish => .fish, .zsh => .zsh, - .@"no-cursor" => nc: { - // We add an environment variable for the shell integration - // scripts to pick up to prevent setting cursor shapes. - // Setting to "no_cursor" means we will detect the shell - try env.put("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR", "1"); - break :nc null; - }, }; const dir = opts.resources_dir orelse break :shell null; @@ -827,6 +820,7 @@ const Subprocess = struct { final_path, &env, force, + opts.full_config.@"shell-integration-features", ); }; if (shell_integrated) |shell| { diff --git a/src/termio/shell_integration.zig b/src/termio/shell_integration.zig index 6f8fe3220..08733f6ee 100644 --- a/src/termio/shell_integration.zig +++ b/src/termio/shell_integration.zig @@ -1,5 +1,6 @@ const std = @import("std"); const EnvMap = std.process.EnvMap; +const config = @import("../config.zig"); const log = std.log.scoped(.shell_integration); @@ -18,23 +19,31 @@ pub fn setup( command_path: []const u8, env: *EnvMap, force_shell: ?Shell, + features: config.ShellIntegrationFeatures, ) !?Shell { const exe = if (force_shell) |shell| switch (shell) { .fish => "/fish", .zsh => "/zsh", } else std.fs.path.basename(command_path); - if (std.mem.eql(u8, "fish", exe)) { - try setupFish(resource_dir, env); - return .fish; - } + const shell: Shell = shell: { + if (std.mem.eql(u8, "fish", exe)) { + try setupFish(resource_dir, env); + break :shell .fish; + } - if (std.mem.eql(u8, "zsh", exe)) { - try setupZsh(resource_dir, env); - return .zsh; - } + if (std.mem.eql(u8, "zsh", exe)) { + try setupZsh(resource_dir, env); + break :shell .zsh; + } - return null; + return null; + }; + + // Setup our feature env vars + if (!features.cursor) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR", "1"); + + return shell; } /// Setup the fish automatic shell integration. This works by