mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00

This adds a new option to the shell integration feature set, `no-title`. If this option is set, the shell integration will not automatically update the window title.
126 lines
4.0 KiB
Zig
126 lines
4.0 KiB
Zig
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
const EnvMap = std.process.EnvMap;
|
|
const config = @import("../config.zig");
|
|
|
|
const log = std.log.scoped(.shell_integration);
|
|
|
|
/// Shell types we support
|
|
pub const Shell = enum {
|
|
fish,
|
|
zsh,
|
|
};
|
|
|
|
/// Setup the command execution environment for automatic
|
|
/// integrated shell integration. This returns true if shell
|
|
/// integration was successful. False could mean many things:
|
|
/// the shell type wasn't detected, etc.
|
|
///
|
|
/// The allocator is only used for temporary values, so it should
|
|
/// be given a general purpose allocator. No allocated memory remains
|
|
/// after this function returns except anything allocated by the
|
|
/// EnvMap.
|
|
pub fn setup(
|
|
alloc: Allocator,
|
|
resource_dir: []const u8,
|
|
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);
|
|
|
|
const shell: Shell = shell: {
|
|
if (std.mem.eql(u8, "fish", exe)) {
|
|
try setupFish(alloc, resource_dir, env);
|
|
break :shell .fish;
|
|
}
|
|
|
|
if (std.mem.eql(u8, "zsh", exe)) {
|
|
try setupZsh(resource_dir, env);
|
|
break :shell .zsh;
|
|
}
|
|
|
|
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 shell;
|
|
}
|
|
|
|
/// Setup the fish automatic shell integration. This works by
|
|
/// modify XDG_DATA_DIRS to include the resource directory.
|
|
/// Fish will automatically load configuration in XDG_DATA_DIRS
|
|
/// "fish/vendor_conf.d/*.fish".
|
|
fn setupFish(
|
|
alloc_gpa: Allocator,
|
|
resource_dir: []const u8,
|
|
env: *EnvMap,
|
|
) !void {
|
|
var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
|
|
|
// Get our path to the shell integration directory.
|
|
const integ_dir = try std.fmt.bufPrint(
|
|
&path_buf,
|
|
"{s}/shell-integration",
|
|
.{resource_dir},
|
|
);
|
|
|
|
// Set an env var so we can remove this from XDG_DATA_DIRS later.
|
|
// This happens in the shell integration config itself. We do this
|
|
// so that our modifications don't interfere with other commands.
|
|
try env.put("GHOSTTY_FISH_XDG_DIR", integ_dir);
|
|
|
|
if (env.get("XDG_DATA_DIRS")) |old| {
|
|
// We have an old value, We need to prepend our value to it.
|
|
|
|
// We attempt to avoid allocating by using the stack up to 4K.
|
|
// Max stack size is considerably larger on macOS and Linux but
|
|
// 4K is a reasonable size for this for most cases. However, env
|
|
// vars can be significantly larger so if we have to we fall
|
|
// back to a heap allocated value.
|
|
var stack_alloc = std.heap.stackFallback(4096, alloc_gpa);
|
|
const alloc = stack_alloc.get();
|
|
const prepended = try std.fmt.allocPrint(
|
|
alloc,
|
|
"{s}{c}{s}",
|
|
.{ integ_dir, std.fs.path.delimiter, old },
|
|
);
|
|
defer alloc.free(prepended);
|
|
|
|
try env.put("XDG_DATA_DIRS", prepended);
|
|
} else {
|
|
// No XDG_DATA_DIRS set, we just set it our desired value.
|
|
try env.put("XDG_DATA_DIRS", integ_dir);
|
|
}
|
|
}
|
|
|
|
/// Setup the zsh automatic shell integration. This works by setting
|
|
/// ZDOTDIR to our resources dir so that zsh will load our config. This
|
|
/// config then loads the true user config.
|
|
fn setupZsh(
|
|
resource_dir: []const u8,
|
|
env: *EnvMap,
|
|
) !void {
|
|
// Preserve the old zdotdir value so we can recover it.
|
|
if (env.get("ZDOTDIR")) |old| {
|
|
try env.put("GHOSTTY_ZSH_ZDOTDIR", old);
|
|
}
|
|
|
|
// Set our new ZDOTDIR
|
|
var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
|
const integ_dir = try std.fmt.bufPrint(
|
|
&path_buf,
|
|
"{s}/shell-integration/zsh",
|
|
.{resource_dir},
|
|
);
|
|
try env.put("ZDOTDIR", integ_dir);
|
|
}
|