Просмотр исходного кода

Implement demo for streaming output (which breaks all commands)

Commands are broken/disabled on purpose, because we have to reimplement
them anyways and without this test case I wasn't getting anywhere.
Luna Stadler лет назад: 4
Родитель
Сommit
5e40d7b1d2
1 измененных файлов с 37 добавлено и 23 удалено
  1. 37 23
      zig/sdl/hello_sdl.zig

+ 37 - 23
zig/sdl/hello_sdl.zig

16
});
16
});
17
const std = @import("std");
17
const std = @import("std");
18
18
19
// TODO: incremental output (e.g. for ag)
20
// TODO: instant output (for some commands like `py ...`, `go ...`, qcalc)
19
// TODO: instant output (for some commands like `py ...`, `go ...`, qcalc)
21
20
22
// commands wishlist:
21
// commands wishlist:
33
// incremental output vs. final output/action
32
// incremental output vs. final output/action
34
33
35
const ProcessWithOutput = struct {
34
const ProcessWithOutput = struct {
36
    process: std.ChildProcess,
37
    stdout: *std.ArrayList(u8),
38
    stderr: *std.ArrayList(u8),
35
    process: *std.ChildProcess,
36
    stdout_buf: std.ArrayList(u8),
37
    stderr_buf: std.ArrayList(u8),
39
38
40
    dead_fds: usize,
41
    max_output_bytes: usize,
39
    dead_fds: usize = 0,
40
    max_output_bytes: usize = 50 * 1024,
42
41
43
    fn spawn(allocator: std.Allocator, argv: [][]u8, max_output_bytes: usize) ProcessWithOutput {
42
    cleanup_done: bool = false,
43
44
    fn spawn(allocator: *std.mem.Allocator, argv: []const []const u8, max_output_bytes: usize) !ProcessWithOutput {
44
        const child = try std.ChildProcess.init(argv, allocator);
45
        const child = try std.ChildProcess.init(argv, allocator);
45
        child.stdin_behavior = std.ChildProcess.Ignore;
46
        child.stdout_behavior = std.ChildProcess.Pipe;
47
        child.stderr_behavior = std.ChildProcess.Pipe;
46
        child.stdin_behavior = std.ChildProcess.StdIo.Ignore;
47
        child.stdout_behavior = std.ChildProcess.StdIo.Pipe;
48
        child.stderr_behavior = std.ChildProcess.StdIo.Pipe;
48
        try child.spawn();
49
        try child.spawn();
49
50
50
        return ProcessWithOutput{ .process = child, .stdout = std.ArrayList(u8).init(allocator), .stderr = std.ArrayList(u8).init(allocator), .dead_fds = 0, .max_output_bytes = max_output_bytes };
51
        return ProcessWithOutput{ .process = child, .stdout_buf = std.ArrayList(u8).init(allocator), .stderr_buf = std.ArrayList(u8).init(allocator), .dead_fds = 0, .max_output_bytes = max_output_bytes };
51
    }
52
    }
52
53
53
    fn is_running(self: ProcessWithOutput) bool {
54
    fn is_running(self: *ProcessWithOutput) bool {
54
        if (self.process.term) |_| {
55
        if (self.process.term) |_| {
55
            return false;
56
            return false;
56
        } else {
57
        } else {
59
    }
60
    }
60
61
61
    fn stdout(self: ProcessWithOutput) []u8 {
62
    fn stdout(self: ProcessWithOutput) []u8 {
62
        return self.stdout.allocatedSlice();
63
        return self.stdout_buf.items;
63
    }
64
    }
64
65
65
    fn stderr(self: ProcessWithOutput) []u8 {
66
    fn stderr(self: ProcessWithOutput) []u8 {
66
        return self.stdout.allocatedSlice();
67
        return self.stderr_buf.items;
67
    }
68
    }
68
69
69
    // poll: https://github.com/ziglang/zig/blob/master/lib/std/child_process.zig#L206
70
    // poll: https://github.com/ziglang/zig/blob/master/lib/std/child_process.zig#L206
70
    //   basically do one iteration with no blocking each time it runs and thus get the output incrementally?
71
    //   basically do one iteration with no blocking each time it runs and thus get the output incrementally?
71
    fn poll(self: ProcessWithOutput) !void {
72
    fn poll(self: *ProcessWithOutput) !void {
72
        if (!self.is_running()) {
73
        if (!self.is_running()) {
73
            return;
74
            return;
74
        }
75
        }
102
        // check if there's some data waiting to be read first.
103
        // check if there's some data waiting to be read first.
103
        if (poll_fds[0].revents & std.os.POLL.IN != 0) {
104
        if (poll_fds[0].revents & std.os.POLL.IN != 0) {
104
            // stdout is ready.
105
            // stdout is ready.
105
            const new_capacity = std.math.min(self.stdout.items.len + bump_amt, self.max_output_bytes);
106
            try self.stdout.ensureTotalCapacity(new_capacity);
107
            const buf = self.stdout.unusedCapacitySlice();
106
            const new_capacity = std.math.min(self.stdout_buf.items.len + bump_amt, self.max_output_bytes);
107
            try self.stdout_buf.ensureTotalCapacity(new_capacity);
108
            const buf = self.stdout_buf.unusedCapacitySlice();
108
            if (buf.len == 0) return error.StdoutStreamTooLong;
109
            if (buf.len == 0) return error.StdoutStreamTooLong;
109
            const nread = try std.os.read(poll_fds[0].fd, buf);
110
            const nread = try std.os.read(poll_fds[0].fd, buf);
110
            self.stdout.items.len += nread;
111
            self.stdout_buf.items.len += nread;
111
112
112
            // Remove the fd when the EOF condition is met.
113
            // Remove the fd when the EOF condition is met.
113
            remove_stdout = nread == 0;
114
            remove_stdout = nread == 0;
117
118
118
        if (poll_fds[1].revents & std.os.POLL.IN != 0) {
119
        if (poll_fds[1].revents & std.os.POLL.IN != 0) {
119
            // stderr is ready.
120
            // stderr is ready.
120
            const new_capacity = std.math.min(self.stderr.items.len + bump_amt, self.max_output_bytes);
121
            try self.stderr.ensureTotalCapacity(new_capacity);
122
            const buf = self.stderr.unusedCapacitySlice();
121
            const new_capacity = std.math.min(self.stderr_buf.items.len + bump_amt, self.max_output_bytes);
122
            try self.stderr_buf.ensureTotalCapacity(new_capacity);
123
            const buf = self.stderr_buf.unusedCapacitySlice();
123
            if (buf.len == 0) return error.StderrStreamTooLong;
124
            if (buf.len == 0) return error.StderrStreamTooLong;
124
            const nread = try std.os.read(poll_fds[1].fd, buf);
125
            const nread = try std.os.read(poll_fds[1].fd, buf);
125
            self.stderr.items.len += nread;
126
            self.stderr_buf.items.len += nread;
126
127
127
            // Remove the fd when the EOF condition is met.
128
            // Remove the fd when the EOF condition is met.
128
            remove_stderr = nread == 0;
129
            remove_stderr = nread == 0;
140
            self.dead_fds += 1;
141
            self.dead_fds += 1;
141
        }
142
        }
142
    }
143
    }
144
145
    fn deinit(self: *ProcessWithOutput) void {
146
        self.stdout_buf.deinit();
147
        self.stderr_buf.deinit();
148
        self.process.deinit();
149
    }
143
};
150
};
144
151
145
const RegexRunner = struct {
152
const RegexRunner = struct {
238
245
239
    c.SDL_StartTextInput();
246
    c.SDL_StartTextInput();
240
247
248
    var process = &try ProcessWithOutput.spawn(gpa, &[_][]const u8{ "ag", "\\bshit\\b", "/usr/include" }, 1024 * 1024);
249
241
    var quit = false;
250
    var quit = false;
242
    var skip: i32 = 0;
251
    var skip: i32 = 0;
243
    var num_lines: i32 = 0;
252
    var num_lines: i32 = 0;
387
                line = lines.next();
396
                line = lines.next();
388
            }
397
            }
389
        }
398
        }
399
400
        try process.poll();
401
        std.debug.print("{s} {d} {d}\n", .{ process.is_running(), process.stdout_buf.items.len, process.stdout_buf.capacity });
402
        lines = std.mem.split(u8, process.stdout(), "\n");
403
        line = lines.next();
390
        while (line != null and i * glyph_height < window_height) {
404
        while (line != null and i * glyph_height < window_height) {
391
            const line_c = try gpa.dupeZ(u8, line.?);
405
            const line_c = try gpa.dupeZ(u8, line.?);
392
            // TODO: render tabs at correct width (or some width at least)
406
            // TODO: render tabs at correct width (or some width at least)