mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Fix shell-integration-features being ignored with manual shell integration (#5048)
## Descriptions The code was short-circuiting the shell integration setup when `shell-integration = none`, which prevented the feature environment variables from being set. These environment variables are needed even for manual shell integration to work properly. ## Changes - Extracted feature environment variables setup into a separate `setup_features` function - Modified the shell integration initialization to ensure features are set up even when `shell-integration = none` <img width="1126" alt="image" src="https://github.com/user-attachments/assets/ceeb33f5-26ee-4a3b-a6d5-eed57848c96c" /> Fixes https://github.com/ghostty-org/ghostty/issues/5046
This commit is contained in:
@ -1670,7 +1670,9 @@ keybind: Keybinds = .{},
|
|||||||
/// The default value is `detect`.
|
/// The default value is `detect`.
|
||||||
@"shell-integration": ShellIntegration = .detect,
|
@"shell-integration": ShellIntegration = .detect,
|
||||||
|
|
||||||
/// Shell integration features to enable if shell integration itself is enabled.
|
/// Shell integration features to enable. These require our shell integration
|
||||||
|
/// to be loaded, either automatically via shell-integration or manually.
|
||||||
|
///
|
||||||
/// The format of this is a list of features to enable separated by commas. If
|
/// 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,
|
/// 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
|
/// its default value is used, so you must explicitly disable features you don't
|
||||||
|
@ -875,7 +875,11 @@ const Subprocess = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const force: ?shell_integration.Shell = switch (cfg.shell_integration) {
|
const force: ?shell_integration.Shell = switch (cfg.shell_integration) {
|
||||||
.none => break :shell .{ null, default_shell_command },
|
.none => {
|
||||||
|
// Even if shell integration is none, we still want to set up the feature env vars
|
||||||
|
try shell_integration.setupFeatures(&env, cfg.shell_integration_features);
|
||||||
|
break :shell .{ null, default_shell_command };
|
||||||
|
},
|
||||||
.detect => null,
|
.detect => null,
|
||||||
.bash => .bash,
|
.bash => .bash,
|
||||||
.elvish => .elvish,
|
.elvish => .elvish,
|
||||||
|
@ -58,7 +58,21 @@ pub fn setup(
|
|||||||
break :exe std.fs.path.basename(command[0..idx]);
|
break :exe std.fs.path.basename(command[0..idx]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const result: ShellIntegration = shell: {
|
const result = try setupShell(alloc_arena, resource_dir, command, env, exe);
|
||||||
|
|
||||||
|
// Setup our feature env vars
|
||||||
|
try setupFeatures(env, features);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setupShell(
|
||||||
|
alloc_arena: Allocator,
|
||||||
|
resource_dir: []const u8,
|
||||||
|
command: []const u8,
|
||||||
|
env: *EnvMap,
|
||||||
|
exe: []const u8,
|
||||||
|
) !?ShellIntegration {
|
||||||
if (std.mem.eql(u8, "bash", exe)) {
|
if (std.mem.eql(u8, "bash", exe)) {
|
||||||
// Apple distributes their own patched version of Bash 3.2
|
// Apple distributes their own patched version of Bash 3.2
|
||||||
// on macOS that disables the ENV-based POSIX startup path.
|
// on macOS that disables the ENV-based POSIX startup path.
|
||||||
@ -80,7 +94,7 @@ pub fn setup(
|
|||||||
resource_dir,
|
resource_dir,
|
||||||
env,
|
env,
|
||||||
) orelse return null;
|
) orelse return null;
|
||||||
break :shell .{
|
return .{
|
||||||
.shell = .bash,
|
.shell = .bash,
|
||||||
.command = new_command,
|
.command = new_command,
|
||||||
};
|
};
|
||||||
@ -88,7 +102,7 @@ pub fn setup(
|
|||||||
|
|
||||||
if (std.mem.eql(u8, "elvish", exe)) {
|
if (std.mem.eql(u8, "elvish", exe)) {
|
||||||
try setupXdgDataDirs(alloc_arena, resource_dir, env);
|
try setupXdgDataDirs(alloc_arena, resource_dir, env);
|
||||||
break :shell .{
|
return .{
|
||||||
.shell = .elvish,
|
.shell = .elvish,
|
||||||
.command = try alloc_arena.dupe(u8, command),
|
.command = try alloc_arena.dupe(u8, command),
|
||||||
};
|
};
|
||||||
@ -96,7 +110,7 @@ pub fn setup(
|
|||||||
|
|
||||||
if (std.mem.eql(u8, "fish", exe)) {
|
if (std.mem.eql(u8, "fish", exe)) {
|
||||||
try setupXdgDataDirs(alloc_arena, resource_dir, env);
|
try setupXdgDataDirs(alloc_arena, resource_dir, env);
|
||||||
break :shell .{
|
return .{
|
||||||
.shell = .fish,
|
.shell = .fish,
|
||||||
.command = try alloc_arena.dupe(u8, command),
|
.command = try alloc_arena.dupe(u8, command),
|
||||||
};
|
};
|
||||||
@ -104,21 +118,13 @@ pub fn setup(
|
|||||||
|
|
||||||
if (std.mem.eql(u8, "zsh", exe)) {
|
if (std.mem.eql(u8, "zsh", exe)) {
|
||||||
try setupZsh(resource_dir, env);
|
try setupZsh(resource_dir, env);
|
||||||
break :shell .{
|
return .{
|
||||||
.shell = .zsh,
|
.shell = .zsh,
|
||||||
.command = try alloc_arena.dupe(u8, command),
|
.command = try alloc_arena.dupe(u8, command),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
|
||||||
|
|
||||||
// Setup our feature env vars
|
|
||||||
if (!features.cursor) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR", "1");
|
|
||||||
if (!features.sudo) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_SUDO", "1");
|
|
||||||
if (!features.title) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_TITLE", "1");
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "force shell" {
|
test "force shell" {
|
||||||
@ -138,6 +144,58 @@ test "force shell" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Setup shell integration feature environment variables without
|
||||||
|
/// performing full shell integration setup.
|
||||||
|
pub fn setupFeatures(
|
||||||
|
env: *EnvMap,
|
||||||
|
features: config.ShellIntegrationFeatures,
|
||||||
|
) !void {
|
||||||
|
if (!features.cursor) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR", "1");
|
||||||
|
if (!features.sudo) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_SUDO", "1");
|
||||||
|
if (!features.title) try env.put("GHOSTTY_SHELL_INTEGRATION_NO_TITLE", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "setup features" {
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
const alloc = arena.allocator();
|
||||||
|
|
||||||
|
// Test: all features enabled (no environment variables should be set)
|
||||||
|
{
|
||||||
|
var env = EnvMap.init(alloc);
|
||||||
|
defer env.deinit();
|
||||||
|
|
||||||
|
try setupFeatures(&env, .{ .cursor = true, .sudo = true, .title = true });
|
||||||
|
try testing.expect(env.get("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR") == null);
|
||||||
|
try testing.expect(env.get("GHOSTTY_SHELL_INTEGRATION_NO_SUDO") == null);
|
||||||
|
try testing.expect(env.get("GHOSTTY_SHELL_INTEGRATION_NO_TITLE") == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test: all features disabled
|
||||||
|
{
|
||||||
|
var env = EnvMap.init(alloc);
|
||||||
|
defer env.deinit();
|
||||||
|
|
||||||
|
try setupFeatures(&env, .{ .cursor = false, .sudo = false, .title = false });
|
||||||
|
try testing.expectEqualStrings("1", env.get("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR").?);
|
||||||
|
try testing.expectEqualStrings("1", env.get("GHOSTTY_SHELL_INTEGRATION_NO_SUDO").?);
|
||||||
|
try testing.expectEqualStrings("1", env.get("GHOSTTY_SHELL_INTEGRATION_NO_TITLE").?);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test: mixed features
|
||||||
|
{
|
||||||
|
var env = EnvMap.init(alloc);
|
||||||
|
defer env.deinit();
|
||||||
|
|
||||||
|
try setupFeatures(&env, .{ .cursor = false, .sudo = true, .title = false });
|
||||||
|
try testing.expectEqualStrings("1", env.get("GHOSTTY_SHELL_INTEGRATION_NO_CURSOR").?);
|
||||||
|
try testing.expect(env.get("GHOSTTY_SHELL_INTEGRATION_NO_SUDO") == null);
|
||||||
|
try testing.expectEqualStrings("1", env.get("GHOSTTY_SHELL_INTEGRATION_NO_TITLE").?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Setup the bash automatic shell integration. This works by
|
/// Setup the bash automatic shell integration. This works by
|
||||||
/// starting bash in POSIX mode and using the ENV environment
|
/// starting bash in POSIX mode and using the ENV environment
|
||||||
/// variable to load our bash integration script. This prevents
|
/// variable to load our bash integration script. This prevents
|
||||||
|
Reference in New Issue
Block a user