Cursor shape keep changing #16569

Open
opened 2026-01-31 05:15:59 +00:00 by claunia · 13 comments
Owner

Originally created by @AnsonYeung on GitHub (Feb 1, 2022).

Windows Terminal version

1.11.3741.0

Windows build number

10.0.19042.1466

Other Software

tmux 3.0a (inside WSL)
NVIM v0.7.0-dev

Steps to reproduce

  1. Create ~/.tmux.conf:
set-option -sg status-interval 1
set -g status-right "%I:%M%S%P"
  1. Enter tmux by typing tmux
  2. Enter nvim inside tmux by typing nvim
  3. Enter insert mode by typing i

Expected Behavior

The cursor should not be changing. I've tested it on other terminals and it behaves correctly. Here is the recording of the terminal output and I've tested this on other terminal and didn't experience any cursor issue with it. However, it causes cursor issue on Windows Terminal.

scriptreplay --timing=timing.log script.log

script.log
timing.log

Actual Behavior

The cursor will keep changing randomly when the status line redraws. This does not happen on every frame but about half of the time.

https://user-images.githubusercontent.com/28508329/151974459-7e0ba6ec-ee66-476b-9893-c77a6ee318f5.mp4

The following is what gets repeatedly emitted to the console after following https://github.com/microsoft/terminal/wiki/Enabling-the-debug-tap

[0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1936pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H[0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1937pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H[0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1938pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H[0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1939pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H
Originally created by @AnsonYeung on GitHub (Feb 1, 2022). ### Windows Terminal version 1.11.3741.0 ### Windows build number 10.0.19042.1466 ### Other Software tmux 3.0a (inside WSL) NVIM v0.7.0-dev ### Steps to reproduce 1. Create `~/.tmux.conf`: ``` set-option -sg status-interval 1 set -g status-right "%I:%M%S%P" ``` 2. Enter tmux by typing `tmux` 3. Enter nvim inside tmux by typing `nvim` 4. Enter insert mode by typing `i` ### Expected Behavior **The cursor should not be changing. I've tested it on other terminals and it behaves correctly.** Here is the recording of the terminal output and I've tested this on other terminal and didn't experience any cursor issue with it. However, it causes cursor issue on Windows Terminal. ```sh scriptreplay --timing=timing.log script.log ``` [script.log](https://github.com/microsoft/terminal/files/7978682/script.log) [timing.log](https://github.com/microsoft/terminal/files/7978685/timing.log) ### Actual Behavior The cursor will keep changing randomly when the status line redraws. This does not happen on every frame but about half of the time. https://user-images.githubusercontent.com/28508329/151974459-7e0ba6ec-ee66-476b-9893-c77a6ee318f5.mp4 The following is what gets repeatedly emitted to the console after following https://github.com/microsoft/terminal/wiki/Enabling-the-debug-tap ``` [0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1936pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H[0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1937pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H[0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1938pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H[0]␣0:nvim*␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣01:1939pm␛[H␛[?25h␛[m␛[2␣q␛[?12l␛[6␣q␛[?25l␛[30m␛[42m␛[45;1H ```
claunia added the Issue-BugArea-VTProduct-ConptyPriority-2 labels 2026-01-31 05:15:59 +00:00
Author
Owner

@j4james commented on GitHub (Feb 1, 2022):

If you search through the script.log file for the letters q (that's a space followed by a q), you'll see a number of escape sequences of the form \e[2 q and \e[6 q. These are Set Cursor Style controls, requesting the terminal switch between a block cursor and a bar cursor, so the behaviour you're seeing is to be expected.

It's not clear to me what the script.log file is capturing, though. If that's coming directly from tmux, then that would suggest this is a tmux or nvim issue. If it's just a capture of the debug tap then it could still be a conpty problem.

@j4james commented on GitHub (Feb 1, 2022): If you search through the _script.log_ file for the letters ` q` (that's a space followed by a q), you'll see a number of escape sequences of the form `\e[2 q` and `\e[6 q`. These are [Set Cursor Style](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81) controls, requesting the terminal switch between a block cursor and a bar cursor, so the behaviour you're seeing is to be expected. It's not clear to me what the _script.log_ file is capturing, though. If that's coming directly from tmux, then that would suggest this is a tmux or nvim issue. If it's just a capture of the debug tap then it could still be a conpty problem.
Author
Owner

@AnsonYeung commented on GitHub (Feb 1, 2022):

If you search through the script.log file for the letters q (that's a space followed by a q), you'll see a number of escape sequences of the form \e[2 q and \e[6 q. These are Set Cursor Style controls, requesting the terminal switch between a block cursor and a bar cursor, so the behaviour you're seeing is to be expected.

It's not clear to me what the script.log file is capturing, though. If that's coming directly from tmux, then that would suggest this is a tmux or nvim issue. If it's just a capture of the debug tap then it could still be a conpty problem.

I am aware that it changes the cursor style. However, in other terminals, this simply isn't displayed as the time between the 2 set cursor style is very short. In fact, the time should be short enough that it shouldn't be visible on the screen at all. Windows Terminal displayed the cursor style for too long before it changes to the correct style.

@AnsonYeung commented on GitHub (Feb 1, 2022): > If you search through the _script.log_ file for the letters ` q` (that's a space followed by a q), you'll see a number of escape sequences of the form `\e[2 q` and `\e[6 q`. These are [Set Cursor Style](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81) controls, requesting the terminal switch between a block cursor and a bar cursor, so the behaviour you're seeing is to be expected. > > It's not clear to me what the _script.log_ file is capturing, though. If that's coming directly from tmux, then that would suggest this is a tmux or nvim issue. If it's just a capture of the debug tap then it could still be a conpty problem. I am aware that it changes the cursor style. However, in other terminals, this simply isn't displayed as the time between the 2 set cursor style is very short. In fact, the time should be short enough that it shouldn't be visible on the screen at all. Windows Terminal displayed the cursor style for too long before it changes to the correct style.
Author
Owner

@AnsonYeung commented on GitHub (Feb 1, 2022):

If you search through the script.log file for the letters q (that's a space followed by a q), you'll see a number of escape sequences of the form \e[2 q and \e[6 q. These are Set Cursor Style controls, requesting the terminal switch between a block cursor and a bar cursor, so the behaviour you're seeing is to be expected.

It's not clear to me what the script.log file is capturing, though. If that's coming directly from tmux, then that would suggest this is a tmux or nvim issue. If it's just a capture of the debug tap then it could still be a conpty problem.

This cursor style change is coming from tmux when drawing the status line at the bottom. However it didn't cause issue on other terminals.

In fact, I think tmux emit the entire sequence at the same time and there shouldn't be any time interval where the cursor style should be a steady block style.

The script.log is capturing the output of tmux

@AnsonYeung commented on GitHub (Feb 1, 2022): > If you search through the _script.log_ file for the letters ` q` (that's a space followed by a q), you'll see a number of escape sequences of the form `\e[2 q` and `\e[6 q`. These are [Set Cursor Style](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81) controls, requesting the terminal switch between a block cursor and a bar cursor, so the behaviour you're seeing is to be expected. > > It's not clear to me what the _script.log_ file is capturing, though. If that's coming directly from tmux, then that would suggest this is a tmux or nvim issue. If it's just a capture of the debug tap then it could still be a conpty problem. This cursor style change is coming from tmux when drawing the status line at the bottom. However it didn't cause issue on other terminals. In fact, I think tmux emit the entire sequence at the same time and there shouldn't be any time interval where the cursor style should be a steady block style. The script.log is capturing the output of tmux
Author
Owner

@j4james commented on GitHub (Feb 1, 2022):

In fact, I think tmux emit the entire sequence at the same time and there shouldn't be any time interval where the cursor style should be a steady block style.

Well most of the time on my system I don't see the cursor change. I suspect it might depend on the speed of the machine and the throughput of your connection when in a real session. Expecting the cursor not to visibly change after you're explicitly requested a cursor change seems like a very flaky design. Not my call to make, put personally I'd consider this a tmux or nvim problem.

Funnily enough, we actually once got a bug report for the exact opposite scenario - a mode that was briefly changed produced no visible effect because there wasn't enough of a delay between turning it on and off again!

@j4james commented on GitHub (Feb 1, 2022): > In fact, I think tmux emit the entire sequence at the same time and there shouldn't be any time interval where the cursor style should be a steady block style. Well most of the time on my system I don't see the cursor change. I suspect it might depend on the speed of the machine and the throughput of your connection when in a real session. Expecting the cursor not to visibly change after you're explicitly requested a cursor change seems like a very flaky design. Not my call to make, put personally I'd consider this a tmux or nvim problem. Funnily enough, we actually once got a bug report for the exact opposite scenario - a mode that was briefly changed produced no visible effect because there wasn't enough of a delay between turning it on and off again!
Author
Owner

@j4james commented on GitHub (Feb 1, 2022):

One thing worth noting from the script.log - it looks like it's hiding the cursor before changing to the block style, which seems like it should prevent the block cursor being visible. Unfortunately it then sets the cursor to visible again before changing back to the bar cursor, so that doesn't really help. But this might work better if/when we get a conpty passthrough mode (#1173), since the current conpty architecture possibly does have an effect on the timing of these controls.

@j4james commented on GitHub (Feb 1, 2022): One thing worth noting from the script.log - it looks like it's hiding the cursor before changing to the block style, which seems like it should prevent the block cursor being visible. Unfortunately it then sets the cursor to visible again *before* changing back to the bar cursor, so that doesn't really help. But this might work better if/when we get a conpty passthrough mode (#1173), since the current conpty architecture possibly does have an effect on the timing of these controls.
Author
Owner

@AnsonYeung commented on GitHub (Feb 2, 2022):

@j4james I've done some investigation on the cursor visibility thing and even if I swapped the cursor visibility thing the issue is still present.

with open("modified.log", "rb") as scriptFile, open("timing.log") as timeFile:
    while scriptFile.read(1) != b'\n':
        pass
    while True:
        ln = timeFile.readline().rstrip()
        if ln == '':
            break
        numChars = int(ln.split(' ')[1])
        print(scriptFile.read(numChars))

output for the modified.log to show I've modified it correctly:

b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim*                                                                                                                                                                        12:3319pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h'
b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim*                                                                                                                                                                        12:3320pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h'
b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim*                                                                                                                                                                        12:3321pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h'
b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim*                                                                                                                                                                        12:3322pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h'
b'\x1b[43;173H\x1b[1m\x1b[7m0-1\r\n\x1b(B\x1b[m            \x1b[H\x1b[2 q'

It's now \x1b[6 q\x1b[?25h at the end so I shouldn't see the block cursor, however, I can still see it on my machine.

On the other hand, the default terminal in windows you open by wsl.exe didn't have any issue even with the original script.log, same as I tested on gnome terminal on another machine.

Here is the modified file:
modified.log

@AnsonYeung commented on GitHub (Feb 2, 2022): @j4james I've done some investigation on the cursor visibility thing and even if I swapped the cursor visibility thing the issue is still present. ```py with open("modified.log", "rb") as scriptFile, open("timing.log") as timeFile: while scriptFile.read(1) != b'\n': pass while True: ln = timeFile.readline().rstrip() if ln == '': break numChars = int(ln.split(' ')[1]) print(scriptFile.read(numChars)) ``` output for the `modified.log` to show I've modified it correctly: ``` b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim* 12:3319pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h' b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim* 12:3320pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h' b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim* 12:3321pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h' b'\x1b[?25l\x1b[2 q\x1b[30m\x1b[42m\x1b[45d[0] 0:nvim* 12:3322pm\x1b(B\x1b[m\x1b[1;1H\x1b[?12l\x1b[6 q\x1b[?25h' b'\x1b[43;173H\x1b[1m\x1b[7m0-1\r\n\x1b(B\x1b[m \x1b[H\x1b[2 q' ``` It's now `\x1b[6 q\x1b[?25h` at the end so I shouldn't see the block cursor, however, I can still see it on my machine. On the other hand, the default terminal in windows you open by `wsl.exe` **didn't have any issue even with the original `script.log`**, same as I tested on gnome terminal on another machine. Here is the modified file: [modified.log](https://github.com/microsoft/terminal/files/7984568/modified.log)
Author
Owner

@AnsonYeung commented on GitHub (Feb 2, 2022):

I suspect it might depend on the speed of the machine and the throughput of your connection when in a real session.

I'm testing it locally using scriptreplay so it isn't related to the connection. The speed of the machine is a valid point as the machine I'm using is pretty old (and should be the reason that the issue is that obvious as seen in the video above).

@AnsonYeung commented on GitHub (Feb 2, 2022): > I suspect it might depend on the speed of the machine and the throughput of your connection when in a real session. I'm testing it locally using `scriptreplay` so it isn't related to the connection. The speed of the machine is a valid point as the machine I'm using is pretty old (and should be the reason that the issue is that obvious as seen in the video above).
Author
Owner

@AnsonYeung commented on GitHub (Feb 2, 2022):

Let's simplify the issue a bit. I've created a bash script that can reproduce the issue.

#!/bin/bash
while true; do
    # emit sequence when the cursor is hidden
    echo -en "\e[?25l\e[2 q\e[6 q\e[?25h"
    sleep 1
done

I can see cursor style change with this script on my machine.

But on wsl.exe spawned terminal:

#!/bin/bash
while true; do
    # emit the sequence order in a way similar to tmux did.
    # while tmux doesn't emit the sequence in a proper way, it still doesn't reproduce the issue on terminals other than windows terminal
    echo -en "\e[?25l\e[2 q\e[?25h\e[6 q"
done

Even with the tmux emitted sequence and without the sleep, I couldn't observe the issue at all. Note that wsl.exe supports cursor changing (for example, I entered nvim and it can change cursor style)

@AnsonYeung commented on GitHub (Feb 2, 2022): Let's simplify the issue a bit. I've created a bash script that can reproduce the issue. ```bash #!/bin/bash while true; do # emit sequence when the cursor is hidden echo -en "\e[?25l\e[2 q\e[6 q\e[?25h" sleep 1 done ``` I can see cursor style change with this script on my machine. But on `wsl.exe` spawned terminal: ```bash #!/bin/bash while true; do # emit the sequence order in a way similar to tmux did. # while tmux doesn't emit the sequence in a proper way, it still doesn't reproduce the issue on terminals other than windows terminal echo -en "\e[?25l\e[2 q\e[?25h\e[6 q" done ``` Even with the tmux emitted sequence and without the sleep, I couldn't observe the issue at all. Note that `wsl.exe` supports cursor changing (for example, I entered `nvim` and it can change cursor style)
Author
Owner

@AnsonYeung commented on GitHub (Feb 2, 2022):

Should I close this issue? I just built tmux from the current newest source and it don't emit \e[2 q anymore. As a result, the issue can't be reproduced in the newest version of tmux (self-reported as tmux next-3.4) (however, the latest tagged release 3.2a still produce the issue). (but in wsl ubuntu 3.0a is still the newest in apt)
However, I would personally still consider the output above is a bug.

@AnsonYeung commented on GitHub (Feb 2, 2022): Should I close this issue? I just built tmux from the current newest source and it don't emit `\e[2 q` anymore. As a result, the issue can't be reproduced in the newest version of tmux (self-reported as tmux next-3.4) (however, the latest tagged release 3.2a still produce the issue). (but in wsl ubuntu 3.0a is still the newest in apt) However, I would personally still consider the output above is a bug.
Author
Owner

@zadjii-msft commented on GitHub (Feb 2, 2022):

Meh, leave it open. I can see the flickering with your bash script on my machine, even if it happens super rarely. Probably a timing issue, but meh, we could probably come up with a fix.

@zadjii-msft commented on GitHub (Feb 2, 2022): Meh, leave it open. I can see the flickering with your bash script on my machine, even if it happens super rarely. Probably a timing issue, but meh, we could probably come up with a fix.
Author
Owner

@j4james commented on GitHub (Feb 3, 2022):

Yeah there's definitely a bug evident from that bash script. If I watch the debug tap while that's running, none of the cursor show/hide sequences are getting through. I assume that's because they're being buffered, and the net result is a noop.

This is similar to issue #8698 - sequences that get "passed through" (in this case the cursor style changes) can end up out of sync with sequences that are buffered (in this case the cursor visibility changes). At least I think that's what is happening here.

This would hopefully be solved by #1173.

@j4james commented on GitHub (Feb 3, 2022): Yeah there's definitely a bug evident from that bash script. If I watch the debug tap while that's running, none of the cursor show/hide sequences are getting through. I assume that's because they're being buffered, and the net result is a noop. This is similar to issue #8698 - sequences that get "passed through" (in this case the cursor style changes) can end up out of sync with sequences that are buffered (in this case the cursor visibility changes). At least I think that's what is happening here. This would hopefully be solved by #1173.
Author
Owner

@OreoLamp commented on GitHub (Dec 14, 2023):

Just bumping this and confirming that this is still definitely an issue, and not limited to wsl/tmux/bash. Even on the windows builds of neovim the cursor stays as a block even after exiting neovim.

@OreoLamp commented on GitHub (Dec 14, 2023): Just bumping this and confirming that this is still definitely an issue, and not limited to wsl/tmux/bash. Even on the windows builds of neovim the cursor stays as a block even after exiting neovim.
Author
Owner

@plutonium-239 commented on GitHub (Jul 28, 2024):

hello, just a bump, are there any planned updates on this?

@plutonium-239 commented on GitHub (Jul 28, 2024): hello, just a bump, are there any planned updates on this?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#16569