| ... | ... | @@ -48,8 +48,9 @@ timer: ?time.Timer = null, |
| 48 | 48 | /// Used to compare with `refresh_rate_ms`. |
| 49 | 49 | prev_refresh_timestamp: u64 = undefined, |
| 50 | 50 | |
| 51 | | /// This buffer represents the maximum number of bytes written to the terminal |
| 52 | | /// with each refresh. |
| 51 | /// This is the maximum number of bytes that can be written to the terminal each refresh. |
| 52 | /// Anything larger than this is truncated. |
| 53 | // we can bump this up if we need to |
| 53 | 54 | output_buffer: [256]u8 = undefined, |
| 54 | 55 | output_buffer_slice: []u8 = undefined, |
| 55 | 56 | |
| ... | ... | @@ -57,6 +58,8 @@ output_buffer_slice: []u8 = undefined, |
| 57 | 58 | /// |
| 58 | 59 | /// It is recommended to leave this as `null` so that `start` can automatically decide an |
| 59 | 60 | /// optimal width for the terminal. |
| 61 | /// |
| 62 | /// Note that this will be clamped to at least 4 and output will appear malformed if it is < 4. |
| 60 | 63 | max_width: ?usize = null, |
| 61 | 64 | |
| 62 | 65 | /// How many nanoseconds between writing updates to the terminal. |
| ... | ... | @@ -156,9 +159,13 @@ pub const Node = struct { |
| 156 | 159 | |
| 157 | 160 | /// Create a new progress node. |
| 158 | 161 | /// Call `Node.end` when done. |
| 159 | | /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this |
| 160 | | /// API to return Progress rather than accept it as a parameter. |
| 161 | 162 | /// `estimated_total_items` value of 0 means unknown. |
| 163 | /// |
| 164 | /// Note that as soon as work is started and progress output is printed, |
| 165 | /// `std.Progress` expects you to lean back and wait and not resize the terminal. |
| 166 | /// Resizing the terminal during progress output may result in malformed output. |
| 167 | // TODO: solve https://github.com/ziglang/zig/issues/2765 and then change this |
| 168 | // API to return Progress rather than accept it as a parameter. |
| 162 | 169 | pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node { |
| 163 | 170 | const stderr = std.io.getStdErr(); |
| 164 | 171 | self.terminal = null; |
| ... | ... | @@ -172,6 +179,22 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N |
| 172 | 179 | // we are in a "dumb" terminal like in acme or writing to a file |
| 173 | 180 | self.terminal = stderr; |
| 174 | 181 | } |
| 182 | self.calculateMaxWidth(); |
| 183 | self.root = Node{ |
| 184 | .context = self, |
| 185 | .parent = null, |
| 186 | .name = name, |
| 187 | .unprotected_estimated_total_items = estimated_total_items, |
| 188 | .unprotected_completed_items = 0, |
| 189 | }; |
| 190 | self.columns_written = 0; |
| 191 | self.prev_refresh_timestamp = 0; |
| 192 | self.timer = time.Timer.start() catch null; |
| 193 | self.done = false; |
| 194 | return &self.root; |
| 195 | } |
| 196 | |
| 197 | fn calculateMaxWidth(self: *Progress) void { |
| 175 | 198 | if (self.max_width == null) { |
| 176 | 199 | if (self.terminal) |terminal| { |
| 177 | 200 | // choose an optimal width and account for progress output that could have been printed |
| ... | ... | @@ -188,18 +211,6 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *N |
| 188 | 211 | truncation_suffix.len, // make sure we can at least truncate |
| 189 | 212 | self.output_buffer.len - 1, |
| 190 | 213 | ); |
| 191 | | self.root = Node{ |
| 192 | | .context = self, |
| 193 | | .parent = null, |
| 194 | | .name = name, |
| 195 | | .unprotected_estimated_total_items = estimated_total_items, |
| 196 | | .unprotected_completed_items = 0, |
| 197 | | }; |
| 198 | | self.columns_written = 0; |
| 199 | | self.prev_refresh_timestamp = 0; |
| 200 | | self.timer = time.Timer.start() catch null; |
| 201 | | self.done = false; |
| 202 | | return &self.root; |
| 203 | 214 | } |
| 204 | 215 | |
| 205 | 216 | fn getTerminalWidth(self: Progress, file_handle: os.fd_t) !u16 { |
| ... | ... | @@ -237,7 +248,7 @@ fn getTerminalCursorColumn(self: Progress, file: std.fs.File) !u16 { |
| 237 | 248 | }; |
| 238 | 249 | |
| 239 | 250 | try file.writeAll("\x1b[6n"); |
| 240 | | var buf: ["\x1b[256;256R".len]u8 = undefined; |
| 251 | var buf: ["\x1b[65536;65536R".len]u8 = undefined; |
| 241 | 252 | const output = try file.reader().readUntilDelimiter(&buf, 'R'); |
| 242 | 253 | var splitter = std.mem.split(u8, output, ";"); |
| 243 | 254 | _ = splitter.next().?; // skip first half |
| ... | ... | @@ -346,7 +357,7 @@ fn refreshWithHeldLock(self: *Progress) void { |
| 346 | 357 | // we possibly wrote previously don't affect whether we truncate the line in `bufWrite`. |
| 347 | 358 | const unprintables = end; |
| 348 | 359 | end = 0; |
| 349 | | self.output_buffer_slice = self.output_buffer[unprintables .. unprintables + self.max_width.?]; |
| 360 | self.output_buffer_slice = self.output_buffer[unprintables..@minimum(self.output_buffer.len, unprintables + self.max_width.?)]; |
| 350 | 361 | |
| 351 | 362 | if (!self.done) { |
| 352 | 363 | var need_ellipsis = false; |
| ... | ... | @@ -432,8 +443,8 @@ test "behavior on buffer overflow" { |
| 432 | 443 | if (skip_tests) |
| 433 | 444 | return error.SkipZigTest; |
| 434 | 445 | |
| 435 | | // move the cursor |
| 436 | | std.debug.print("{s}", .{"A" ** 300}); |
| 446 | // uncomment this to move the cursor |
| 447 | //std.debug.print("{s}", .{"A" ** 300}); |
| 437 | 448 | |
| 438 | 449 | var progress = Progress{}; |
| 439 | 450 | |