| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| | 2 | const windows = std.os.windows; |
| 2 | const testing = std.testing; | 3 | const testing = std.testing; |
| 3 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 4 | | 5 | |
| ... | @@ -99,7 +100,12 @@ pub const Progress = struct { | ... | @@ -99,7 +100,12 @@ pub const Progress = struct { |
| 99 | /// API to return Progress rather than accept it as a parameter. | 100 | /// API to return Progress rather than accept it as a parameter. |
| 100 | pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node { | 101 | pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node { |
| 101 | const stderr = std.io.getStdErr(); | 102 | const stderr = std.io.getStdErr(); |
| 102 | self.terminal = if (stderr.supportsAnsiEscapeCodes()) stderr else null; | 103 | self.terminal = null; |
| | 104 | if (stderr.supportsAnsiEscapeCodes()) { |
| | 105 | self.terminal = stderr; |
| | 106 | } else if (std.builtin.os.tag == .windows and stderr.isTty()) { |
| | 107 | self.terminal = stderr; |
| | 108 | } |
| 103 | self.root = Node{ | 109 | self.root = Node{ |
| 104 | .context = self, | 110 | .context = self, |
| 105 | .parent = null, | 111 | .parent = null, |
| ... | @@ -129,12 +135,48 @@ pub const Progress = struct { | ... | @@ -129,12 +135,48 @@ pub const Progress = struct { |
| 129 | const prev_columns_written = self.columns_written; | 135 | const prev_columns_written = self.columns_written; |
| 130 | var end: usize = 0; | 136 | var end: usize = 0; |
| 131 | if (self.columns_written > 0) { | 137 | if (self.columns_written > 0) { |
| 132 | // restore cursor position | 138 | // restore the cursor position by moving the cursor |
| 133 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len; | 139 | // `columns_written` cells to the left, then clear the rest of the |
| 134 | self.columns_written = 0; | 140 | // line |
| | 141 | if (std.builtin.os.tag != .windows) { |
| | 142 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len; |
| | 143 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; |
| | 144 | } else { |
| | 145 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; |
| | 146 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) |
| | 147 | unreachable; |
| | 148 | |
| | 149 | var cursor_pos = windows.COORD{ |
| | 150 | .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written), |
| | 151 | .Y = info.dwCursorPosition.Y, |
| | 152 | }; |
| | 153 | |
| | 154 | if (cursor_pos.X < 0) |
| | 155 | cursor_pos.X = 0; |
| 135 | | 156 | |
| 136 | // clear rest of line | 157 | const fill_chars = @intCast(windows.DWORD, info.dwSize.X - cursor_pos.X); |
| 137 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; | 158 | |
| | 159 | var written: windows.DWORD = undefined; |
| | 160 | if (windows.kernel32.FillConsoleOutputAttribute( |
| | 161 | file.handle, |
| | 162 | info.wAttributes, |
| | 163 | fill_chars, |
| | 164 | cursor_pos, |
| | 165 | &written, |
| | 166 | ) != windows.TRUE) unreachable; |
| | 167 | if (windows.kernel32.FillConsoleOutputCharacterA( |
| | 168 | file.handle, |
| | 169 | ' ', |
| | 170 | fill_chars, |
| | 171 | cursor_pos, |
| | 172 | &written, |
| | 173 | ) != windows.TRUE) unreachable; |
| | 174 | |
| | 175 | if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) |
| | 176 | unreachable; |
| | 177 | } |
| | 178 | |
| | 179 | self.columns_written = 0; |
| 138 | } | 180 | } |
| 139 | | 181 | |
| 140 | if (!self.done) { | 182 | if (!self.done) { |
| ... | @@ -195,7 +237,7 @@ pub const Progress = struct { | ... | @@ -195,7 +237,7 @@ pub const Progress = struct { |
| 195 | end.* = self.output_buffer.len; | 237 | end.* = self.output_buffer.len; |
| 196 | }, | 238 | }, |
| 197 | } | 239 | } |
| 198 | const bytes_needed_for_esc_codes_at_end = 11; | 240 | const bytes_needed_for_esc_codes_at_end = if (std.builtin.os.tag == .windows) 0 else 11; |
| 199 | const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end; | 241 | const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end; |
| 200 | if (end.* > max_end) { | 242 | if (end.* > max_end) { |
| 201 | const suffix = "..."; | 243 | const suffix = "..."; |