Skip to content

build_runner: clear the terminal when debounce times out #23472

@weskoerber

Description

@weskoerber

When using the --watch flag and rapidly making changes, it can be difficult to identify new build outputs after several consecutive debounce timeouts:

Example
❯ zig build test --watch
test
└─ run test 2/3 passed, 1 failed
error: 'root.test.custom type' failed: /home/wes/Projects/cli-zig/src/root.zig:58:21: 0x10f5dd1 in parseArgs__anon_30471 (test)
                    return error.UnknownOption;
                    ^
/home/wes/Projects/cli-zig/src/root.zig:148:24: 0x10f6e51 in test.custom type (test)
        const result = try Cli.parseArgs(Args, &.{"--list foo,bar,baz"});
                       ^
error: while executing test 'root.test.custom type', the following test command failed:
/home/wes/Projects/cli-zig/.zig-cache/o/2a503f1eb3d0c8bd2baea20f57759aa3/test --seed=0x8ac8acda --cache-dir=/home/wes/Projects/cli-zig/.zig-cache --listen=-
Build Summary: 1/3 steps succeeded; 1 failed; 2/3 tests passed; 1 failed
test transitive failure
└─ run test 2/3 passed, 1 failed
test
└─ run test 2/3 passed, 1 failed
error: 'root.test.custom type' failed: /home/wes/Projects/cli-zig/src/root.zig:58:21: 0x10f5dd1 in parseArgs__anon_30471 (test)
                    return error.UnknownOption;
                    ^
/home/wes/Projects/cli-zig/src/root.zig:148:24: 0x10f6e51 in test.custom type (test)
        const result = try Cli.parseArgs(Args, &.{"--list foo,bar,baz"});
                       ^
error: while executing test 'root.test.custom type', the following test command failed:
/home/wes/Projects/cli-zig/.zig-cache/o/2a503f1eb3d0c8bd2baea20f57759aa3/test --seed=0x8ac8acda --cache-dir=/home/wes/Projects/cli-zig/.zig-cache --listen=-
Build Summary: 1/3 steps succeeded; 1 failed; 2/3 tests passed; 1 failed
test transitive failure
└─ run test 2/3 passed, 1 failed
test
└─ run test 2/3 passed, 1 failed
error: 'root.test.custom type' failed: /home/wes/Projects/cli-zig/src/root.zig:58:21: 0x10f5dd1 in parseArgs__anon_30471 (test)
                    return error.UnknownOption;
                    ^
/home/wes/Projects/cli-zig/src/root.zig:148:24: 0x10f6e51 in test.custom type (test)
        const result = try Cli.parseArgs(Args, &.{"--list foo,bar,baz"});
                       ^
error: while executing test 'root.test.custom type', the following test command failed:
/home/wes/Projects/cli-zig/.zig-cache/o/2a503f1eb3d0c8bd2baea20f57759aa3/test --seed=0x8ac8acda --cache-dir=/home/wes/Projects/cli-zig/.zig-cache --listen=-
Build Summary: 1/3 steps succeeded; 1 failed; 2/3 tests passed; 1 failed
test transitive failure
└─ run test 2/3 passed, 1 failed
test
└─ run test 2/3 passed, 1 failed
error: 'root.test.custom type' failed: /home/wes/Projects/cli-zig/src/root.zig:58:21: 0x10f5dd1 in parseArgs__anon_30471 (test)
                    return error.UnknownOption;
                    ^
/home/wes/Projects/cli-zig/src/root.zig:148:24: 0x10f6e51 in test.custom type (test)
        const result = try Cli.parseArgs(Args, &.{"--list foo,bar,baz"});
                       ^
error: while executing test 'root.test.custom type', the following test command failed:
/home/wes/Projects/cli-zig/.zig-cache/o/2a503f1eb3d0c8bd2baea20f57759aa3/test --seed=0x8ac8acda --cache-dir=/home/wes/Projects/cli-zig/.zig-cache --listen=-
Build Summary: 1/3 steps succeeded; 1 failed; 2/3 tests passed; 1 failed
test transitive failure
└─ run test 2/3 passed, 1 failed
watching 76 directories, 0 processes

It would be more clear and easier to follow if the terminal was cleared upon debounce timeout. This way, you're only shown the most relevant output. With Ghostty on Linux, I use the following hack in the build runner to accomplish this. Each time the project is rebuilt only the latest result is displayed:

diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig
index 6c68911e9b..39036e62d2 100644
--- a/lib/compiler/build_runner.zig
+++ b/lib/compiler/build_runner.zig
@@ -472,6 +472,7 @@ pub fn main() !void {
         var debounce_timeout: Watch.Timeout = .none;
         while (true) switch (try w.wait(gpa, debounce_timeout)) {
             .timeout => {
+                try std.io.getStdOut().writeAll("\x1B[2J\x1B[H");
                 debouncing_node.end();
                 markFailedStepsDirty(gpa, run.step_stack.keys());
                 continue :rebuild;
Example
test
└─ run test 2/3 passed, 1 failed
error: 'root.test.custom type' failed: /home/wes/Projects/cli-zig/src/root.zig:58:21: 0x10f5dd1 in parseArgs__anon_30471 (test)
                    return error.UnknownOption;
                    ^
/home/wes/Projects/cli-zig/src/root.zig:148:24: 0x10f6e51 in test.custom type (test)
        const result = try Cli.parseArgs(Args, &.{"--list foo,bar,baz"});
                       ^
error: while executing test 'root.test.custom type', the following test command failed:
/home/wes/Projects/cli-zig/.zig-cache/o/2a503f1eb3d0c8bd2baea20f57759aa3/test --seed=0x8882f54e --cache-dir=/home/wes/Projects/cli-zig/.zig-cache --listen=-
Build Summary: 1/3 steps succeeded; 1 failed; 2/3 tests passed; 1 failed
test transitive failure
└─ run test 2/3 passed, 1 failed
watching 76 directories, 0 processes

Admittedly, this is a subjective opinion. This sort of thing can be improved by using a custom build runner, but I think it would be a valuable addition to the build system. If this is too subjective, then perhaps a middle-ground where this behavior may be opted into or out of using a flag would work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions