diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/os/env.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/os/env.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/os/env.zig | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/os/env.zig b/vendor/libghostty-vt/src/os/env.zig new file mode 100644 index 00000000..8f01a14d --- /dev/null +++ b/vendor/libghostty-vt/src/os/env.zig @@ -0,0 +1,178 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const Allocator = std.mem.Allocator; +const posix = std.posix; +const isFlatpak = @import("flatpak.zig").isFlatpak; + +pub const Error = Allocator.Error; + +/// Get the environment map. +pub fn getEnvMap(alloc: Allocator) !std.process.EnvMap { + return if (isFlatpak()) + std.process.EnvMap.init(alloc) + else + try std.process.getEnvMap(alloc); +} + +/// Append a value to an environment variable such as PATH. +/// The returned value is always allocated so it must be freed. +pub fn appendEnv( + alloc: Allocator, + current: []const u8, + value: []const u8, +) Error![]u8 { + // If there is no prior value, we return it as-is + if (current.len == 0) return try alloc.dupe(u8, value); + + // Otherwise we must prefix. + return try appendEnvAlways(alloc, current, value); +} + +/// Always append value to environment, even when it is empty. +/// This is useful because some env vars (like MANPATH) want there +/// to be an empty prefix to preserve existing values. +/// +/// The returned value is always allocated so it must be freed. +pub fn appendEnvAlways( + alloc: Allocator, + current: []const u8, + value: []const u8, +) Error![]u8 { + return try std.fmt.allocPrint(alloc, "{s}{c}{s}", .{ + current, + std.fs.path.delimiter, + value, + }); +} + +/// Prepend a value to an environment variable such as PATH. +/// The returned value is always allocated so it must be freed. +pub fn prependEnv( + alloc: Allocator, + current: []const u8, + value: []const u8, +) 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, + }); +} + +/// The result of getenv, with a shared deinit to properly handle allocation +/// on Windows. +pub const GetEnvResult = struct { + value: []const u8, + + pub fn deinit(self: GetEnvResult, alloc: Allocator) void { + switch (builtin.os.tag) { + .windows => alloc.free(self.value), + else => {}, + } + } +}; + +/// Gets the value of an environment variable, or null if not found. +/// This will allocate on Windows but not on other platforms. The returned +/// value should have deinit called to do the proper cleanup no matter what +/// platform you are on. +pub fn getenv(alloc: Allocator, key: []const u8) Error!?GetEnvResult { + return switch (builtin.os.tag) { + // Non-Windows doesn't need to allocate + else => if (posix.getenv(key)) |v| .{ .value = v } else null, + + // Windows needs to allocate + .windows => if (std.process.getEnvVarOwned(alloc, key)) |v| .{ + .value = v, + } else |err| switch (err) { + error.EnvironmentVariableNotFound => null, + error.InvalidWtf8 => null, + else => |e| e, + }, + }; +} + +/// Gets the value of an environment variable. Returns null if not found or the +/// value is empty. This will allocate on Windows but not on other platforms. +/// The returned value should have deinit called to do the proper cleanup no +/// matter what platform you are on. +pub fn getenvNotEmpty(alloc: Allocator, key: []const u8) !?GetEnvResult { + const result_ = try getenv(alloc, key); + if (result_) |result| { + if (result.value.len == 0) { + result.deinit(alloc); + return null; + } + } + return result_; +} + +pub fn setenv(key: [:0]const u8, value: [:0]const u8) c_int { + return switch (builtin.os.tag) { + .windows => c._putenv_s(key.ptr, value.ptr), + else => c.setenv(key.ptr, value.ptr, 1), + }; +} + +pub fn unsetenv(key: [:0]const u8) c_int { + return switch (builtin.os.tag) { + .windows => c._putenv_s(key.ptr, ""), + else => c.unsetenv(key.ptr), + }; +} + +const c = struct { + // POSIX + extern "c" fn setenv(name: ?[*]const u8, value: ?[*]const u8, overwrite: c_int) c_int; + extern "c" fn unsetenv(name: ?[*]const u8) c_int; + + // Windows + extern "c" fn _putenv_s(varname: ?[*]const u8, value_string: ?[*]const u8) c_int; +}; + +test "appendEnv empty" { + const testing = std.testing; + const alloc = testing.allocator; + + const result = try appendEnv(alloc, "", "foo"); + defer alloc.free(result); + try testing.expectEqualStrings(result, "foo"); +} + +test "appendEnv existing" { + const testing = std.testing; + const alloc = testing.allocator; + + const result = try appendEnv(alloc, "a:b", "foo"); + defer alloc.free(result); + if (builtin.os.tag == .windows) { + try testing.expectEqualStrings(result, "a:b;foo"); + } else { + try testing.expectEqualStrings(result, "a:b:foo"); + } +} + +test "prependEnv empty" { + const testing = std.testing; + const alloc = testing.allocator; + + const result = try prependEnv(alloc, "", "foo"); + defer alloc.free(result); + try testing.expectEqualStrings(result, "foo"); +} + +test "prependEnv existing" { + const testing = std.testing; + const alloc = testing.allocator; + + const result = try prependEnv(alloc, "a:b", "foo"); + defer alloc.free(result); + if (builtin.os.tag == .windows) { + try testing.expectEqualStrings(result, "foo;a:b"); + } else { + try testing.expectEqualStrings(result, "foo:a:b"); + } +} |
