| ... | @@ -192,32 +192,28 @@ pub fn refresh(self: *Progress) void { | ... | @@ -192,32 +192,28 @@ pub fn refresh(self: *Progress) void { |
| 192 | return self.refreshWithHeldLock(); | 192 | return self.refreshWithHeldLock(); |
| 193 | } | 193 | } |
| 194 | | 194 | |
| 195 | fn refreshWithHeldLock(self: *Progress) void { | 195 | fn clearWithHeldLock(p: *Progress, end_ptr: *usize) void { |
| 196 | const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal; | 196 | const file = p.terminal orelse return; |
| 197 | if (is_dumb and self.dont_print_on_dumb) return; | 197 | var end = end_ptr.*; |
| 198 | | 198 | if (p.columns_written > 0) { |
| 199 | const file = self.terminal orelse return; | | |
| 200 | | | |
| 201 | var end: usize = 0; | | |
| 202 | if (self.columns_written > 0) { | | |
| 203 | // restore the cursor position by moving the cursor | 199 | // restore the cursor position by moving the cursor |
| 204 | // `columns_written` cells to the left, then clear the rest of the | 200 | // `columns_written` cells to the left, then clear the rest of the |
| 205 | // line | 201 | // line |
| 206 | if (self.supports_ansi_escape_codes) { | 202 | if (p.supports_ansi_escape_codes) { |
| 207 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{d}D", .{self.columns_written}) catch unreachable).len; | 203 | end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[{d}D", .{p.columns_written}) catch unreachable).len; |
| 208 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; | 204 | end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; |
| 209 | } else if (builtin.os.tag == .windows) winapi: { | 205 | } else if (builtin.os.tag == .windows) winapi: { |
| 210 | std.debug.assert(self.is_windows_terminal); | 206 | std.debug.assert(p.is_windows_terminal); |
| 211 | | 207 | |
| 212 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | 208 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; |
| 213 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { | 209 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { |
| 214 | // stop trying to write to this file | 210 | // stop trying to write to this file |
| 215 | self.terminal = null; | 211 | p.terminal = null; |
| 216 | break :winapi; | 212 | break :winapi; |
| 217 | } | 213 | } |
| 218 | | 214 | |
| 219 | var cursor_pos = windows.COORD{ | 215 | var cursor_pos = windows.COORD{ |
| 220 | .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written), | 216 | .X = info.dwCursorPosition.X - @intCast(windows.SHORT, p.columns_written), |
| 221 | .Y = info.dwCursorPosition.Y, | 217 | .Y = info.dwCursorPosition.Y, |
| 222 | }; | 218 | }; |
| 223 | | 219 | |
| ... | @@ -235,7 +231,7 @@ fn refreshWithHeldLock(self: *Progress) void { | ... | @@ -235,7 +231,7 @@ fn refreshWithHeldLock(self: *Progress) void { |
| 235 | &written, | 231 | &written, |
| 236 | ) != windows.TRUE) { | 232 | ) != windows.TRUE) { |
| 237 | // stop trying to write to this file | 233 | // stop trying to write to this file |
| 238 | self.terminal = null; | 234 | p.terminal = null; |
| 239 | break :winapi; | 235 | break :winapi; |
| 240 | } | 236 | } |
| 241 | if (windows.kernel32.FillConsoleOutputCharacterW( | 237 | if (windows.kernel32.FillConsoleOutputCharacterW( |
| ... | @@ -246,22 +242,33 @@ fn refreshWithHeldLock(self: *Progress) void { | ... | @@ -246,22 +242,33 @@ fn refreshWithHeldLock(self: *Progress) void { |
| 246 | &written, | 242 | &written, |
| 247 | ) != windows.TRUE) { | 243 | ) != windows.TRUE) { |
| 248 | // stop trying to write to this file | 244 | // stop trying to write to this file |
| 249 | self.terminal = null; | 245 | p.terminal = null; |
| 250 | break :winapi; | 246 | break :winapi; |
| 251 | } | 247 | } |
| 252 | if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) { | 248 | if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) { |
| 253 | // stop trying to write to this file | 249 | // stop trying to write to this file |
| 254 | self.terminal = null; | 250 | p.terminal = null; |
| 255 | break :winapi; | 251 | break :winapi; |
| 256 | } | 252 | } |
| 257 | } else { | 253 | } else { |
| 258 | // we are in a "dumb" terminal like in acme or writing to a file | 254 | // we are in a "dumb" terminal like in acme or writing to a file |
| 259 | self.output_buffer[end] = '\n'; | 255 | p.output_buffer[end] = '\n'; |
| 260 | end += 1; | 256 | end += 1; |
| 261 | } | 257 | } |
| 262 | | 258 | |
| 263 | self.columns_written = 0; | 259 | p.columns_written = 0; |
| 264 | } | 260 | } |
| | 261 | end_ptr.* = end; |
| | 262 | } |
| | 263 | |
| | 264 | fn refreshWithHeldLock(self: *Progress) void { |
| | 265 | const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal; |
| | 266 | if (is_dumb and self.dont_print_on_dumb) return; |
| | 267 | |
| | 268 | const file = self.terminal orelse return; |
| | 269 | |
| | 270 | var end: usize = 0; |
| | 271 | clearWithHeldLock(self, &end); |
| 265 | | 272 | |
| 266 | if (!self.done) { | 273 | if (!self.done) { |
| 267 | var need_ellipse = false; | 274 | var need_ellipse = false; |
| ... | @@ -318,6 +325,26 @@ pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { | ... | @@ -318,6 +325,26 @@ pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { |
| 318 | self.columns_written = 0; | 325 | self.columns_written = 0; |
| 319 | } | 326 | } |
| 320 | | 327 | |
| | 328 | /// Allows the caller to freely write to stderr until unlock_stderr() is called. |
| | 329 | /// During the lock, the progress information is cleared from the terminal. |
| | 330 | pub fn lock_stderr(p: *Progress) void { |
| | 331 | p.update_mutex.lock(); |
| | 332 | if (p.terminal) |file| { |
| | 333 | var end: usize = 0; |
| | 334 | clearWithHeldLock(p, &end); |
| | 335 | _ = file.write(p.output_buffer[0..end]) catch { |
| | 336 | // stop trying to write to this file |
| | 337 | p.terminal = null; |
| | 338 | }; |
| | 339 | } |
| | 340 | std.debug.getStderrMutex().lock(); |
| | 341 | } |
| | 342 | |
| | 343 | pub fn unlock_stderr(p: *Progress) void { |
| | 344 | std.debug.getStderrMutex().unlock(); |
| | 345 | p.update_mutex.unlock(); |
| | 346 | } |
| | 347 | |
| 321 | fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void { | 348 | fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void { |
| 322 | if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| { | 349 | if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| { |
| 323 | const amt = written.len; | 350 | const amt = written.len; |