~jamii/focus

ref: 6ca339cc4a715b8a5bac73b4345a1f5c07c6ddfc focus/lib/focus/launcher.zig -rw-r--r-- 2.8 KiB
6ca339ccJamie Brandon Bugfixes 1 year, 5 months ago
                                                                                
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
const focus = @import("../focus.zig");
usingnamespace focus.common;
const meta = focus.meta;
const App = focus.App;
const Buffer = focus.Buffer;
const Editor = focus.Editor;
const SingleLineEditor = focus.SingleLineEditor;
const Window = focus.Window;
const style = focus.style;
const Selector = focus.Selector;

pub const Launcher = struct {
    app: *App,
    input: SingleLineEditor,
    selector: Selector,
    exes: []const []const u8,

    pub fn init(app: *App) *Launcher {
        const input = SingleLineEditor.init(app, "");
        var selector = Selector.init(app);

        var exes = ArrayList([]const u8).init(app.allocator);
        {
            const result = std.ChildProcess.exec(.{
                .allocator = app.frame_allocator,
                .argv = &[_][]const u8{ "bash", "-c", "compgen -c" },
                .cwd = "/home/jamie",
                .max_output_bytes = 128 * 1024 * 1024,
            }) catch |err| panic("{} while calling compgen", .{err});
            assert(result.term == .Exited and result.term.Exited == 0);
            var lines = std.mem.split(result.stdout, "\n");
            while (lines.next()) |line| {
                exes.append(app.dupe(line)) catch oom();
            }
        }

        const self = app.allocator.create(Launcher) catch oom();
        self.* = Launcher{
            .app = app,
            .input = input,
            .selector = selector,
            .exes = exes.toOwnedSlice(),
        };
        return self;
    }

    pub fn deinit(self: *Launcher) void {
        for (self.exes) |exe| self.app.allocator.free(exe);
        self.app.allocator.free(self.exes);
        self.selector.deinit();
        self.input.deinit();
        self.app.allocator.destroy(self);
    }

    pub fn frame(self: *Launcher, window: *Window, rect: Rect, events: []const c.SDL_Event) void {
        const layout = window.layoutSearcher(rect);

        // run input frame
        self.input.frame(window, layout.input, events);

        // filter exes
        const filtered_exes = fuzzy_search(self.app.frame_allocator, self.exes, self.input.getText());

        // run selector frame
        const action = self.selector.frame(window, layout.selector, events, filtered_exes);

        // handle action
        if (filtered_exes.len > 0 and action == .SelectOne) {
            const exe = filtered_exes[self.selector.selected];
            // TODO this is kinda hacky :D
            const command = format(self.app.frame_allocator, "{} & disown", .{exe});
            var process = std.ChildProcess.init(
                &[_][]const u8{ "bash", "-c", command },
                self.app.frame_allocator,
            ) catch |err| panic("Failed to init {}: {}", .{ command, err });
            process.spawn() catch |err| panic("Failed to spawn {}: {}", .{ command, err });
            window.close_after_frame = true;
        }
    }
};