| ... | ... | @@ -192,32 +192,28 @@ pub fn refresh(self: *Progress) void { |
| 192 | 192 | return self.refreshWithHeldLock(); |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | | fn refreshWithHeldLock(self: *Progress) void { |
| 196 | | const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal; |
| 197 | | if (is_dumb and self.dont_print_on_dumb) return; |
| 198 | | |
| 199 | | const file = self.terminal orelse return; |
| 200 | | |
| 201 | | var end: usize = 0; |
| 202 | | if (self.columns_written > 0) { |
| 195 | fn clearWithHeldLock(p: *Progress, end_ptr: *usize) void { |
| 196 | const file = p.terminal orelse return; |
| 197 | var end = end_ptr.*; |
| 198 | if (p.columns_written > 0) { |
| 203 | 199 | // restore the cursor position by moving the cursor |
| 204 | 200 | // `columns_written` cells to the left, then clear the rest of the |
| 205 | 201 | // line |
| 206 | | if (self.supports_ansi_escape_codes) { |
| 207 | | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{d}D", .{self.columns_written}) catch unreachable).len; |
| 208 | | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; |
| 202 | if (p.supports_ansi_escape_codes) { |
| 203 | end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[{d}D", .{p.columns_written}) catch unreachable).len; |
| 204 | end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; |
| 209 | 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 | 208 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; |
| 213 | 209 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { |
| 214 | 210 | // stop trying to write to this file |
| 215 | | self.terminal = null; |
| 211 | p.terminal = null; |
| 216 | 212 | break :winapi; |
| 217 | 213 | } |
| 218 | 214 | |
| 219 | 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 | 217 | .Y = info.dwCursorPosition.Y, |
| 222 | 218 | }; |
| 223 | 219 | |
| ... | ... | @@ -235,7 +231,7 @@ fn refreshWithHeldLock(self: *Progress) void { |
| 235 | 231 | &written, |
| 236 | 232 | ) != windows.TRUE) { |
| 237 | 233 | // stop trying to write to this file |
| 238 | | self.terminal = null; |
| 234 | p.terminal = null; |
| 239 | 235 | break :winapi; |
| 240 | 236 | } |
| 241 | 237 | if (windows.kernel32.FillConsoleOutputCharacterW( |
| ... | ... | @@ -246,22 +242,33 @@ fn refreshWithHeldLock(self: *Progress) void { |
| 246 | 242 | &written, |
| 247 | 243 | ) != windows.TRUE) { |
| 248 | 244 | // stop trying to write to this file |
| 249 | | self.terminal = null; |
| 245 | p.terminal = null; |
| 250 | 246 | break :winapi; |
| 251 | 247 | } |
| 252 | 248 | if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) { |
| 253 | 249 | // stop trying to write to this file |
| 254 | | self.terminal = null; |
| 250 | p.terminal = null; |
| 255 | 251 | break :winapi; |
| 256 | 252 | } |
| 257 | 253 | } else { |
| 258 | 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 | 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 | 273 | if (!self.done) { |
| 267 | 274 | var need_ellipse = false; |
| ... | ... | @@ -318,6 +325,26 @@ pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { |
| 318 | 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 | 348 | fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void { |
| 322 | 349 | if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| { |
| 323 | 350 | const amt = written.len; |