diff options
| author | Mitchell Hashimoto <mitchell.hashimoto@gmail.com> | 2023-07-06 14:14:55 -0700 |
|---|---|---|
| committer | Mitchell Hashimoto <mitchell.hashimoto@gmail.com> | 2023-07-06 14:14:55 -0700 |
| commit | ae206b2f8957bd85e9f5e7900d6230b16258dc5c (patch) | |
| tree | a48d01b89c19e7fd36392a6960286a1cfc352e70 /src/termio/shell_integration.zig | |
| parent | 59fb3a55e378a33b854f5fc090fc9a6b56acdcc3 (diff) | |
termio: fish shell integration injection
Diffstat (limited to 'src/termio/shell_integration.zig')
| -rw-r--r-- | src/termio/shell_integration.zig | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/termio/shell_integration.zig b/src/termio/shell_integration.zig new file mode 100644 index 000000000..c941965b5 --- /dev/null +++ b/src/termio/shell_integration.zig @@ -0,0 +1,70 @@ +const std = @import("std"); +const EnvMap = std.process.EnvMap; + +const log = std.log.scoped(.shell_integration); + +/// Shell types we support +pub const Shell = enum { + fish, +}; + +/// 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. +pub fn setup( + resource_dir: []const u8, + command_path: []const u8, + env: *EnvMap, +) !?Shell { + const exe = std.fs.path.basename(command_path); + if (std.mem.eql(u8, "fish", exe)) { + try setupFish(resource_dir, env); + return .fish; + } + + return null; +} + +/// 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( + 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_DIR", integ_dir); + + if (env.get("XDG_DATA_DIRS")) |old| { + // We have an old value, We need to prepend our value to it. + + // We use a 4K buffer to hold our XDG_DATA_DIR value. The stack + // on macOS is at least 512K and Linux is 8MB or more. So this + // should fit. If the user has a XDG_DATA_DIR value that is longer + // than this then it will fail... and we will cross that bridge + // when we actually get there. This avoids us needing an allocator. + var buf: [4096]u8 = undefined; + const prepended = try std.fmt.bufPrint( + &buf, + "{s}{c}{s}", + .{ integ_dir, std.fs.path.delimiter, old }, + ); + 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); + } +} |
