authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-06-03 13:29:23-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-06-03 13:29:23-04:00
log7fc3fb955abf3d510079ad5e42027b90e897dc20
treedcac380d81ee4d0dda14943614e37e17f14642fc
parent7f6ec51c8bf72ac99f619370de621fb54e77b66f
parent337f09e93297f8097e7b5093ea138b60f2c52e5f
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20172 from squeek502/windows-vt-enable

Add `File.getOrEnableAnsiEscapeSupport` and use it

3 files changed, 45 insertions(+), 4 deletions(-)

lib/std/Progress.zig+1-1
......@@ -377,7 +377,7 @@ pub fn start(options: Options) Node {
377377 }
378378 const stderr = std.io.getStdErr();
379379 global_progress.terminal = stderr;
380 if (stderr.supportsAnsiEscapeCodes()) {
380 if (stderr.getOrEnableAnsiEscapeSupport()) {
381381 global_progress.terminal_mode = .ansi_escape_codes;
382382 } else if (is_windows and stderr.isTty()) {
383383 global_progress.terminal_mode = TerminalMode{ .windows_api = .{
lib/std/fs/File.zig+42-2
......@@ -188,7 +188,7 @@ pub fn sync(self: File) SyncError!void {
188188}
189189
190190/// Test whether the file refers to a terminal.
191/// See also `supportsAnsiEscapeCodes`.
191/// See also `getOrEnableAnsiEscapeSupport` and `supportsAnsiEscapeCodes`.
192192pub fn isTty(self: File) bool {
193193 return posix.isatty(self.handle);
194194}
......@@ -245,7 +245,47 @@ pub fn isCygwinPty(file: File) bool {
245245 std.mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null;
246246}
247247
248/// Test whether ANSI escape codes will be treated as such.
248/// Returns whether or not ANSI escape codes will be treated as such,
249/// and attempts to enable support for ANSI escape codes if necessary
250/// (on Windows).
251///
252/// Returns `true` if ANSI escape codes are supported or support was
253/// successfully enabled. Returns false if ANSI escape codes are not
254/// supported or support was unable to be enabled.
255///
256/// See also `supportsAnsiEscapeCodes`.
257pub fn getOrEnableAnsiEscapeSupport(self: File) bool {
258 if (builtin.os.tag == .windows) {
259 var original_console_mode: windows.DWORD = 0;
260
261 // For Windows Terminal, VT Sequences processing is enabled by default.
262 if (windows.kernel32.GetConsoleMode(self.handle, &original_console_mode) != 0) {
263 if (original_console_mode & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0) return true;
264
265 // For Windows Console, VT Sequences processing support was added in Windows 10 build 14361, but disabled by default.
266 // https://devblogs.microsoft.com/commandline/tmux-support-arrives-for-bash-on-ubuntu-on-windows/
267 // Use Microsoft's recommended way to enable virtual terminal processing.
268 // https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#example-of-enabling-virtual-terminal-processing
269 var requested_console_modes: windows.DWORD = windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | windows.DISABLE_NEWLINE_AUTO_RETURN;
270 var console_mode = original_console_mode | requested_console_modes;
271 if (windows.kernel32.SetConsoleMode(self.handle, console_mode) != 0) return true;
272
273 // An application receiving ERROR_INVALID_PARAMETER with one of the newer console mode
274 // flags in the bit field should gracefully degrade behavior and try again.
275 requested_console_modes = windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING;
276 console_mode = original_console_mode | requested_console_modes;
277 if (windows.kernel32.SetConsoleMode(self.handle, console_mode) != 0) return true;
278 }
279
280 return self.isCygwinPty();
281 }
282 return self.supportsAnsiEscapeCodes();
283}
284
285/// Test whether ANSI escape codes will be treated as such without
286/// attempting to enable support for ANSI escape codes.
287///
288/// See also `getOrEnableAnsiEscapeSupport`.
249289pub fn supportsAnsiEscapeCodes(self: File) bool {
250290 if (builtin.os.tag == .windows) {
251291 var console_mode: windows.DWORD = 0;
lib/std/io/tty.zig+2-1
......@@ -8,6 +8,7 @@ const native_os = builtin.os.tag;
88/// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
99/// This includes feature checks for ANSI escape codes and the Windows console API, as well as
1010/// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
11/// Will attempt to enable ANSI escape code support if necessary/possible.
1112pub fn detectConfig(file: File) Config {
1213 const force_color: ?bool = if (builtin.os.tag == .wasi)
1314 null // wasi does not support environment variables
......@@ -20,7 +21,7 @@ pub fn detectConfig(file: File) Config {
2021
2122 if (force_color == false) return .no_color;
2223
23 if (file.supportsAnsiEscapeCodes()) return .escape_codes;
24 if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
2425
2526 if (native_os == .windows and file.isTty()) {
2627 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;