| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const windows = std.os.windows; |
| 2 | 3 | const testing = std.testing; |
| 3 | 4 | const assert = std.debug.assert; |
| 4 | 5 | |
| ... | ... | @@ -99,7 +100,12 @@ pub const Progress = struct { |
| 99 | 100 | /// API to return Progress rather than accept it as a parameter. |
| 100 | 101 | pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node { |
| 101 | 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 | 109 | self.root = Node{ |
| 104 | 110 | .context = self, |
| 105 | 111 | .parent = null, |
| ... | ... | @@ -129,12 +135,48 @@ pub const Progress = struct { |
| 129 | 135 | const prev_columns_written = self.columns_written; |
| 130 | 136 | var end: usize = 0; |
| 131 | 137 | if (self.columns_written > 0) { |
| 132 | | // restore cursor position |
| 133 | | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len; |
| 134 | | self.columns_written = 0; |
| 138 | // restore the cursor position by moving the cursor |
| 139 | // `columns_written` cells to the left, then clear the rest of the |
| 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 |
| 137 | | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; |
| 157 | const fill_chars = @intCast(windows.DWORD, info.dwSize.X - cursor_pos.X); |
| 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 | 182 | if (!self.done) { |
| ... | ... | @@ -195,7 +237,7 @@ pub const Progress = struct { |
| 195 | 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 | 241 | const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end; |
| 200 | 242 | if (end.* > max_end) { |
| 201 | 243 | const suffix = "..."; |