New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing 'shell'
on Windows, properly
#28384
Comments
For the record, being more restrictive (and explicit) about which "shells" we support on Windows is an option here (though maybe not for 0.10). |
In the sense of saying "we only support cmd.exe and powershell", or "we eventually stop supporting cmd.exe"? I use Neovim on Windows exclusively through an MSYS2 environment, and while I understand it's not an officially supported use case/"platform", I would really like for unix shells to be supported and working. Lots of people use Git Bash on Windows for example. I think, generally speaking: For non-cmd.exe, we should completely ignore shellquote/shellxquote/shellxescape/etc, not do any quoting/escaping of our own, and instead let libuv handle it for us. This will work correctly with any program that uses the regular C runtime argument handling (including, I believe, powershell/pwsh). For cmd.exe, we could continue using the existing code paths and tell libuv to pass the arguments verbatim as we do now. libuv does not handle cmd.exe specially in any way, so this seems reasonable if it's important that the edge cases are handled proper. I could imagine a future where Neovim simply doesn't support cmd.exe as a shell anymore, and defaults to powershell. I can't think of anything that would definitely break, since users are already free to change the shell settings away from cmd.exe, so nothing inside of Neovim should really have a hard dependency on it, but I still imagine it may cause some churn. Either way, that decision should not stand in the way of fixing the existing use cases today. |
That's what I was thinking, yes, if it allows things to work better on other platforms (including win shells) and the alternatives are reasonable. In any case, it would be helpful to gather some data on 1. which shells/platforms are actually used on Windows and 2. the issues each have (what works, what doesn't, what requires jumping through hoops). |
Nice analysis!
Seems like a separate topic. Based on this thread, I don't see a reason to drop support for a particular shell?
Based on the git logs, I don't see a rationale for why f3cc843 special-cased "cmd.exe", I assume it was just conservative.
Sure, let's try it. Existing tests are here:
|
One thing I'd definitely like to fix is this :make
:!cargo 2>&1| tee F:\msys2\tmp\nvim.0\cn0m97\2
cargo 2>&1| tee F:\msys2 mp
vim.0error
...
E40: Can't open errorfile F:\msys2\tmp\nvim.0\cn0m97\2 The weird printing seems to be zsh specific, but even with bash it still doesn't write the correct file, so quickfix is broken. I think the temporary file path should be obeying
I'm not sure how involved of a fix that is, but seeing as Neovim doesn't currently use UNC paths, I don't see a big issue. |
Or |
That would be a more radical if for my purposes equally workable solution.
The There are still weird edge cases that use the "DOS device" path format, like named pipes. I don't know that we care about this, but for the sake of completeness I'm mentioning it. |
(Again, this is just opening a door to more options for a solution to these issues, not a push to do that.) Note we claim support for Windows >= 8, but that, too, can be revisited. We need to distinguish platform tiers ( |
We use named pipes. Does it not support forward slashes? In any case I'm not sure we need to care, because we don't treat named pipes as filesystem paths. |
I will one-up you and claim we already don't support anything older than Windows 10 "Version 1809" as the One might argue that this quasi-bump in minimum version was accidental and that it should therefore count more as a bug/accident than intentional. I personally think this is a bit weak stance as documenting this problem is already an admission from our side that we don't see this being resolved soon. I propose we simply bite the bullet and officially only support Windows 10 "Version 1809" to simplify the question on which windows version we support (which is brought up surprisingly frequently). |
Was briefly mentioned as part of neovim#28384 Allows Windows file APIs (and anything that uses them) to bypass the 260-character `MAX_PATH` limitation on Windows 10 1607 or later. NOTE: This change by itself does not change the behaviour of running Neovim. The system must also have the Windows registry key `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled` set to a `REG_DWORD` with value 1. See https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=powershell#enable-long-paths-in-windows-10-version-1607-and-later for more information.
Yes. The current wording implies that ":terminal" is not covered by "support". It's a slippery slope I would like to get off of. It strikes me as weird that we support significantly more versions than our core dependencies (libuv; would have to check tree-sitter). |
ref #28384 Allows Windows file APIs (and anything that uses them) to bypass the 260-character `MAX_PATH` limitation on Windows 10 1607 or later. NOTE: This change by itself does not change the behaviour of running Neovim. The system must also have the Windows registry key `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled` set to a `REG_DWORD` with value 1. See https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=powershell#enable-long-paths-in-windows-10-version-1607-and-later for more information.
Linking #28395 since the topic of slash handling got brought up here. Treating this as a sort of "tracking issue" while the details of what we want to change/fix aren't fully decided yet. If/when that PR lands, I would try and take stock of what works/doesn't on Windows with various shells and try to implement the "let's have libuv alone handle non-cmd shells" strategy, unless there are strong objections or other things to try first. |
Problem
See #16957 for some of the existing issues with using a Unix shell in Neovim on Windows.
I've dug into it now, seeing as no workaround really managed to fully take, and here's what I was able to find.
The root of evil is the fact that
CreateProcessA
takes some long string as the command line. The Microsoft C runtime takes that string, runs it through splitting logic described here, then passes the processed result tomain
. The result of that processing is what'shell'
ultimately receives.Vim on the other hand, wants to be able to think about running programs in terms of regular C
argv
arrays.Assuming
shell=bash
,shellcmdflag=-c
andshellxquote="
, running!ls -l
, produces the argument vector[bash, -c, "ls -l"]
(note the quotes aroundls -l
). The resulting argument vector is then passed to libuv, which then reconstitutes the entire thing back to a single string so it can pass it toCreateProcessA
.This is where the issue arises. libuv expects an unquoted argument vector (
[bash, -c, ls -l]
, no quotes), as you would pass toexecve
on Unix, but gets[bash, -c, "ls -l"]
instead. This causes it to quote the quoted string on Windows, which ultimately causes bash to receive the command"ls -l"
(one shell word, with quotes) instead ofls -l
(two shell words, no quotes).So, basically, there are two places in the chain that are trying to make the argument vector "windows-friendly": Vim's
shell_build_argv
, and libuv'smake_program_args
. Only one of the two should be done. To only use vim's behaviour, it is probably sufficient to change libuv_process_spawn to always passUV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS
. Sincecmd.exe
already has to use this behaviour since its argument parsing does not follow that of the C runtime (i.e. all other programs), this seems like it will cause the least amount of breakage.To only follow libuv's behaviour (an arguably more sound strategy but that may not work with cmd.exe), we'd simply need to skip
shell_xescape_xquote
(or set bothshellxescape
andshellxquote
to the empty string?).Whichever the case may be, it's pretty clear that Neovim's current behaviour on Windows is incorrect. Double quoting like this shouldn't occur, and having two completely different implementations both doing argv-sanitation depending on context is bound to lead to issues. (As it did very recently for Rust)
There's also some other issues. For example, Neovim tries to pass
2>&1 | tee <tempfile>
to the shell. However, the Windows-style backslash-using tempfile path will cause the shell to misinterpret something likeC:\somedir\tmp\
to contain a\t
(tab) (at least in zsh) and cause it to spit out the file in the wrong place, causing errors in:make
,:grep
, etc. Easiest solution would be to change the path to use/
as the separator (possibly in accordance with'shellslash'
, which doesn't apply to the temporary file arguments currently) (though this will also not work for UNC paths), or to use something likecygpath
if available (most unix shells on Windows are cygwin/msys2 based).Steps to reproduce
nvim --clean
:set shell=C:/path/to/bash.exe shellcmdflag=-c
:!echo test <- fails
:set shellxquote=
:!echo test <- works
(and many other such cases)
Expected behavior
We should figure out a way to fix this properly, once and for all.
Neovim version (nvim -v)
master
Vim (not Nvim) behaves the same?
Have not verified, but it seems to be Neovim specific
Operating system/version
Windows 10/11
Terminal name/version
wezterm, but doesn't matter (not TUI related)
$TERM environment variable
xterm-256color
Installation
GitHub nightly releases
The text was updated successfully, but these errors were encountered: