Skip to content
Merged
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
51 changes: 31 additions & 20 deletions lib/std/Progress.zig
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,18 @@ timer: ?time.Timer = null,
/// Used to compare with `refresh_rate_ms`.
prev_refresh_timestamp: u64 = undefined,

/// This buffer represents the maximum number of bytes written to the terminal
/// with each refresh.
/// This is the maximum number of bytes that can be written to the terminal each refresh.
/// Anything larger than this is truncated.
// we can bump this up if we need to
output_buffer: [256]u8 = undefined,
output_buffer_slice: []u8 = undefined,

/// This is the maximum number of bytes written to the terminal with each refresh.
///
/// It is recommended to leave this as `null` so that `start` can automatically decide an
/// optimal width for the terminal.
///
/// Note that this will be clamped to at least 4 and output will appear malformed if it is < 4.
max_width: ?usize = null,

/// How many nanoseconds between writing updates to the terminal.
Expand Down Expand Up @@ -156,9 +159,13 @@ pub const Node = struct {

/// Create a new progress node.
/// Call `Node.end` when done.
/// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this
/// API to return Progress rather than accept it as a parameter.
/// `estimated_total_items` value of 0 means unknown.
///
/// Note that as soon as work is started and progress output is printed,
/// `std.Progress` expects you to lean back and wait and not resize the terminal.
/// Resizing the terminal during progress output may result in malformed output.
// TODO: solve https://github.com/ziglang/zig/issues/2765 and then change this
// API to return Progress rather than accept it as a parameter.
pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node {
const stderr = std.io.getStdErr();
self.terminal = null;
Expand All @@ -172,6 +179,22 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N
// we are in a "dumb" terminal like in acme or writing to a file
self.terminal = stderr;
}
self.calculateMaxWidth();
self.root = Node{
.context = self,
.parent = null,
.name = name,
.unprotected_estimated_total_items = estimated_total_items,
.unprotected_completed_items = 0,
};
self.columns_written = 0;
self.prev_refresh_timestamp = 0;
self.timer = time.Timer.start() catch null;
self.done = false;
return &self.root;
}

fn calculateMaxWidth(self: *Progress) void {
if (self.max_width == null) {
if (self.terminal) |terminal| {
// choose an optimal width and account for progress output that could have been printed
Expand All @@ -188,18 +211,6 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N
truncation_suffix.len, // make sure we can at least truncate
self.output_buffer.len - 1,
);
self.root = Node{
.context = self,
.parent = null,
.name = name,
.unprotected_estimated_total_items = estimated_total_items,
.unprotected_completed_items = 0,
};
self.columns_written = 0;
self.prev_refresh_timestamp = 0;
self.timer = time.Timer.start() catch null;
self.done = false;
return &self.root;
}

fn getTerminalWidth(self: Progress, file_handle: os.fd_t) !u16 {
Expand Down Expand Up @@ -237,7 +248,7 @@ fn getTerminalCursorColumn(self: Progress, file: std.fs.File) !u16 {
};

try file.writeAll("\x1b[6n");
var buf: ["\x1b[256;256R".len]u8 = undefined;
var buf: ["\x1b[65536;65536R".len]u8 = undefined;
const output = try file.reader().readUntilDelimiter(&buf, 'R');
var splitter = std.mem.split(u8, output, ";");
_ = splitter.next().?; // skip first half
Expand Down Expand Up @@ -346,7 +357,7 @@ fn refreshWithHeldLock(self: *Progress) void {
// we possibly wrote previously don't affect whether we truncate the line in `bufWrite`.
const unprintables = end;
end = 0;
self.output_buffer_slice = self.output_buffer[unprintables .. unprintables + self.max_width.?];
self.output_buffer_slice = self.output_buffer[unprintables..@minimum(self.output_buffer.len, unprintables + self.max_width.?)];

if (!self.done) {
var need_ellipsis = false;
Expand Down Expand Up @@ -432,8 +443,8 @@ test "behavior on buffer overflow" {
if (skip_tests)
return error.SkipZigTest;

// move the cursor
std.debug.print("{s}", .{"A" ** 300});
// uncomment this to move the cursor
//std.debug.print("{s}", .{"A" ** 300});

var progress = Progress{};

Expand Down