zsh-syntax-highlighting
zsh-syntax-highlighting copied to clipboard
syntax highlighting is super slow in WSL2
On WSL the zsh syntax highlighting worked perfectly, but in WSL2 it's extremely slow. When you type there's about a 1 second delay before your input is actually shown. Not sure if it's a problem with WSL2 or the highlighting itself.
What are the version numbers of zsh and zsh-syntax-highlighting in each environment?
@danielshahaf I'm on zsh 5.8 and the latest version of zsh syntax highlighting installed via git clone. I'm using Ubuntu-20,04 via WSL2
@danielshahaf https://github.com/danielshahaf I'm on zsh 5.8 and the latest version of zsh syntax highlighting installed via git clone. I'm using Ubuntu-20,04 via WSL2
What are the version numbers on the WSL1 environment?
Assuming everything is the same except WSL1 v. WSL2… well, I don't know of any developers who use WSL (either version), so you may have to debug this yourself. Getting a minimal reproducer (one that doesn't even involve z-sy-h, if possible), and/or employing zprof/set -x to identify the slow part, would be reasonable starting points.
encounter the same issue
To answer the deleted comment: z-sy-h uses $PATH via the type builtin to determine whether a command word should be highlighted in green or red. However, an expensive-to-access $PATH wouldn't by itself explain slowness after the command word has finished being inputted, since both z-sy-h and zsh memoize the results of filesystem queries. Related knobs include zsh's PATH_DIRS and HASH_CMDS options and related options in that section, and the rehash builtin and style. z-sy-h's memoization takes place in _zsh_highlight_main__type.
That can be ruled out simply by trying to reproduce the issue under zsh -f (and then sourcing zsh-syntax-highlighting.zsh manually).
I noticed some sluggish behaviour while on WSL2 but nothing like a 1 second delay (if I had to guess about ~200ms). The only thing that should be slow on WSL2 would be the NTFS mounts from the windows file system as they are mounted by using 9P. I have added the windows mount in the directory blacklist as mentioned here: https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters/main.md#parameters
ZSH_HIGHLIGHT_DIRS_BLACKLIST+=(/mnt/c)
This makes the "cold" highlighting after a fresh start a bit faster. Surprisingly enough it still recognizes commands like code as valid commands and highlights them green/red accordingly although being located in /mnt/c/. However, as mentioned by @danielshahaf the Path lookups are memorized and it shouldn't make that big difference.
Adding ZSH_HIGHLIGHT_DIRS_BLACKLIST doesn't seem to change anything.
Is there anything else to try?
Try zsh 5.9. I don't know that any maintainer has WSL, so, y'all may need to help investigate. Does it reproduce in zsh -f? Do make check and make perf work? Does zsh/zprof show anything (don't forget to zprof -c before starting the timed section)? Can you try a different terminal?
(I just posted that on #899, but it works equally well as an answer to @wywywywy.)
I solved this by excluding windows directories from $PATH by adding following in /etc/wsl.conf. Create the file if it doesn't exist
[interop]
appendWindowsPath = false
Then restart wsl with
wsl --shutdown
It's also possible to disable the possibility to run windows binaries inside WSL instances with the following in /etc/wsl.conf. I didn't do this myself since the above solved my performance problems I had
enabled = false
I solved this by excluding windows directories from
$PATHby adding following in/etc/wsl.conf. Create the file if it doesn't exist[interop] appendWindowsPath = false
For my use case I still want some Windows paths. For example the code command is found in /mnt/c/Users/<user>/AppData/Local/Programs/Microsoft VS Code/bin
I solved this by excluding windows directories from
$PATHby adding following in/etc/wsl.conf. Create the file if it doesn't exist[interop] appendWindowsPath = falseFor my use case I still want some Windows paths. For example the
codecommand is found in/mnt/c/Users/pcrei/AppData/Local/Programs/Microsoft VS Code/bin
You could make some aliases for your common windows commands if you still wanted to exclude the windows directories from the $PATH. For example alias code=/mnt/c/vscode.exe
I ended up manually adding that bin to PATH, which didn't noticeably slow down performance:
export PATH="/mnt/c/Users/<user>/AppData/Local/Programs/Microsoft VS Code/bin:$PATH"
I wonder which windows paths causes the poor performance of syntax highlighting.
I ended up manually adding that bin to
PATH, which didn't noticeably slow down performance:export PATH="/mnt/c/Users/<user>/AppData/Local/Programs/Microsoft VS Code/bin:$PATH"I wonder which windows paths causes the poor performance of syntax highlighting.
I imagine it's not any specific paths that causes the slowdown, it's probably just the number of paths.
@amimof Thanks for the info that removing some entries from $path resolves the slowness.
First, I'd like to check whether there are any other causes of slowness at play here. So:
-
After applying the workaround proposed in https://github.com/zsh-users/zsh-syntax-highlighting/issues/790#issuecomment-1385406603 by @amimof, does anyone observe slowness that isn't covered by some other open issue? [Note I haven't reviewed the workaround.]
-
Does slowness happen at words other than command words? For instance, when completing --options, arguments to them, or positional arguments (filenames to ls(1), hostname to ping(1), etc.).
-
There's caching going on, both at the zsh level (see the
rehashbuiltin) and at the z-sy-h level (in_zsh_highlight_main__type()). Negative matches are cached at the z-sy-h level — to see that, runprint -raC2 - "${(@kv)_zsh_highlight_main__command_type_cache}"and observe thenoneentries — so, in theory, once you've typedfoobarin command position once, the next time you typefoobarin command position will be highlighted quickly. Is that what happens?
I wonder which windows paths causes the poor performance of syntax highlighting.
I imagine it's not any specific paths that causes the slowdown, it's probably just the number of paths.
WSL2 is well known to have poor performance interacting with Windows' filesystem. There's an open issue dating back to 2019: https://github.com/microsoft/WSL/issues/4197
Workarounds include working inside WSL2's filesystem or creating an NFS server and use that instead (which funnily enough, seems to work faster than the native WSL2's way of doing it).
This performance issue directly affects anything that has to do with Windows' path, to list a couple:
- https://github.com/microsoft/WSL/issues/4234
- https://github.com/kubernetes/kubectl/issues/1336
- https://github.com/microsoft/WSL/issues/4401
I solved this by excluding windows directories from
$PATHby adding following in/etc/wsl.conf. Create the file if it doesn't exist[interop] appendWindowsPath = false
This workaround "solves" the problem. By removing Window's paths from WSL2 we won't take the performance hit of doing lookups outside Linux... but we lose a bit of the cool integration with Windows.
Using ZSH_HIGHLIGHT_DIRS_BLACKLIST should help, but I'm not sure why it still feels slow... it's as if there were still some lookups happening on Windows's filesystem. Maybe there's some other paths that are symlinks to Windows? I'm not sure how to go about trying to figure that one out.
From what I can gather, the /mnt/c/WINDOWS/System32 path has a lot of files and is most likely the culprit here: it has over 5k items!
So added this appendWindowsPath flag and re-added some of my Windows' paths to my .zshrc (including the Windows folder itself), and the slowness is gone for me (these are most likely what the average coder using WSL2 will need anyway):
# .zshrc
### Windows ###
export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Microsoft/WindowsApps"
export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Programs/Microsoft VS Code/bin"
export PATH="$PATH:/mnt/c/Program Files/Docker/Docker/resources/bin"
export PATH="$PATH:/mnt/c/ProgramData/DockerDesktop/version-bin"
export PATH="$PATH:/mnt/c/WINDOWS"
Maybe we just need to figure out why ZSH_HIGHLIGHT_DIRS_BLACKLIST doesn't seem to work?
Sinuhé Coronel wrote on Mon, 23 Jan 2023 07:22 +00:00:
So added this
appendWindowsPathflag and re-added some of my Windows' paths to my.zshrc(including the Windows folder itself), and the slowness is gone for me (these are most likely what the average coder using WSL2 will need anyway):# .zshrc ### Windows ### export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Microsoft/WindowsApps" export PATH="$PATH:/mnt/c/Users/lesmo/AppData/Local/Programs/Microsoft VS Code/bin" export PATH="$PATH:/mnt/c/Program Files/Docker/Docker/resources/bin" export PATH="$PATH:/mnt/c/ProgramData/DockerDesktop/version-bin" export PATH="$PATH:/mnt/c/WINDOWS"
This might be more readable with the array counterpart of $PATH:
path+=(
/mnt/c/Users/lesmo/AppData/Local/Microsoft/WindowsApps
/mnt/c/Users/lesmo/AppData/Local/Programs/Microsoft VS Code/bin
/mnt/c/Program Files/Docker/Docker/resources/bin
/mnt/c/ProgramData/DockerDesktop/version-bin
/mnt/c/WINDOWS
)
Maybe we just need to figure out why `ZSH_HIGHLIGHT_DIRS_BLACKLIST` doesn't seem to work?
ZSH_HIGHLIGHT_DIRS_BLACKLIST only applies to words literally typed on the command line. It doesn't magically cause $PATH directories not to be hashed. That's actually a zsh functionality, not a z-sy-h one. So, perhaps this:
() {
set -- $path # save $PATH without overwriting any user variables
path=( /some /directories /that /can /be /stat\(2\)ed /performantly )
rehash
path=( "$@" )
}
With this, commands from other directories will only be runnable by
their full paths, or after running rehash again.
May need to add an 'always' block, depending on how exactly the temporary value of $PATH is computed.
I solved this by excluding windows directories from
$PATHby adding following in/etc/wsl.conf. Create the file if it doesn't exist[interop] appendWindowsPath = falseThen restart wsl with
wsl --shutdownIt's also possible to disable the possibility to run windows binaries inside WSL instances with the following in
/etc/wsl.conf. I didn't do this myself since the above solved my performance problems I hadenabled = false
@amimof Thanks, that's useful for me.
marked, helped me as well
same problem here, but I still want to keep windows path in WSL2, because I often use windows commands like clip.exe, cmd.exe, etc. and I don't want to alias all command one by one, that will be annoying.
maybe there's a bug of ZSH_HIGHLIGHT_DIRS_BLACKLIST?
Thank you @amimof, it worked for me.
Thank you! That helps a lot!
Thank you @amimof, It's propery worked fine