msys true in pipe to vim with termguicolors causes escape codes to be displayed in terminal #16535

Closed
opened 2026-01-31 05:14:57 +00:00 by claunia · 9 comments
Owner

Originally created by @kevinoid on GitHub (Jan 30, 2022).

Windows Terminal version

1.11.3471.0

Windows build number

10.0.19043.1466

Other Software

Git 2.35.0
Vim 8.4.4227

Steps to reproduce

To reproduce with cmd (in WT or Conhost), run:

"C:\Program Files\Git\usr\bin\perl.exe" -e "for (1..100) { `true` }" | vim --clean --cmd "set tgc" -

To reproduce with powershell or pwsh (in WT or Conhost), run:

& 'C:\Program Files\Git\usr\bin\perl.exe' -e 'for (1..100) { `true` }' | vim --clean --cmd 'set tgc' -

It can also be reproduced by running git show $commit if core.pager=vim, vimrc has set tgc, and $commit includes changes to a .docx file, which is how I initially encountered the issue: Git for Windows has *.docx diff=astextplain which invokes astextplain which invokes docx2txt.pl which invokes unzip twice. I found the reproduction to be more reliable if perl invokes another program more times. 100 invocations reliably reproduces the issue on my system.

Expected Behavior

Vim would show its default empty-input startup screen:
Screenshot of Vim default empty-input startup screen in Windows Terminal

Actual Behavior

The first and last row of the terminal shows what appear to be terminal escape codes. Keyboard input changes the escape codes, rather than appearing as expected:
Screenshot of Vim showing escape codes in Windows Terminal

Originally created by @kevinoid on GitHub (Jan 30, 2022). ### Windows Terminal version 1.11.3471.0 ### Windows build number 10.0.19043.1466 ### Other Software Git 2.35.0 Vim 8.4.4227 ### Steps to reproduce To reproduce with `cmd` (in WT or Conhost), run: ```cmd "C:\Program Files\Git\usr\bin\perl.exe" -e "for (1..100) { `true` }" | vim --clean --cmd "set tgc" - ``` To reproduce with `powershell` or `pwsh` (in WT or Conhost), run: ```pwsh & 'C:\Program Files\Git\usr\bin\perl.exe' -e 'for (1..100) { `true` }' | vim --clean --cmd 'set tgc' - ``` It can also be reproduced by running `git show $commit` if `core.pager=vim`, `vimrc` has `set tgc`, and $commit includes changes to a .docx file, which is how I initially encountered the issue: Git for Windows has `*.docx diff=astextplain` which invokes [astextplain](https://github.com/git-for-windows/build-extra/blob/main/git-extra/astextplain) which invokes [docx2txt.pl](http://docx2txt.sourceforge.net/) which invokes `unzip` twice. I found the reproduction to be more reliable if perl invokes another program more times. 100 invocations reliably reproduces the issue on my system. ### Expected Behavior Vim would show its default empty-input startup screen: ![Screenshot of Vim default empty-input startup screen in Windows Terminal](https://user-images.githubusercontent.com/336433/151682128-be18d3c6-de64-48a0-9a56-ca8e78fc8a69.png) ### Actual Behavior The first and last row of the terminal shows what appear to be terminal escape codes. Keyboard input changes the escape codes, rather than appearing as expected: ![Screenshot of Vim showing escape codes in Windows Terminal](https://user-images.githubusercontent.com/336433/151682159-9710fa23-0b41-4f24-99a5-e1243181421c.png)
claunia added the Resolution-Duplicate label 2026-01-31 05:14:57 +00:00
Author
Owner

@kevinoid commented on GitHub (Jan 30, 2022):

For reference, I'm also able to reproduce the issue with Vim 8.2.0916, although the behavior is slightly different: The screen is initially blank, but pressing any keys (including Ctrl-L to redraw) causes the escape codes to appear as in 8.4.4227.

@kevinoid commented on GitHub (Jan 30, 2022): For reference, I'm also able to reproduce the issue with Vim 8.2.0916, although the behavior is slightly different: The screen is initially blank, but pressing any keys (including Ctrl-L to redraw) causes the escape codes to appear as in 8.4.4227.
Author
Owner

@elsaco commented on GitHub (Jan 30, 2022):

@kevinoid git does some coloring of its own. color.ui = true is the default for Git for Windows. The output changes when this setting is false.

Git with nvim as pager:
git_nvim_pager

Git with color.ui = false and nvim as pager:
git_no_color

Git with color.ui = false and nvim with no tgc:
git_no_color_pager_no_tgc

I'm not sure who's doing the coloring, the application or the terminal.

@elsaco commented on GitHub (Jan 30, 2022): @kevinoid `git` does some coloring of its own. `color.ui = true` is the default for `Git for Windows`. The output changes when this setting is false. Git with `nvim` as pager: ![git_nvim_pager](https://user-images.githubusercontent.com/3933920/151686309-445c664f-b58c-4b99-a823-c3b884e52303.png) Git with `color.ui = false` and `nvim` as pager: ![git_no_color](https://user-images.githubusercontent.com/3933920/151686322-12bbcf17-5289-46e0-a991-0b1c9002cc90.png) Git with `color.ui = false` and `nvim` with no `tgc`: ![git_no_color_pager_no_tgc](https://user-images.githubusercontent.com/3933920/151686347-10995f4d-2e16-4efe-b88b-65355dccfdbf.png) I'm not sure who's doing the coloring, the application or the terminal.
Author
Owner

@kevinoid commented on GitHub (Jan 30, 2022):

@elsaco That's a good observation. I think it's a related, but separate issue. (I'm not sure whether it's a bug since I'm not sure how the color escape sequences git produces should be interpreted once vim enablestermguicolors.) For reference, I usually configure git with color.ui=auto to avoid the issue.

Note that the reproduction I provided for this issue doesn't actually invoke git, just perl and vim (and true indirectly). In the reproduction, perl doesn't produce any output to stdout or stderr that I'm aware of, so the escape codes are almost certainly coming from vim.

@kevinoid commented on GitHub (Jan 30, 2022): @elsaco That's a good observation. I think it's a related, but separate issue. (I'm not sure whether it's a bug since I'm not sure how the color escape sequences git produces should be interpreted once vim enables`termguicolors`.) For reference, I usually configure git with `color.ui=auto` to avoid the issue. Note that the reproduction I provided for this issue doesn't actually invoke `git`, just `perl` and `vim` (and `true` indirectly). In the reproduction, `perl` doesn't produce any output to `stdout` or `stderr` that I'm aware of, so the escape codes are almost certainly coming from vim.
Author
Owner

@kevinoid commented on GitHub (Jan 30, 2022):

I just realized that the issue can be reproduced without perl too. To reproduce with cmd (in WT or Conhost):

(@echo off & for /l %x in (1, 1, 100) do "C:\Program Files\Git\usr\bin\true.exe") | vim --clean --cmd "set tgc" -

To reproduce with powershell or pwsh (in WT or Conhost):

@(1..100) | ForEach-Object { & 'C:\Program Files\Git\usr\bin\true.exe' } | vim --clean --cmd 'set tgc' -

I am unable to reproduce the issue with non-msys programs. For example, the issue does not occur with:

(@echo off & for /l %x in (1, 1, 100) do findstr foo C:\Windows\system.ini) | vim --clean --cmd "set tgc" -
@kevinoid commented on GitHub (Jan 30, 2022): I just realized that the issue can be reproduced without `perl` too. To reproduce with `cmd` (in WT or Conhost): ```cmd (@echo off & for /l %x in (1, 1, 100) do "C:\Program Files\Git\usr\bin\true.exe") | vim --clean --cmd "set tgc" - ``` To reproduce with `powershell` or `pwsh` (in WT or Conhost): ```pwsh @(1..100) | ForEach-Object { & 'C:\Program Files\Git\usr\bin\true.exe' } | vim --clean --cmd 'set tgc' - ``` I am unable to reproduce the issue with non-msys programs. For example, the issue **does not occur** with: ```cmd (@echo off & for /l %x in (1, 1, 100) do findstr foo C:\Windows\system.ini) | vim --clean --cmd "set tgc" - ```
Author
Owner

@j4james commented on GitHub (Jan 30, 2022):

What you're seeing is usually the result an application resetting the ENABLE_VIRTUAL_TERMINAL_PROCESSING mode. See for example #6634, #6711, and #7091.

@j4james commented on GitHub (Jan 30, 2022): What you're seeing is usually the result an application resetting the `ENABLE_VIRTUAL_TERMINAL_PROCESSING` mode. See for example #6634, #6711, and #7091.
Author
Owner

@zadjii-msft commented on GitHub (May 16, 2022):

Wait how did we never triage this one? This does look like the same thing as /dup #6634 to me. See https://github.com/microsoft/terminal/issues/6634#issuecomment-647726408 specifically.

@zadjii-msft commented on GitHub (May 16, 2022): Wait how did we never triage this one? This does look like the same thing as /dup #6634 to me. See https://github.com/microsoft/terminal/issues/6634#issuecomment-647726408 specifically.
Author
Owner

@ghost commented on GitHub (May 16, 2022):

Hi! We've identified this issue as a duplicate of another one that already exists on this Issue Tracker. This specific instance is being closed in favor of tracking the concern over on the referenced thread. Thanks for your report!

@ghost commented on GitHub (May 16, 2022): Hi! We've identified this issue as a duplicate of another one that already exists on this Issue Tracker. This specific instance is being closed in favor of tracking the concern over on the referenced thread. Thanks for your report!
Author
Owner

@kevinoid commented on GitHub (May 16, 2022):

This does look like the same thing as /dup https://github.com/microsoft/terminal/issues/6634 to me.

@zadjii-msft Do I understand correctly that you think C:\Program Files\Git\usr\bin\true.exe disables ENABLE_VIRTUAL_TERMINAL_PROCESSING via SetConsoleMode()? Could you explain why true has to be run in a loop for the issue to occur?

@kevinoid commented on GitHub (May 16, 2022): > This does look like the same thing as /dup https://github.com/microsoft/terminal/issues/6634 to me. @zadjii-msft Do I understand correctly that you think `C:\Program Files\Git\usr\bin\true.exe` disables `ENABLE_VIRTUAL_TERMINAL_PROCESSING` via `SetConsoleMode()`? Could you explain why `true` has to be run in a loop for the issue to occur?
Author
Owner

@DHowett commented on GitHub (May 16, 2022):

Could you explain why true has to be run in a loop for the issue to occur?

It's a race condition, unfortunately. The console mode is global state, and spawning true repeatedly and letting it turn VT parsing on and off while vim is starting turns out to be a good way to trigger the race.

Part of this is due to how pipelines work: vim is starting up and configuring the console handle before any given instance of true exits, as it needs to service the reading end of the pipe.

It probably looks like this:

  1. true starts, enables VT parsing (old mode = off)
  2. vim starts
  3. true exits, disabling VT parsing (mode = old mode)
  4. true starts, enabling VT parsing (old mode = off)
  5. vim enables VT parsing (it is much slower to start up than true)
  6. true exits, disabling VT parsing (mode = old mode)
  7. vim tries to emit VT

The cached value from 4 reflects the console state at the time it was launched, and it cannot be aware of vim's changes in 5 when step 6 happens.

@DHowett commented on GitHub (May 16, 2022): > Could you explain why `true` has to be run in a loop for the issue to occur? It's a race condition, unfortunately. The console mode is global state, and spawning `true` repeatedly and letting it turn VT parsing on and off _while vim is starting_ turns out to be a good way to trigger the race. Part of this is due to how pipelines work: vim is starting up and configuring the console handle before any given instance of `true` exits, as it needs to service the reading end of the pipe. It probably looks like this: 1. `true` starts, enables VT parsing (old mode = off) 2. `vim` starts 3. `true` exits, disabling VT parsing (mode = old mode) 4. `true` starts, enabling VT parsing (old mode = **off**) 5. `vim` enables VT parsing (it is much slower to start up than `true`) 6. `true` exits, disabling VT parsing (mode = old mode) 7. `vim` tries to emit VT The cached value from 4 reflects the console state at the time it was launched, and it cannot be aware of vim's changes in 5 when step 6 happens.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#16535