output: print results in very basic colors unless suppressed

zig now outputs dimmed comments and bold identifiers, where supported.
suppressed by NO_COLOR env var or --nocolor flag.
0.10
alex 2 years ago
parent 8c2b7543b1
commit c6fe95a36b

@ -37,6 +37,9 @@ list all expectXxx functions from the testing module:
as a special case, if the source is exactly `std` and no such file
or directory exists, zdoc searches across the whole zig std lib.
zdoc outputs results in a basic colored format unless `NO_COLOR`
env variable is set or `--nocolor` flag is seen on command line.
---
to contribute, create a pull request or send a patch with

@ -2,6 +2,7 @@
//! the results to stdout. see usage for details.
const std = @import("std");
const builtin = @import("builtin");
const analyze = @import("analyze.zig");
const output = @import("output.zig");
@ -23,6 +24,7 @@ pub fn main() !void {
var zsource: [:0]const u8 = undefined; // std.xxx or an fs path
const opts = struct { // cmd line options with defaults
var sub: bool = false; // -s substr option
var color: bool = true; // --nocolor sets to false
};
var nargs: u8 = 0; // positional only, aka excluding opts
@ -31,6 +33,10 @@ pub fn main() !void {
opts.sub = true;
continue;
}
if (std.mem.eql(u8, a, "--nocolor")) {
opts.color = false;
continue;
}
switch (nargs) {
0 => {
zsource = a;
@ -52,6 +58,7 @@ pub fn main() !void {
var auto_indenting_stream = output.Ais{
.indent_delta = output.indent_delta,
.underlying_writer = output.TypeErasedWriter.init(&stdout),
.ttyconf = if (opts.color) detectTTY(std.io.getStdOut()) else .no_color,
};
const ais = &auto_indenting_stream;
@ -117,6 +124,9 @@ fn usage(prog: []const u8) !void {
\\as a special case, if the source is exactly "std" and no such file
\\or directory exists, zdoc searches across the whole zig std lib.
\\
\\zdoc outputs results in a basic colored format unless NO_COLOR
\\env variable is set or --nocolor flag is seen on command line.
\\
, .{prog});
}
@ -222,6 +232,18 @@ fn zigStdPath(alloc: std.mem.Allocator) ![]const u8 {
return alloc.dupe(u8, jenv.std_dir);
}
fn detectTTY(out: anytype) std.debug.TTY.Config {
if (std.process.hasEnvVarConstant("NO_COLOR")) {
return .no_color;
} else if (out.supportsAnsiEscapeCodes()) {
return .escape_codes;
} else if (builtin.os.tag == .windows and out.isTty()) {
return .windows_api;
} else {
return .no_color;
}
}
test {
// run tests found in all @import'ed files.
std.testing.refAllDecls(@This());

@ -23,11 +23,13 @@ pub const Ais = AutoIndentingStream(TypeErasedWriter.Writer);
// outputs all the line comments at the beginning of the tree.
pub fn renderTopLevelDocComments(ais: *Ais, tree: Ast) !void {
ais.colorComments();
const comment_end_loc = tree.tokens.items(.start)[0];
_ = try renderComments(ais, tree, 0, comment_end_loc);
if (tree.tokens.items(.tag)[0] == .container_doc_comment) {
try renderContainerDocComments(ais, tree, 0);
}
ais.colorReset();
}
/// renderPubMember prints the given declaration using ais.
@ -897,7 +899,9 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
Space.space
else
Space.none;
ais.colorIdentifier();
try renderToken(ais, tree, var_decl.ast.mut_token + 1, name_space); // name
ais.colorReset();
if (var_decl.ast.type_node != 0) {
try renderToken(ais, tree, var_decl.ast.mut_token + 2, Space.space); // :
@ -1105,10 +1109,14 @@ fn renderContainerField(
try renderToken(ais, tree, t, .space); // comptime
}
if (field.ast.type_expr == 0 and field.ast.value_expr == 0) {
ais.colorIdentifier();
defer ais.colorReset();
return renderTokenComma(ais, tree, field.ast.name_token, space); // name
}
if (field.ast.type_expr != 0 and field.ast.value_expr == 0) {
ais.colorIdentifier();
try renderToken(ais, tree, field.ast.name_token, .none); // name
ais.colorReset();
try renderToken(ais, tree, field.ast.name_token + 1, .space); // :
if (field.ast.align_expr != 0) {
@ -1124,12 +1132,16 @@ fn renderContainerField(
}
}
if (field.ast.type_expr == 0 and field.ast.value_expr != 0) {
ais.colorIdentifier();
try renderToken(ais, tree, field.ast.name_token, .space); // name
ais.colorReset();
try renderToken(ais, tree, field.ast.name_token + 1, .space); // =
return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value
}
ais.colorIdentifier();
try renderToken(ais, tree, field.ast.name_token, .none); // name
ais.colorReset();
try renderToken(ais, tree, field.ast.name_token + 1, .space); // :
try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type
@ -1228,7 +1240,9 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
const after_fn_token = fn_proto.ast.fn_token + 1;
const lparen = if (token_tags[after_fn_token] == .identifier) blk: {
try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn
ais.colorIdentifier();
try renderToken(ais, tree, after_fn_token, .none); // name
ais.colorReset();
break :blk after_fn_token + 1;
} else blk: {
try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn
@ -2436,18 +2450,22 @@ fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) anyerror!v
}
}
ais.colorComments();
while (token_tags[tok] == .doc_comment) : (tok += 1) {
try renderToken(ais, tree, tok, .newline);
}
ais.colorReset();
}
/// start_token is first container doc comment token.
fn renderContainerDocComments(ais: *Ais, tree: Ast, start_token: Ast.TokenIndex) !void {
const token_tags = tree.tokens.items(.tag);
var tok = start_token;
ais.colorComments();
while (token_tags[tok] == .container_doc_comment) : (tok += 1) {
try renderToken(ais, tree, tok, .newline);
}
ais.colorReset();
// Render extra newline if there is one between final container doc comment and
// the next token. If the next token is a doc comment, that code path
// will have its own logic to insert a newline.
@ -2621,6 +2639,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
pub const Writer = std.io.Writer(*Self, WriteError, write);
underlying_writer: UnderlyingWriter,
ttyconf: std.debug.TTY.Config = .no_color,
/// Offset into the source at which formatting has been disabled with
/// a `zig fmt: off` comment.
@ -2647,6 +2666,18 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
/// use setSearchFile to set a new name before starting a search.
search_file: ?[]const u8 = null,
fn colorIdentifier(self: *Self) void {
self.ttyconf.setColor(self.underlying_writer, .Bold);
}
fn colorComments(self: *Self) void {
self.ttyconf.setColor(self.underlying_writer, .Dim);
}
fn colorReset(self: *Self) void {
self.ttyconf.setColor(self.underlying_writer, .Reset);
}
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}

Loading…
Cancel
Save