authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-04-22 12:58:02+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-04-22 12:58:02+02:00
log155e631aa6f9fabc101abceeeec00b4808a3e4e3
tree7bc571311b748170d6bf7b1d6c9ecd5a81614852
parent395b5303877601ff0752baf0ca1489c652358248

std: Implement progress for Windows

Use the Win32 API instead of using the VT escape sequences.

2 files changed, 52 insertions(+), 7 deletions(-)

lib/std/os/windows/kernel32.zig+3
......@@ -83,6 +83,9 @@ pub extern "kernel32" fn GetCommandLineA() callconv(.Stdcall) LPSTR;
8383pub extern "kernel32" fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) callconv(.Stdcall) BOOL;
8484
8585pub extern "kernel32" fn GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) callconv(.Stdcall) BOOL;
86pub extern "kernel32" fn FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: TCHAR, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfCharsWritten: LPDWORD) callconv(.Stdcall) BOOL;
87pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: LPDWORD) callconv(.Stdcall) BOOL;
88pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(.Stdcall) BOOL;
8689
8790pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(.Stdcall) DWORD;
8891
lib/std/progress.zig+49-7
......@@ -1,4 +1,5 @@
11const std = @import("std");
2const windows = std.os.windows;
23const testing = std.testing;
34const assert = std.debug.assert;
45
......@@ -99,7 +100,12 @@ pub const Progress = struct {
99100 /// API to return Progress rather than accept it as a parameter.
100101 pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node {
101102 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 }
103109 self.root = Node{
104110 .context = self,
105111 .parent = null,
......@@ -129,12 +135,48 @@ pub const Progress = struct {
129135 const prev_columns_written = self.columns_written;
130136 var end: usize = 0;
131137 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;
135156
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;
138180 }
139181
140182 if (!self.done) {
......@@ -195,7 +237,7 @@ pub const Progress = struct {
195237 end.* = self.output_buffer.len;
196238 },
197239 }
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;
199241 const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end;
200242 if (end.* > max_end) {
201243 const suffix = "...";