diff --git a/src/main.zig b/src/main.zig index 07eac25..ac07ea6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -17,6 +17,35 @@ const inspect_mode = @import("modes/inspect.zig"); const repl_mode = @import("modes/repl.zig"); const completions_mod = @import("completions.zig"); +// Windows console UTF-8 setup (Issue #201) +const DWORD = std.os.windows.DWORD; +const HANDLE = std.os.windows.HANDLE; +const BOOL = std.os.windows.BOOL; +const UINT = std.os.windows.UINT; +const LPDWORD = *DWORD; + +const STD_OUTPUT_HANDLE: DWORD = @bitCast(@as(i32, -11)); // 0xFFFFFFF5 +const ENABLE_VIRTUAL_TERMINAL_PROCESSING: DWORD = 0x0004; +const INVALID_HANDLE_VALUE: HANDLE = @ptrFromInt(std.math.maxInt(usize)); + +extern "kernel32" fn SetConsoleOutputCP(wCodePageID: UINT) callconv(.winapi) BOOL; +extern "kernel32" fn GetStdHandle(nStdHandle: DWORD) callconv(.winapi) HANDLE; +extern "kernel32" fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) callconv(.winapi) BOOL; +extern "kernel32" fn SetConsoleMode(hConsoleHandle: HANDLE, dwMode: DWORD) callconv(.winapi) BOOL; + +/// Best-effort UTF-8 + VT support for the Windows console (Issue #201). +/// No-op on non-Windows: body eliminated at compile time. +fn setupConsoleOutput() void { + if (@import("builtin").os.tag == .windows) { + _ = SetConsoleOutputCP(65001); + const handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle == INVALID_HANDLE_VALUE) return; + var mode: DWORD = 0; + _ = GetConsoleMode(handle, &mode); + _ = SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + } +} + const VERSION: []const u8 = build_options.version; const SqlPipeError = args_mod.SqlPipeError; @@ -374,6 +403,9 @@ pub fn main(init: std.process.Init.Minimal) void { // ponytail: c_allocator; DebugAllocator deinit was _ = discarded, leak detection was off const allocator = std.heap.c_allocator; + // Windows: enable UTF-8 output + VT processing for box-drawing chars (Issue #201) + setupConsoleOutput(); + var io = std.Io.Threaded.init_single_threaded; var stderr_buf: [1024]u8 = undefined;