mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std: Move std.debug.{TTY.Config,detectTTYConfig} to std.io.tty
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.
This commit is contained in:
parent
39c2eee285
commit
0f6fa3f20b
11 changed files with 152 additions and 144 deletions
|
|
@ -333,7 +333,7 @@ const Run = struct {
|
||||||
|
|
||||||
claimed_rss: usize,
|
claimed_rss: usize,
|
||||||
enable_summary: ?bool,
|
enable_summary: ?bool,
|
||||||
ttyconf: std.debug.TTY.Config,
|
ttyconf: std.io.tty.Config,
|
||||||
stderr: std.fs.File,
|
stderr: std.fs.File,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -535,7 +535,7 @@ const PrintNode = struct {
|
||||||
last: bool = false,
|
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;
|
const parent = node.parent orelse return;
|
||||||
if (parent.parent == null) return;
|
if (parent.parent == null) return;
|
||||||
try printPrefix(parent, stderr, ttyconf);
|
try printPrefix(parent, stderr, ttyconf);
|
||||||
|
|
@ -553,7 +553,7 @@ fn printTreeStep(
|
||||||
b: *std.Build,
|
b: *std.Build,
|
||||||
s: *Step,
|
s: *Step,
|
||||||
stderr: std.fs.File,
|
stderr: std.fs.File,
|
||||||
ttyconf: std.debug.TTY.Config,
|
ttyconf: std.io.tty.Config,
|
||||||
parent_node: *PrintNode,
|
parent_node: *PrintNode,
|
||||||
step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
|
step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
|
||||||
) !void {
|
) !void {
|
||||||
|
|
@ -1026,15 +1026,15 @@ fn cleanExit() void {
|
||||||
|
|
||||||
const Color = enum { auto, off, on };
|
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) {
|
return switch (color) {
|
||||||
.auto => std.debug.detectTTYConfig(stderr),
|
.auto => std.io.tty.detectConfig(stderr),
|
||||||
.on => .escape_codes,
|
.on => .escape_codes,
|
||||||
.off => .no_color,
|
.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 .{
|
return .{
|
||||||
.ttyconf = ttyconf,
|
.ttyconf = ttyconf,
|
||||||
.include_source_line = ttyconf != .no_color,
|
.include_source_line = ttyconf != .no_color,
|
||||||
|
|
|
||||||
|
|
@ -1712,7 +1712,7 @@ fn dumpBadGetPathHelp(
|
||||||
s.name,
|
s.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tty_config = std.debug.detectTTYConfig(stderr);
|
const tty_config = std.io.tty.detectConfig(stderr);
|
||||||
tty_config.setColor(w, .red) catch {};
|
tty_config.setColor(w, .red) catch {};
|
||||||
try stderr.writeAll(" The step was created by this stack trace:\n");
|
try stderr.writeAll(" The step was created by this stack trace:\n");
|
||||||
tty_config.setColor(w, .reset) catch {};
|
tty_config.setColor(w, .reset) catch {};
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ pub fn dump(step: *Step) void {
|
||||||
|
|
||||||
const stderr = std.io.getStdErr();
|
const stderr = std.io.getStdErr();
|
||||||
const w = stderr.writer();
|
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| {
|
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
|
||||||
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
|
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
|
||||||
@errorName(err),
|
@errorName(err),
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ pub const StackTrace = struct {
|
||||||
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
|
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)});
|
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");
|
try writer.writeAll("\n");
|
||||||
std.debug.writeStackTrace(self, writer, arena.allocator(), debug_info, tty_config) catch |err| {
|
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)});
|
try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)});
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ const mem = std.mem;
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
const os = std.os;
|
const os = std.os;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const process = std.process;
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const elf = std.elf;
|
const elf = std.elf;
|
||||||
const DW = std.dwarf;
|
const DW = std.dwarf;
|
||||||
|
|
@ -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.
|
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
|
||||||
/// TODO multithreaded awareness
|
/// TODO multithreaded awareness
|
||||||
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
||||||
|
|
@ -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;
|
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
|
||||||
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;
|
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -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;
|
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
const tty_config = detectTTYConfig(io.getStdErr());
|
const tty_config = io.tty.detectConfig(io.getStdErr());
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
writeCurrentStackTraceWindows(stderr, debug_info, tty_config, ip) catch return;
|
writeCurrentStackTraceWindows(stderr, debug_info, tty_config, ip) catch return;
|
||||||
return;
|
return;
|
||||||
|
|
@ -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;
|
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
|
||||||
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;
|
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -403,7 +377,7 @@ pub fn writeStackTrace(
|
||||||
out_stream: anytype,
|
out_stream: anytype,
|
||||||
allocator: mem.Allocator,
|
allocator: mem.Allocator,
|
||||||
debug_info: *DebugInfo,
|
debug_info: *DebugInfo,
|
||||||
tty_config: TTY.Config,
|
tty_config: io.tty.Config,
|
||||||
) !void {
|
) !void {
|
||||||
_ = allocator;
|
_ = allocator;
|
||||||
if (builtin.strip_debug_info) return error.MissingDebugInfo;
|
if (builtin.strip_debug_info) return error.MissingDebugInfo;
|
||||||
|
|
@ -562,7 +536,7 @@ pub const StackIterator = struct {
|
||||||
pub fn writeCurrentStackTrace(
|
pub fn writeCurrentStackTrace(
|
||||||
out_stream: anytype,
|
out_stream: anytype,
|
||||||
debug_info: *DebugInfo,
|
debug_info: *DebugInfo,
|
||||||
tty_config: TTY.Config,
|
tty_config: io.tty.Config,
|
||||||
start_addr: ?usize,
|
start_addr: ?usize,
|
||||||
) !void {
|
) !void {
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
|
|
@ -634,7 +608,7 @@ pub noinline fn walkStackWindows(addresses: []usize) usize {
|
||||||
pub fn writeCurrentStackTraceWindows(
|
pub fn writeCurrentStackTraceWindows(
|
||||||
out_stream: anytype,
|
out_stream: anytype,
|
||||||
debug_info: *DebugInfo,
|
debug_info: *DebugInfo,
|
||||||
tty_config: TTY.Config,
|
tty_config: io.tty.Config,
|
||||||
start_addr: ?usize,
|
start_addr: ?usize,
|
||||||
) !void {
|
) !void {
|
||||||
var addr_buf: [1024]usize = undefined;
|
var addr_buf: [1024]usize = undefined;
|
||||||
|
|
@ -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 {
|
fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
|
||||||
var min: usize = 0;
|
var min: usize = 0;
|
||||||
var max: usize = symbols.len - 1;
|
var max: usize = symbols.len - 1;
|
||||||
|
|
@ -785,7 +670,7 @@ test "machoSearchSymbols" {
|
||||||
try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);
|
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);
|
const module_name = debug_info.getModuleNameForAddress(address);
|
||||||
return printLineInfo(
|
return printLineInfo(
|
||||||
out_stream,
|
out_stream,
|
||||||
|
|
@ -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) {
|
const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
|
||||||
error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
|
error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
|
||||||
else => return err,
|
else => return err,
|
||||||
|
|
@ -827,7 +712,7 @@ fn printLineInfo(
|
||||||
address: usize,
|
address: usize,
|
||||||
symbol_name: []const u8,
|
symbol_name: []const u8,
|
||||||
compile_unit_name: []const u8,
|
compile_unit_name: []const u8,
|
||||||
tty_config: TTY.Config,
|
tty_config: io.tty.Config,
|
||||||
comptime printLineFromFile: anytype,
|
comptime printLineFromFile: anytype,
|
||||||
) !void {
|
) !void {
|
||||||
nosuspend {
|
nosuspend {
|
||||||
|
|
@ -2193,7 +2078,7 @@ test "manage resources correctly" {
|
||||||
const writer = std.io.null_writer;
|
const writer = std.io.null_writer;
|
||||||
var di = try openSelfDebugInfo(testing.allocator);
|
var di = try openSelfDebugInfo(testing.allocator);
|
||||||
defer di.deinit();
|
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 {
|
noinline fn showMyTrace() usize {
|
||||||
|
|
@ -2253,7 +2138,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
|
||||||
pub fn dump(t: @This()) void {
|
pub fn dump(t: @This()) void {
|
||||||
if (!enabled) return;
|
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 stderr = io.getStdErr().writer();
|
||||||
const end = @min(t.index, size);
|
const end = @min(t.index, size);
|
||||||
const debug_info = getSelfDebugInfo() catch |err| {
|
const debug_info = getSelfDebugInfo() catch |err| {
|
||||||
|
|
|
||||||
|
|
@ -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 StreamSource = @import("io/stream_source.zig").StreamSource;
|
||||||
|
|
||||||
|
pub const tty = @import("io/tty.zig");
|
||||||
|
|
||||||
/// A Writer that doesn't write to anything.
|
/// A Writer that doesn't write to anything.
|
||||||
pub const null_writer = @as(NullWriter, .{ .context = {} });
|
pub const null_writer = @as(NullWriter, .{ .context = {} });
|
||||||
|
|
||||||
|
|
|
||||||
121
lib/std/io/tty.zig
Normal file
121
lib/std/io/tty.zig
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const File = std.fs.File;
|
||||||
|
const process = std.process;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
|
||||||
|
/// 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` environment variable.
|
||||||
|
pub fn detectConfig(file: File) 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Color = enum {
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
yellow,
|
||||||
|
cyan,
|
||||||
|
white,
|
||||||
|
dim,
|
||||||
|
bold,
|
||||||
|
reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Provides simple functionality for manipulating the terminal in some way,
|
||||||
|
/// such as coloring text, etc.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -279,7 +279,7 @@ test "expectApproxEqRel" {
|
||||||
/// This function is intended to be used only in tests. When the two slices are not
|
/// This function is intended to be used only in tests. When the two slices are not
|
||||||
/// equal, prints diagnostics to stderr to show exactly how they are not equal (with
|
/// equal, prints diagnostics to stderr to show exactly how they are not equal (with
|
||||||
/// the differences highlighted in red), then returns a test failure error.
|
/// the differences highlighted in red), then returns a test failure error.
|
||||||
/// The colorized output is optional and controlled by the return of `std.debug.detectTTYConfig()`.
|
/// The colorized output is optional and controlled by the return of `std.io.tty.detectConfig()`.
|
||||||
/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
|
/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
|
||||||
pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
|
pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
|
||||||
if (expected.ptr == actual.ptr and expected.len == actual.len) {
|
if (expected.ptr == actual.ptr and expected.len == actual.len) {
|
||||||
|
|
@ -312,7 +312,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
|
||||||
const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
|
const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
|
||||||
const actual_truncated = window_start + actual_window.len < actual.len;
|
const actual_truncated = window_start + actual_window.len < actual.len;
|
||||||
|
|
||||||
const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
|
const ttyconf = std.io.tty.detectConfig(std.io.getStdErr());
|
||||||
var differ = if (T == u8) BytesDiffer{
|
var differ = if (T == u8) BytesDiffer{
|
||||||
.expected = expected_window,
|
.expected = expected_window,
|
||||||
.actual = actual_window,
|
.actual = actual_window,
|
||||||
|
|
@ -379,7 +379,7 @@ fn SliceDiffer(comptime T: type) type {
|
||||||
start_index: usize,
|
start_index: usize,
|
||||||
expected: []const T,
|
expected: []const T,
|
||||||
actual: []const T,
|
actual: []const T,
|
||||||
ttyconf: std.debug.TTY.Config,
|
ttyconf: std.io.tty.Config,
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
|
@ -398,7 +398,7 @@ fn SliceDiffer(comptime T: type) type {
|
||||||
const BytesDiffer = struct {
|
const BytesDiffer = struct {
|
||||||
expected: []const u8,
|
expected: []const u8,
|
||||||
actual: []const u8,
|
actual: []const u8,
|
||||||
ttyconf: std.debug.TTY.Config,
|
ttyconf: std.io.tty.Config,
|
||||||
|
|
||||||
pub fn write(self: BytesDiffer, writer: anytype) !void {
|
pub fn write(self: BytesDiffer, writer: anytype) !void {
|
||||||
var expected_iterator = ChunkIterator{ .bytes = self.expected };
|
var expected_iterator = ChunkIterator{ .bytes = self.expected };
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const RenderOptions = struct {
|
pub const RenderOptions = struct {
|
||||||
ttyconf: std.debug.TTY.Config,
|
ttyconf: std.io.tty.Config,
|
||||||
include_reference_trace: bool = true,
|
include_reference_trace: bool = true,
|
||||||
include_source_line: bool = true,
|
include_source_line: bool = true,
|
||||||
include_log_text: bool = true,
|
include_log_text: bool = true,
|
||||||
|
|
@ -181,7 +181,7 @@ fn renderErrorMessageToWriter(
|
||||||
err_msg_index: MessageIndex,
|
err_msg_index: MessageIndex,
|
||||||
stderr: anytype,
|
stderr: anytype,
|
||||||
kind: []const u8,
|
kind: []const u8,
|
||||||
color: std.debug.TTY.Color,
|
color: std.io.tty.Color,
|
||||||
indent: usize,
|
indent: usize,
|
||||||
) anyerror!void {
|
) anyerror!void {
|
||||||
const ttyconf = options.ttyconf;
|
const ttyconf = options.ttyconf;
|
||||||
|
|
|
||||||
|
|
@ -6044,9 +6044,9 @@ const ClangSearchSanitizer = struct {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn get_tty_conf(color: Color) std.debug.TTY.Config {
|
fn get_tty_conf(color: Color) std.io.tty.Config {
|
||||||
return switch (color) {
|
return switch (color) {
|
||||||
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
|
.auto => std.io.tty.detectConfig(std.io.getStdErr()),
|
||||||
.on => .escape_codes,
|
.on => .escape_codes,
|
||||||
.off => .no_color,
|
.off => .no_color,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1354,7 +1354,7 @@ fn runOneCase(
|
||||||
defer all_errors.deinit(allocator);
|
defer all_errors.deinit(allocator);
|
||||||
if (all_errors.errorMessageCount() > 0) {
|
if (all_errors.errorMessageCount() > 0) {
|
||||||
all_errors.renderToStdErr(.{
|
all_errors.renderToStdErr(.{
|
||||||
.ttyconf = std.debug.detectTTYConfig(std.io.getStdErr()),
|
.ttyconf = std.io.tty.detectConfig(std.io.getStdErr()),
|
||||||
});
|
});
|
||||||
// TODO print generated C code
|
// TODO print generated C code
|
||||||
return error.UnexpectedCompileErrors;
|
return error.UnexpectedCompileErrors;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue