diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-10 21:51:57 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-10 21:51:57 +0300 |
| commit | 425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch) | |
| tree | e52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/src/termio/shell_integration.zig | |
| parent | 90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff) | |
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/src/termio/shell_integration.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/termio/shell_integration.zig | 110 |
1 files changed, 68 insertions, 42 deletions
diff --git a/vendor/libghostty-vt/src/termio/shell_integration.zig b/vendor/libghostty-vt/src/termio/shell_integration.zig index 2dd09ee2..d56a84cc 100644 --- a/vendor/libghostty-vt/src/termio/shell_integration.zig +++ b/vendor/libghostty-vt/src/termio/shell_integration.zig @@ -2,10 +2,11 @@ const std = @import("std"); const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; -const EnvMap = std.process.EnvMap; +const EnvMap = std.process.Environ.Map; const config = @import("../config.zig"); const homedir = @import("../os/homedir.zig"); const internal_os = @import("../os/main.zig"); +const global = @import("../global.zig"); const log = std.log.scoped(.shell_integration); @@ -97,7 +98,7 @@ test "force shell" { inline for (@typeInfo(Shell).@"enum".fields) |field| { const shell = @field(Shell, field.name); - var res: TmpResourcesDir = try .init(alloc, shell); + var res: TmpResourcesDir = try .init(shell); defer res.deinit(); const result = try setup( @@ -373,12 +374,12 @@ fn setupBash( "{s}/shell-integration/bash/ghostty.bash", .{resource_dir}, ); - if (std.fs.openFileAbsolute(script_path, .{})) |file| { - file.close(); + if (std.Io.Dir.openFileAbsolute(global.io(), script_path, .{})) |file| { + file.close(global.io()); try env.put("ENV", script_path); } else |err| { log.warn("unable to open {s}: {}", .{ script_path, err }); - env.remove("GHOSTTY_BASH_ENV"); + _ = env.swapRemove("GHOSTTY_BASH_ENV"); return null; } @@ -390,8 +391,10 @@ fn setupBash( // In POSIX mode, HISTFILE defaults to ~/.sh_history, so unless we're // staying in POSIX mode (--posix), change it back to ~/.bash_history. if (env.get("HISTFILE") == null) { + var environ_map = try global.environMap(); + defer environ_map.deinit(); var home_buf: [1024]u8 = undefined; - if (try homedir.home(&home_buf)) |home| { + if (try homedir.home(global.io(), &environ_map, &home_buf)) |home| { var histfile_buf: [std.fs.max_path_bytes]u8 = undefined; const histfile = try std.fmt.bufPrint( &histfile_buf, @@ -404,7 +407,7 @@ fn setupBash( } // Return a copy of our modified command line to use as the shell command. - return .{ .shell = try alloc.dupeZ(u8, try cmd.toOwnedSlice()) }; + return .{ .shell = try alloc.dupeZ(u8, cmd.buffer.written()) }; } test "bash" { @@ -413,7 +416,7 @@ test "bash" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .bash); + var res: TmpResourcesDir = try .init(.bash); defer res.deinit(); var env = EnvMap.init(alloc); @@ -436,7 +439,7 @@ test "bash: unsupported options" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .bash); + var res: TmpResourcesDir = try .init(.bash); defer res.deinit(); const cmdlines = [_][:0]const u8{ @@ -462,7 +465,7 @@ test "bash: inject flags" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .bash); + var res: TmpResourcesDir = try .init(.bash); defer res.deinit(); // bash --norc @@ -492,7 +495,7 @@ test "bash: rcfile" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .bash); + var res: TmpResourcesDir = try .init(.bash); defer res.deinit(); var env = EnvMap.init(alloc); @@ -519,7 +522,7 @@ test "bash: HISTFILE" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .bash); + var res: TmpResourcesDir = try .init(.bash); defer res.deinit(); // HISTFILE unset @@ -551,7 +554,7 @@ test "bash: ENV" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .bash); + var res: TmpResourcesDir = try .init(.bash); defer res.deinit(); var env = EnvMap.init(alloc); @@ -575,7 +578,7 @@ test "bash: additional arguments" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .bash); + var res: TmpResourcesDir = try .init(.bash); defer res.deinit(); var env = EnvMap.init(alloc); @@ -603,7 +606,7 @@ test "bash: missing resources" { var tmp_dir = testing.tmpDir(.{}); defer tmp_dir.cleanup(); - const resources_dir = try tmp_dir.dir.realpathAlloc(alloc, "."); + const resources_dir = try tmp_dir.dir.realPathFileAlloc(testing.io, ".", alloc); defer alloc.free(resources_dir); var env = EnvMap.init(alloc); @@ -633,11 +636,15 @@ fn setupXdgDataDirs( "{s}/shell-integration", .{resource_dir}, ); - var integ_dir = std.fs.openDirAbsolute(integ_path, .{}) catch |err| { + var integ_dir = std.Io.Dir.openDirAbsolute( + global.io(), + integ_path, + .{}, + ) catch |err| { log.warn("unable to open {s}: {}", .{ integ_path, err }); return false; }; - integ_dir.close(); + integ_dir.close(global.io()); // 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 @@ -659,7 +666,7 @@ fn setupXdgDataDirs( const xdg_data_dirs_key = "XDG_DATA_DIRS"; try env.put( xdg_data_dirs_key, - try internal_os.prependEnv( + try prependEnv( stack_alloc, env.get(xdg_data_dirs_key) orelse "/usr/local/share:/usr/share", integ_path, @@ -669,6 +676,23 @@ fn setupXdgDataDirs( return true; } +/// Prepend a value to an environment variable such as PATH. +/// The returned value is always allocated so it must be freed. +fn prependEnv( + alloc: Allocator, + current: []const u8, + value: []const u8, +) Allocator.Error![]u8 { + // If there is no prior value, we return it as-is + if (current.len == 0) return try alloc.dupe(u8, value); + + return try std.fmt.allocPrint(alloc, "{s}{c}{s}", .{ + value, + std.fs.path.delimiter, + current, + }); +} + test "xdg: empty XDG_DATA_DIRS" { if (builtin.os.tag == .windows) return error.SkipZigTest; @@ -678,7 +702,7 @@ test "xdg: empty XDG_DATA_DIRS" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .fish); + var res: TmpResourcesDir = try .init(.fish); defer res.deinit(); var env = EnvMap.init(alloc); @@ -706,7 +730,7 @@ test "xdg: existing XDG_DATA_DIRS" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .fish); + var res: TmpResourcesDir = try .init(.fish); defer res.deinit(); var env = EnvMap.init(alloc); @@ -736,7 +760,7 @@ test "xdg: missing resources" { var tmp_dir = testing.tmpDir(.{}); defer tmp_dir.cleanup(); - const resources_dir = try tmp_dir.dir.realpathAlloc(alloc, "."); + const resources_dir = try tmp_dir.dir.realPathFileAlloc(testing.io, ".", alloc); defer alloc.free(resources_dir); var env = EnvMap.init(alloc); @@ -815,7 +839,7 @@ fn setupNushell( } // Return a copy of our modified command line to use as the shell command. - return .{ .shell = try alloc.dupeZ(u8, try cmd.toOwnedSlice()) }; + return .{ .shell = try alloc.dupeZ(u8, cmd.buffer.written()) }; } test "nushell" { @@ -824,7 +848,7 @@ test "nushell" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .nushell); + var res: TmpResourcesDir = try .init(.nushell); defer res.deinit(); var env = EnvMap.init(alloc); @@ -850,7 +874,7 @@ test "nushell: unsupported options" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(alloc, .nushell); + var res: TmpResourcesDir = try .init(.nushell); defer res.deinit(); const cmdlines = [_][:0]const u8{ @@ -879,7 +903,7 @@ test "nushell: missing resources" { var tmp_dir = testing.tmpDir(.{}); defer tmp_dir.cleanup(); - const resources_dir = try tmp_dir.dir.realpathAlloc(alloc, "."); + const resources_dir = try tmp_dir.dir.realPathFileAlloc(testing.io, ".", alloc); defer alloc.free(resources_dir); var env = EnvMap.init(alloc); @@ -910,11 +934,15 @@ fn setupZsh( "{s}/shell-integration/zsh", .{resource_dir}, ); - var integ_dir = std.fs.openDirAbsolute(integ_path, .{}) catch |err| { + var integ_dir = std.Io.Dir.openDirAbsolute( + global.io(), + integ_path, + .{}, + ) catch |err| { log.warn("unable to open {s}: {}", .{ integ_path, err }); return null; }; - integ_dir.close(); + integ_dir.close(global.io()); try env.put("ZDOTDIR", integ_path); return try command.clone(alloc); @@ -927,7 +955,7 @@ test "zsh" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(testing.allocator, .zsh); + var res: TmpResourcesDir = try .init(.zsh); defer res.deinit(); var env = EnvMap.init(testing.allocator); @@ -946,7 +974,7 @@ test "zsh: ZDOTDIR" { defer arena.deinit(); const alloc = arena.allocator(); - var res: TmpResourcesDir = try .init(testing.allocator, .zsh); + var res: TmpResourcesDir = try .init(.zsh); defer res.deinit(); var env = EnvMap.init(testing.allocator); @@ -969,7 +997,7 @@ test "zsh: missing resources" { var tmp_dir = testing.tmpDir(.{}); defer tmp_dir.cleanup(); - const resources_dir = try tmp_dir.dir.realpathAlloc(alloc, "."); + const resources_dir = try tmp_dir.dir.realPathFileAlloc(testing.io, ".", alloc); defer alloc.free(resources_dir); var env = EnvMap.init(alloc); @@ -981,12 +1009,11 @@ test "zsh: missing resources" { /// Test helper that creates a temporary resources directory with shell integration paths. const TmpResourcesDir = struct { - allocator: Allocator, tmp_dir: std.testing.TmpDir, - path: []const u8, + path: [:0]const u8, shell_path: []const u8, - fn init(allocator: Allocator, shell: Shell) !TmpResourcesDir { + fn init(shell: Shell) !TmpResourcesDir { var tmp_dir = std.testing.tmpDir(.{}); errdefer tmp_dir.cleanup(); @@ -996,20 +1023,20 @@ const TmpResourcesDir = struct { "shell-integration/{s}", .{@tagName(shell)}, ); - try tmp_dir.dir.makePath(relative_shell_path); + try tmp_dir.dir.createDirPath(std.testing.io, relative_shell_path); - const path = try tmp_dir.dir.realpathAlloc(allocator, "."); - errdefer allocator.free(path); + const path = try tmp_dir.dir.realPathFileAlloc(std.testing.io, ".", std.testing.allocator); + errdefer std.testing.allocator.free(path); const shell_path = try std.fmt.allocPrint( - allocator, + std.testing.allocator, "{s}/{s}", .{ path, relative_shell_path }, ); - errdefer allocator.free(shell_path); + errdefer std.testing.allocator.free(shell_path); switch (shell) { - .bash => try tmp_dir.dir.writeFile(.{ + .bash => try tmp_dir.dir.writeFile(std.testing.io, .{ .sub_path = "shell-integration/bash/ghostty.bash", .data = "", }), @@ -1017,7 +1044,6 @@ const TmpResourcesDir = struct { } return .{ - .allocator = allocator, .tmp_dir = tmp_dir, .path = path, .shell_path = shell_path, @@ -1025,8 +1051,8 @@ const TmpResourcesDir = struct { } fn deinit(self: *TmpResourcesDir) void { - self.allocator.free(self.shell_path); - self.allocator.free(self.path); + std.testing.allocator.free(self.shell_path); + std.testing.allocator.free(self.path); self.tmp_dir.cleanup(); } }; |
