mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
add lib/std/progress.zig
This commit is contained in:
parent
17aa8c3ee2
commit
a73c7bcaf9
107
lib/std/progress.zig
Normal file
107
lib/std/progress.zig
Normal file
@ -0,0 +1,107 @@
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
|
||||
pub const PrintConfig = struct {
|
||||
/// If the current node (and its children) should
|
||||
/// print to stderr on update()
|
||||
flag: bool = false,
|
||||
|
||||
/// If all output should be suppressed instead
|
||||
/// serves the same practical purpose as `flag` but supposed to be used
|
||||
/// by separate parts of the user program.
|
||||
suppress: bool = false,
|
||||
};
|
||||
|
||||
pub const ProgressNode = struct {
|
||||
completed_items: usize = 0,
|
||||
total_items: usize,
|
||||
|
||||
print_config: PrintConfig,
|
||||
|
||||
// TODO maybe instead of keeping a prefix field, we could
|
||||
// select the proper prefix at the time of update(), and if we're not
|
||||
// in a terminal, we use warn("/r{}", lots_of_whitespace).
|
||||
prefix: []const u8,
|
||||
|
||||
/// Create a new progress node.
|
||||
pub fn start(
|
||||
parent_opt: ?ProgressNode,
|
||||
total_items_opt: ?usize,
|
||||
) !ProgressNode {
|
||||
|
||||
// inherit the last set print "configuration" from the parent node
|
||||
var print_config = PrintConfig{};
|
||||
if (parent_opt) |parent| {
|
||||
print_config = parent.print_config;
|
||||
}
|
||||
|
||||
var stderr = try std.io.getStdErr();
|
||||
const is_term = std.os.isatty(stderr.handle);
|
||||
|
||||
// if we're in a terminal, use vt100 escape codes
|
||||
// for the progress.
|
||||
var prefix: []const u8 = undefined;
|
||||
if (is_term) {
|
||||
prefix = "\x21[2K\r";
|
||||
} else {
|
||||
prefix = "\n";
|
||||
}
|
||||
|
||||
return ProgressNode{
|
||||
.total_items = total_items_opt orelse 0,
|
||||
.print_config = print_config,
|
||||
.prefix = prefix,
|
||||
};
|
||||
}
|
||||
|
||||
/// Signal an update on the progress node.
|
||||
/// The user of this function is supposed to modify
|
||||
/// ProgressNode.PrintConfig.flag when update() is supposed to print.
|
||||
pub fn update(
|
||||
self: *ProgressNode,
|
||||
current_action: ?[]const u8,
|
||||
items_done_opt: ?usize,
|
||||
) void {
|
||||
if (items_done_opt) |items_done| {
|
||||
self.completed_items = items_done;
|
||||
|
||||
if (items_done > self.total_items) {
|
||||
self.total_items = items_done;
|
||||
}
|
||||
}
|
||||
|
||||
var cfg = self.print_config;
|
||||
if (cfg.flag and !cfg.suppress and current_action != null) {
|
||||
std.debug.warn(
|
||||
"{}[{}/{}] {}",
|
||||
self.prefix,
|
||||
self.completed_items,
|
||||
self.total_items,
|
||||
current_action,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn end(self: *ProgressNode) void {
|
||||
if (!self.print_config.flag) return;
|
||||
|
||||
// TODO emoji?
|
||||
std.debug.warn("\n[V] done!");
|
||||
}
|
||||
};
|
||||
|
||||
test "basic functionality" {
|
||||
var node = try ProgressNode.start(null, 100);
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < 100) : (i += 6) {
|
||||
if (i > 50) node.print_config.flag = true;
|
||||
const msg = try std.fmt.bufPrint(buf[0..], "action at i={}", i);
|
||||
node.update(msg, i);
|
||||
std.time.sleep(10 * std.time.millisecond);
|
||||
}
|
||||
|
||||
node.end();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user