Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions lib/std/Progress.zig
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,17 @@ pub fn start(options: Options) Node {
posix.sigaction(posix.SIG.WINCH, &act, null);
}

std.io.tty.setInterruptSignalHandler(struct {
fn interrupt_signal_handler() void {
switch (global_progress.terminal_mode) {
.off => unreachable, // handled a few lines above
.ansi_escape_codes => clearWrittenWithEscapeCodes() catch {},
.windows_api => if (is_windows) clearWrittenWindowsApi() catch {} else unreachable,
}
std.process.exit(1);
}
}.interrupt_signal_handler) catch {};

if (switch (global_progress.terminal_mode) {
.off => unreachable, // handled a few lines above
.ansi_escape_codes => std.Thread.spawn(.{}, updateThreadRun, .{}),
Expand Down
40 changes: 40 additions & 0 deletions lib/std/io/tty.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,46 @@ const process = std.process;
const windows = std.os.windows;
const native_os = builtin.os.tag;

/// Registers a global handler function to run if an interrupt signal is catched.
/// An interrupt signal is usually fired if Ctrl+C is pressed in the terminal that controls the process.
///
/// Because this handler won't run if Ctrl+C isn't pressed by the user, registering this handler failed,
/// or the handler was overwritten by another setInterruptSignalHandler call,
/// this should be used only for non-critical cleanups or resets of terminal state and such.
///
/// A program can only have one handler at a time.
///
/// The handler will not exit the program after it runs.
pub fn setInterruptSignalHandler(comptime handler: *const fn () void) error{Unexpected}!void {
if (builtin.os.tag == .windows) {
const handler_routine = struct {
fn handler_routine(dwCtrlType: windows.DWORD) callconv(windows.WINAPI) windows.BOOL {
if (dwCtrlType == windows.CTRL_C_EVENT) {
handler();
return windows.TRUE;
} else {
// Ignore this event.
return windows.FALSE;
}
}
}.handler_routine;
try windows.SetConsoleCtrlHandler(handler_routine, true);
} else {
const internal_handler = struct {
fn internal_handler(sig: c_int) callconv(.C) void {
std.debug.assert(sig == std.posix.SIG.INT);
handler();
}
}.internal_handler;
const act = std.posix.Sigaction{
.handler = .{ .handler = internal_handler },
.mask = std.posix.empty_sigset,
.flags = 0,
};
std.posix.sigaction(std.posix.SIG.INT, &act, null);
}
}

/// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
/// This includes feature checks for ANSI escape codes and the Windows console API, as well as
/// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
Expand Down