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/TempDir.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (diff) | |
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/os/TempDir.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/os/TempDir.zig | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/os/TempDir.zig b/vendor/libghostty-vt/src/os/TempDir.zig new file mode 100644 index 00000000..2ddf18da --- /dev/null +++ b/vendor/libghostty-vt/src/os/TempDir.zig @@ -0,0 +1,95 @@ +//! Creates a temporary directory at runtime that can be safely used to +//! store temporary data and is destroyed on deinit. +const TempDir = @This(); + +const std = @import("std"); +const testing = std.testing; +const Dir = std.fs.Dir; +const allocTmpDir = @import("file.zig").allocTmpDir; +const freeTmpDir = @import("file.zig").freeTmpDir; + +const log = std.log.scoped(.tempdir); + +/// Dir is the directory handle +dir: Dir, + +/// Parent directory +parent: Dir, + +/// Name buffer that name points into. Generally do not use. To get the +/// name call the name() function. +name_buf: [TMP_PATH_LEN:0]u8, + +/// Create the temporary directory. +pub fn init() !TempDir { + // Note: the tmp_path_buf sentinel is important because it ensures + // we actually always have TMP_PATH_LEN+1 bytes of available space. We + // need that so we can set the sentinel in the case we use all the + // possible length. + var tmp_path_buf: [TMP_PATH_LEN:0]u8 = undefined; + var rand_buf: [RANDOM_BYTES]u8 = undefined; + + const dir = dir: { + const cwd = std.fs.cwd(); + const tmp_dir = allocTmpDir(std.heap.page_allocator) orelse break :dir cwd; + defer freeTmpDir(std.heap.page_allocator, tmp_dir); + break :dir try cwd.openDir(tmp_dir, .{}); + }; + + // We now loop forever until we can find a directory that we can create. + while (true) { + std.crypto.random.bytes(rand_buf[0..]); + const tmp_path = b64_encoder.encode(&tmp_path_buf, &rand_buf); + tmp_path_buf[tmp_path.len] = 0; + + dir.makeDir(tmp_path) catch |err| switch (err) { + error.PathAlreadyExists => continue, + else => |e| return e, + }; + + return TempDir{ + .dir = try dir.openDir(tmp_path, .{}), + .parent = dir, + .name_buf = tmp_path_buf, + }; + } +} + +/// Name returns the name of the directory. This is just the basename +/// and is not the full absolute path. +pub fn name(self: *TempDir) []const u8 { + return std.mem.sliceTo(&self.name_buf, 0); +} + +/// Finish with the temporary directory. This deletes all contents in the +/// directory. +pub fn deinit(self: *TempDir) void { + self.dir.close(); + self.parent.deleteTree(self.name()) catch |err| + log.err("error deleting temp dir err={}", .{err}); +} + +// The amount of random bytes to get to determine our filename. +const RANDOM_BYTES = 16; +const TMP_PATH_LEN = b64_encoder.calcSize(RANDOM_BYTES); + +// Base64 encoder, replacing the standard `+/` with `-_` so that it can +// be used in a file name on any filesystem. +const b64_encoder = std.base64.Base64Encoder.init(b64_alphabet, null); +const b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*; + +test { + var td = try init(); + errdefer td.deinit(); + + const nameval = td.name(); + try testing.expect(nameval.len > 0); + + // Can open a new handle to it proves it exists. + var dir = try td.parent.openDir(nameval, .{}); + dir.close(); + + // Should be deleted after we deinit + td.deinit(); + try testing.expectError(error.FileNotFound, td.parent.openDir(nameval, .{})); +} |
