diff --git a/src/bun.js/webcore.zig b/src/bun.js/webcore.zig index ab76f70729..5f55258ecf 100644 --- a/src/bun.js/webcore.zig +++ b/src/bun.js/webcore.zig @@ -267,7 +267,7 @@ pub const Prompt = struct { // unset `ENABLE_VIRTUAL_TERMINAL_INPUT` on windows. This prevents backspace from // deleting the entire line const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows) - bun.win32.unsetStdioModeFlags(0, bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT) catch null; + bun.win32.updateStdioModeFlags(0, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null; defer if (comptime Environment.isWindows) { if (original_mode) |mode| { diff --git a/src/bun.zig b/src/bun.zig index 62fae99f6b..e75552448c 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -2356,25 +2356,12 @@ pub const win32 = struct { pub var STDERR_FD: FileDescriptor = undefined; pub var STDIN_FD: FileDescriptor = undefined; - /// Returns the original mode - pub fn unsetStdioModeFlags(i: anytype, flags: w.DWORD) !w.DWORD { - const fd = stdio(i); - var original_mode: w.DWORD = 0; - if (windows.kernel32.GetConsoleMode(fd.cast(), &original_mode) != 0) { - if (windows.kernel32.SetConsoleMode(fd.cast(), original_mode & ~flags) == 0) { - return windows.getLastError(); - } - } else return windows.getLastError(); - - return original_mode; - } - - /// Returns the original mode - pub fn setStdioModeFlags(i: anytype, flags: w.DWORD) !w.DWORD { + /// Returns the original mode, or null on failure + pub fn updateStdioModeFlags(i: anytype, opts: struct { set: w.DWORD = 0, unset: w.DWORD = 0 }) !w.DWORD { const fd = stdio(i); var original_mode: w.DWORD = 0; if (windows.GetConsoleMode(fd.cast(), &original_mode) != 0) { - if (windows.SetConsoleMode(fd.cast(), original_mode | flags) == 0) { + if (windows.SetConsoleMode(fd.cast(), (original_mode | opts.set) & ~opts.unset) == 0) { return windows.getLastError(); } } else return windows.getLastError(); diff --git a/src/cli/init_command.zig b/src/cli/init_command.zig index 6d47f30bae..0e063be053 100644 --- a/src/cli/init_command.zig +++ b/src/cli/init_command.zig @@ -41,7 +41,7 @@ pub const InitCommand = struct { // unset `ENABLE_VIRTUAL_TERMINAL_INPUT` on windows. This prevents backspace from // deleting the entire line const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows) - bun.win32.unsetStdioModeFlags(0, bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT) catch null; + bun.win32.updateStdioModeFlags(0, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null; defer if (comptime Environment.isWindows) { if (original_mode) |mode| { @@ -122,9 +122,6 @@ pub const InitCommand = struct { } initial_draw = false; - // Clear from cursor to end of screen - Output.clearToEnd(); - // Print options vertically inline for (choices, 0..) |option, i| { if (i == @intFromEnum(selected)) { @@ -134,14 +131,15 @@ pub const InitCommand = struct { Output.pretty("> ", .{}); } if (colors) { - Output.print("\x1B[4m{s}\x1B[24m\n", .{option}); + Output.print("\x1B[4m{s}\x1B[24m\x1B[0K\n", .{option}); } else { - Output.print(" {s}\n", .{option}); + Output.print(" {s}\x1B[0K\n", .{option}); } } else { - Output.print(" {s}\n", .{option}); + Output.print(" {s}\x1B[0K\n", .{option}); } } + Output.clearToEnd(); Output.flush(); @@ -208,7 +206,12 @@ pub const InitCommand = struct { // Set raw mode to read single characters without echo const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows) - bun.win32.unsetStdioModeFlags(0, bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT) catch null; + bun.win32.updateStdioModeFlags(0, .{ + // virtual terminal input enables arrow keys, processed input lets ctrl+c kill the program + .set = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT | bun.windows.ENABLE_PROCESSED_INPUT, + // disabling line input sends keys immediately, disabling echo input makes sure it doesn't print to the terminal + .unset = bun.windows.ENABLE_LINE_INPUT | bun.windows.ENABLE_ECHO_INPUT, + }) catch null; if (Environment.isPosix) _ = Bun__ttySetMode(0, 1); diff --git a/src/cli/publish_command.zig b/src/cli/publish_command.zig index 59755decd8..94b9116e81 100644 --- a/src/cli/publish_command.zig +++ b/src/cli/publish_command.zig @@ -682,7 +682,7 @@ pub const PublishCommand = struct { // unset `ENABLE_VIRTUAL_TERMINAL_INPUT` on windows. This prevents backspace from // deleting the entire line const original_mode: if (Environment.isWindows) ?bun.windows.DWORD else void = if (comptime Environment.isWindows) - bun.win32.unsetStdioModeFlags(0, bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT) catch null; + bun.win32.updateStdioModeFlags(0, .{ .unset = bun.windows.ENABLE_VIRTUAL_TERMINAL_INPUT }) catch null; defer if (comptime Environment.isWindows) { if (original_mode) |mode| { diff --git a/src/windows.zig b/src/windows.zig index ecf2de5334..0530e0e1ee 100644 --- a/src/windows.zig +++ b/src/windows.zig @@ -3477,6 +3477,9 @@ pub extern "kernel32" fn GetThreadDescription( *PWSTR, // [out] ) std.os.windows.HRESULT; +pub const ENABLE_ECHO_INPUT = 0x004; +pub const ENABLE_LINE_INPUT = 0x002; +pub const ENABLE_PROCESSED_INPUT = 0x001; pub const ENABLE_VIRTUAL_TERMINAL_INPUT = 0x200; pub const ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002; pub const ENABLE_PROCESSED_OUTPUT = 0x0001;