diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig index 8cdf07c1aa..b50143b075 100644 --- a/lib/std/os/windows/kernel32.zig +++ b/lib/std/os/windows/kernel32.zig @@ -83,6 +83,9 @@ pub extern "kernel32" fn GetCommandLineA() callconv(.Stdcall) LPSTR; pub extern "kernel32" fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) callconv(.Stdcall) BOOL; pub extern "kernel32" fn GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) callconv(.Stdcall) BOOL; +pub extern "kernel32" fn FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: TCHAR, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfCharsWritten: LPDWORD) callconv(.Stdcall) BOOL; +pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: LPDWORD) callconv(.Stdcall) BOOL; +pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(.Stdcall) BOOL; pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(.Stdcall) DWORD; diff --git a/lib/std/progress.zig b/lib/std/progress.zig index a693ec8619..bde67f1a23 100644 --- a/lib/std/progress.zig +++ b/lib/std/progress.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const windows = std.os.windows; const testing = std.testing; const assert = std.debug.assert; @@ -99,7 +100,12 @@ pub const Progress = struct { /// API to return Progress rather than accept it as a parameter. pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node { const stderr = std.io.getStdErr(); - self.terminal = if (stderr.supportsAnsiEscapeCodes()) stderr else null; + self.terminal = null; + if (stderr.supportsAnsiEscapeCodes()) { + self.terminal = stderr; + } else if (std.builtin.os.tag == .windows and stderr.isTty()) { + self.terminal = stderr; + } self.root = Node{ .context = self, .parent = null, @@ -129,12 +135,48 @@ pub const Progress = struct { const prev_columns_written = self.columns_written; var end: usize = 0; if (self.columns_written > 0) { - // restore cursor position - end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len; - self.columns_written = 0; + // restore the cursor position by moving the cursor + // `columns_written` cells to the left, then clear the rest of the + // line + if (std.builtin.os.tag != .windows) { + end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len; + end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; + } else { + var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; + if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) + unreachable; - // clear rest of line - end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; + var cursor_pos = windows.COORD{ + .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written), + .Y = info.dwCursorPosition.Y, + }; + + if (cursor_pos.X < 0) + cursor_pos.X = 0; + + const fill_chars = @intCast(windows.DWORD, info.dwSize.X - cursor_pos.X); + + var written: windows.DWORD = undefined; + if (windows.kernel32.FillConsoleOutputAttribute( + file.handle, + info.wAttributes, + fill_chars, + cursor_pos, + &written, + ) != windows.TRUE) unreachable; + if (windows.kernel32.FillConsoleOutputCharacterA( + file.handle, + ' ', + fill_chars, + cursor_pos, + &written, + ) != windows.TRUE) unreachable; + + if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) + unreachable; + } + + self.columns_written = 0; } if (!self.done) { @@ -195,7 +237,7 @@ pub const Progress = struct { end.* = self.output_buffer.len; }, } - const bytes_needed_for_esc_codes_at_end = 11; + const bytes_needed_for_esc_codes_at_end = if (std.builtin.os.tag == .windows) 0 else 11; const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end; if (end.* > max_end) { const suffix = "..."; diff --git a/src/analyze.cpp b/src/analyze.cpp index ef23e896e3..89ad5aca74 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -9044,7 +9044,7 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) { FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; bool first_arg_return = want_first_arg_sret(g, fn_type_id); bool is_async = fn_type_id->cc == CallingConventionAsync; - bool is_c_abi = fn_type_id->cc == CallingConventionC; + bool is_c_abi = !calling_convention_allows_zig_types(fn_type_id->cc); bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id); // +1 for maybe making the first argument the return value // +1 for maybe first argument the error return trace diff --git a/src/codegen.cpp b/src/codegen.cpp index dad8e4768a..730f2695e0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2071,7 +2071,7 @@ var_ok: void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { CallingConvention cc = fn_type->data.fn.fn_type_id.cc; - if (cc == CallingConventionC) { + if (!calling_convention_allows_zig_types(cc)) { size_t src_i = 0; for (;;) { if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i)) @@ -7862,7 +7862,7 @@ static void do_code_gen(CodeGen *g) { FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; CallingConvention cc = fn_type_id->cc; - bool is_c_abi = cc == CallingConventionC; + bool is_c_abi = !calling_convention_allows_zig_types(cc); bool want_sret = want_first_arg_sret(g, fn_type_id); LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);