From d660233edfffed3d358f109e1456e74597efa701 Mon Sep 17 00:00:00 2001 From: Elijah Koulaxis <90087463+kx0101@users.noreply.github.com> Date: Mon, 6 Apr 2026 02:16:48 +0300 Subject: [PATCH] fix(windows): force console codepage to UTF-8 for shell/system() #38742 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: On Windows, `:!echo тест` shows `????` because the console code page defaults to a legacy ANSI encoding (e.g. CP1252) instead of `UTF-8` Solution: Call `SetConsoleOutputCP(CP_UTF8)` and `SetConsoleCP(CP_UTF8)` in `do_os_system()` before spawning child processes, and restore the original values after. It covers both `:!` and `system()` since they both go through `do_os_system()` (cherry picked from commit bba48ee1b0c6070e0aaacc1d8a40848179cc64d9) --- src/nvim/os/shell.c | 8 ++++++++ test/functional/vimscript/system_spec.lua | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 83af72d8f2..f1eec952fb 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -867,6 +867,12 @@ static int do_os_system(char **argv, const char *input, size_t len, char **outpu // environment variable $NoDefaultCurrentDirectoryInExePath char *oldval = os_getenv("NoDefaultCurrentDirectoryInExePath"); os_setenv("NoDefaultCurrentDirectoryInExePath", "1", true); + + UINT old_output_cp = GetConsoleOutputCP(); + UINT old_input_cp = GetConsoleCP(); + // Force console codepage to UTF-8 before spawning child process. #33480 + SetConsoleOutputCP(CP_UTF8); + SetConsoleCP(CP_UTF8); #endif out_data_decide_throttle(0); // Initialize throttle decider. @@ -982,6 +988,8 @@ end: #ifdef MSWIN // Restore original value of NoDefaultCurrentDirectoryInExePath restore_env_var("NoDefaultCurrentDirectoryInExePath", oldval, true); + SetConsoleOutputCP(old_output_cp); + SetConsoleCP(old_input_cp); #endif return exitcode; diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua index 67a613d848..09b7b739f9 100644 --- a/test/functional/vimscript/system_spec.lua +++ b/test/functional/vimscript/system_spec.lua @@ -166,6 +166,11 @@ describe('system()', function() test_shell_unquoting() end) + it('spawns child process with UTF-8 codepage', function() + command('set shell=cmd.exe') + eq('тест\n', eval([[system('echo тест')]])) + end) + it('with shell=cmd', function() command('set shell=cmd') eq('"a b"\n', eval([[system('echo "a b"')]]))