Skip to content

Commit

Permalink
std: Move std.debug.{TTY.Config,detectTTYConfig} to std.io.tty
Browse files Browse the repository at this point in the history
Also get rid of the TTY wrapper struct, which was exlusively used as a
namespace - this is done by the tty.zig root struct now.

detectTTYConfig has been renamed to just detectConfig, which is enough
given the new namespace. Additionally, a doc comment had been added.
  • Loading branch information
linusg committed May 24, 2023
1 parent 39c2eee commit 0f6fa3f
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 144 deletions.
12 changes: 6 additions & 6 deletions lib/build_runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ const Run = struct {

claimed_rss: usize,
enable_summary: ?bool,
ttyconf: std.debug.TTY.Config,
ttyconf: std.io.tty.Config,
stderr: std.fs.File,
};

Expand Down Expand Up @@ -535,7 +535,7 @@ const PrintNode = struct {
last: bool = false,
};

fn printPrefix(node: *PrintNode, stderr: std.fs.File, ttyconf: std.debug.TTY.Config) !void {
fn printPrefix(node: *PrintNode, stderr: std.fs.File, ttyconf: std.io.tty.Config) !void {
const parent = node.parent orelse return;
if (parent.parent == null) return;
try printPrefix(parent, stderr, ttyconf);
Expand All @@ -553,7 +553,7 @@ fn printTreeStep(
b: *std.Build,
s: *Step,
stderr: std.fs.File,
ttyconf: std.debug.TTY.Config,
ttyconf: std.io.tty.Config,
parent_node: *PrintNode,
step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
) !void {
Expand Down Expand Up @@ -1026,15 +1026,15 @@ fn cleanExit() void {

const Color = enum { auto, off, on };

fn get_tty_conf(color: Color, stderr: std.fs.File) std.debug.TTY.Config {
fn get_tty_conf(color: Color, stderr: std.fs.File) std.io.tty.Config {
return switch (color) {
.auto => std.debug.detectTTYConfig(stderr),
.auto => std.io.tty.detectConfig(stderr),
.on => .escape_codes,
.off => .no_color,
};
}

fn renderOptions(ttyconf: std.debug.TTY.Config) std.zig.ErrorBundle.RenderOptions {
fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
return .{
.ttyconf = ttyconf,
.include_source_line = ttyconf != .no_color,
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1712,7 +1712,7 @@ fn dumpBadGetPathHelp(
s.name,
});

const tty_config = std.debug.detectTTYConfig(stderr);
const tty_config = std.io.tty.detectConfig(stderr);
tty_config.setColor(w, .red) catch {};
try stderr.writeAll(" The step was created by this stack trace:\n");
tty_config.setColor(w, .reset) catch {};
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/Step.zig
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub fn dump(step: *Step) void {

const stderr = std.io.getStdErr();
const w = stderr.writer();
const tty_config = std.debug.detectTTYConfig(stderr);
const tty_config = std.io.tty.detectConfig(stderr);
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
@errorName(err),
Expand Down
2 changes: 1 addition & 1 deletion lib/std/builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub const StackTrace = struct {
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
return writer.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
};
const tty_config = std.debug.detectTTYConfig(std.io.getStdErr());
const tty_config = std.io.tty.detectConfig(std.io.getStdErr());
try writer.writeAll("\n");
std.debug.writeStackTrace(self, writer, arena.allocator(), debug_info, tty_config) catch |err| {
try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)});
Expand Down
137 changes: 11 additions & 126 deletions lib/std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const mem = std.mem;
const io = std.io;
const os = std.os;
const fs = std.fs;
const process = std.process;
const testing = std.testing;
const elf = std.elf;
const DW = std.dwarf;
Expand Down Expand Up @@ -109,31 +108,6 @@ pub fn getSelfDebugInfo() !*DebugInfo {
}
}

pub fn detectTTYConfig(file: std.fs.File) TTY.Config {
if (builtin.os.tag == .wasi) {
// Per https://github.com/WebAssembly/WASI/issues/162 ANSI codes
// aren't currently supported.
return .no_color;
} else if (process.hasEnvVarConstant("ZIG_DEBUG_COLOR")) {
return .escape_codes;
} else if (process.hasEnvVarConstant("NO_COLOR")) {
return .no_color;
} else if (file.supportsAnsiEscapeCodes()) {
return .escape_codes;
} else if (native_os == .windows and file.isTty()) {
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) {
// TODO: Should this return an error instead?
return .no_color;
}
return .{ .windows_api = .{
.handle = file.handle,
.reset_attributes = info.wAttributes,
} };
}
return .no_color;
}

/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
/// TODO multithreaded awareness
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
Expand All @@ -154,7 +128,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
return;
};
writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| {
writeCurrentStackTrace(stderr, debug_info, io.tty.detectConfig(io.getStdErr()), start_addr) catch |err| {
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
return;
};
Expand Down Expand Up @@ -182,7 +156,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
return;
};
const tty_config = detectTTYConfig(io.getStdErr());
const tty_config = io.tty.detectConfig(io.getStdErr());
if (native_os == .windows) {
writeCurrentStackTraceWindows(stderr, debug_info, tty_config, ip) catch return;
return;
Expand Down Expand Up @@ -265,7 +239,7 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void {
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
return;
};
writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig(io.getStdErr())) catch |err| {
writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, io.tty.detectConfig(io.getStdErr())) catch |err| {
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
return;
};
Expand Down Expand Up @@ -403,7 +377,7 @@ pub fn writeStackTrace(
out_stream: anytype,
allocator: mem.Allocator,
debug_info: *DebugInfo,
tty_config: TTY.Config,
tty_config: io.tty.Config,
) !void {
_ = allocator;
if (builtin.strip_debug_info) return error.MissingDebugInfo;
Expand Down Expand Up @@ -562,7 +536,7 @@ pub const StackIterator = struct {
pub fn writeCurrentStackTrace(
out_stream: anytype,
debug_info: *DebugInfo,
tty_config: TTY.Config,
tty_config: io.tty.Config,
start_addr: ?usize,
) !void {
if (native_os == .windows) {
Expand Down Expand Up @@ -634,7 +608,7 @@ pub noinline fn walkStackWindows(addresses: []usize) usize {
pub fn writeCurrentStackTraceWindows(
out_stream: anytype,
debug_info: *DebugInfo,
tty_config: TTY.Config,
tty_config: io.tty.Config,
start_addr: ?usize,
) !void {
var addr_buf: [1024]usize = undefined;
Expand All @@ -651,95 +625,6 @@ pub fn writeCurrentStackTraceWindows(
}
}

/// Provides simple functionality for manipulating the terminal in some way,
/// for debugging purposes, such as coloring text, etc.
pub const TTY = struct {
pub const Color = enum {
red,
green,
yellow,
cyan,
white,
dim,
bold,
reset,
};

pub const Config = union(enum) {
no_color,
escape_codes,
windows_api: if (native_os == .windows) WindowsContext else void,

pub const WindowsContext = struct {
handle: File.Handle,
reset_attributes: u16,
};

pub fn setColor(conf: Config, out_stream: anytype, color: Color) !void {
nosuspend switch (conf) {
.no_color => return,
.escape_codes => {
const color_string = switch (color) {
.red => "\x1b[31;1m",
.green => "\x1b[32;1m",
.yellow => "\x1b[33;1m",
.cyan => "\x1b[36;1m",
.white => "\x1b[37;1m",
.bold => "\x1b[1m",
.dim => "\x1b[2m",
.reset => "\x1b[0m",
};
try out_stream.writeAll(color_string);
},
.windows_api => |ctx| if (native_os == .windows) {
const attributes = switch (color) {
.red => windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY,
.green => windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
.yellow => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY,
.cyan => windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
.white, .bold => windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY,
.dim => windows.FOREGROUND_INTENSITY,
.reset => ctx.reset_attributes,
};
try windows.SetConsoleTextAttribute(ctx.handle, attributes);
} else {
unreachable;
},
};
}

pub fn writeDEC(conf: Config, writer: anytype, codepoint: u8) !void {
const bytes = switch (conf) {
.no_color, .windows_api => switch (codepoint) {
0x50...0x5e => @as(*const [1]u8, &codepoint),
0x6a => "+", // ┘
0x6b => "+", // ┐
0x6c => "+", // ┌
0x6d => "+", // └
0x6e => "+", // ┼
0x71 => "-", // ─
0x74 => "+", // ├
0x75 => "+", // ┤
0x76 => "+", // ┴
0x77 => "+", // ┬
0x78 => "|", // │
else => " ", // TODO
},
.escape_codes => switch (codepoint) {
// Here we avoid writing the DEC beginning sequence and
// ending sequence in separate syscalls by putting the
// beginning and ending sequence into the same string
// literals, to prevent terminals ending up in bad states
// in case a crash happens between syscalls.
inline 0x50...0x7f => |x| "\x1B\x28\x30" ++ [1]u8{x} ++ "\x1B\x28\x42",
else => unreachable,
},
};
return writer.writeAll(bytes);
}
};
};

fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
var min: usize = 0;
var max: usize = symbols.len - 1;
Expand Down Expand Up @@ -785,7 +670,7 @@ test "machoSearchSymbols" {
try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);
}

fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {
fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
const module_name = debug_info.getModuleNameForAddress(address);
return printLineInfo(
out_stream,
Expand All @@ -798,7 +683,7 @@ fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usiz
);
}

pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
else => return err,
Expand Down Expand Up @@ -827,7 +712,7 @@ fn printLineInfo(
address: usize,
symbol_name: []const u8,
compile_unit_name: []const u8,
tty_config: TTY.Config,
tty_config: io.tty.Config,
comptime printLineFromFile: anytype,
) !void {
nosuspend {
Expand Down Expand Up @@ -2193,7 +2078,7 @@ test "manage resources correctly" {
const writer = std.io.null_writer;
var di = try openSelfDebugInfo(testing.allocator);
defer di.deinit();
try printSourceAtAddress(&di, writer, showMyTrace(), detectTTYConfig(std.io.getStdErr()));
try printSourceAtAddress(&di, writer, showMyTrace(), io.tty.detectConfig(std.io.getStdErr()));
}

noinline fn showMyTrace() usize {
Expand Down Expand Up @@ -2253,7 +2138,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
pub fn dump(t: @This()) void {
if (!enabled) return;

const tty_config = detectTTYConfig(std.io.getStdErr());
const tty_config = io.tty.detectConfig(std.io.getStdErr());
const stderr = io.getStdErr().writer();
const end = @min(t.index, size);
const debug_info = getSelfDebugInfo() catch |err| {
Expand Down
2 changes: 2 additions & 0 deletions lib/std/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt

pub const StreamSource = @import("io/stream_source.zig").StreamSource;

pub const tty = @import("io/tty.zig");

/// A Writer that doesn't write to anything.
pub const null_writer = @as(NullWriter, .{ .context = {} });

Expand Down
Loading

0 comments on commit 0f6fa3f

Please sign in to comment.