aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/libghostty-vt/src/crash/dir.zig
blob: 0f877ee32e3377548899617f9c52d7776a1ea735 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
const std = @import("std");
const Allocator = std.mem.Allocator;
const internal_os = @import("../os/main.zig");

/// Returns a Dir for the default directory. The Dir.path field must be
/// freed with the given allocator.
pub fn defaultDir(io: std.Io, alloc: Allocator, environ_map: *const std.process.Environ.Map) !Dir {
    const crash_dir = try internal_os.xdg.state(io, alloc, environ_map, .{ .subdir = "ghostty/crash" });
    errdefer alloc.free(crash_dir);
    return .{ .path = crash_dir };
}

pub const Dir = struct {
    /// The directory where crash reports are stored. This memory is owned
    /// by the caller.
    path: []const u8,

    /// Returns an iterator over the crash reports in this directory. This
    /// iterator must be freed with `ReportIterator.deinit`. The iterator
    /// may have no reports.
    pub fn iterator(self: *const Dir, io: std.Io) !ReportIterator {
        var dir = std.Io.Dir.openDirAbsolute(
            io,
            self.path,
            .{ .iterate = true },
        ) catch return .{};
        errdefer dir.close(io);

        return .{
            .dir = dir,
            .it = dir.iterate(),
        };
    }
};

pub const ReportIterator = struct {
    dir: ?std.Io.Dir = null,
    it: std.Io.Dir.Iterator = undefined,

    pub fn deinit(self: *ReportIterator, io: std.Io) void {
        if (self.dir) |dir| dir.close(io);
    }

    pub fn next(self: *ReportIterator, io: std.Io) !?Report {
        // If we have no dir then we failed to open the directory.
        const dir = self.dir orelse return null;

        // Get the next file entry, if any.
        const entry = entry: while (true) {
            const entry = try self.it.next(io) orelse return null;
            if (entry.kind != .file) continue;
            break :entry entry;
        };

        const stat = try dir.statFile(io, entry.name, .{});
        return .{
            .name = entry.name,
            .mtime = stat.mtime.toNanoseconds(),
        };
    }
};

pub const Report = struct {
    name: []const u8,
    mtime: i128,
};