"vintage" cursor shape + blinking with an escape sequence? #10272

Open
opened 2026-01-31 02:16:56 +00:00 by claunia · 23 comments
Owner

Originally created by @vefatica on GitHub (Aug 24, 2020).

In Windows Terminal, can I get the "vintage" cursor (~30% blinking horizontal bar) with an escape sequence?

Both of these (below) give a non-blinking cursor of the desired size. Other similar pairs suggest that 7 should be blinking?

ESC[7 q
ESC[8 q

  • Vince
Originally created by @vefatica on GitHub (Aug 24, 2020). In Windows Terminal, can I get the "vintage" cursor (~30% blinking horizontal bar) with an escape sequence? Both of these (below) give a non-blinking cursor of the desired size. Other similar pairs suggest that 7 should be blinking? ESC[7 q ESC[8 q - Vince
claunia added the Product-ConhostIssue-TaskArea-VT labels 2026-01-31 02:16:56 +00:00
Author
Owner

@zadjii-msft commented on GitHub (Aug 25, 2020):

@DHowett had a horrible idea in chat

if we did that, we could also add a subparameter to it
\e[7:25 q sets vintage at 25%
and therefore communicate the cursor state from conpty to terminal . . .

which is actually an amazing idea IMO. We don't currently support subparams in sequences, but we're not too far away from that.

I'm gonna summon @j4james to sanity check that using these sequences like this don't have an existing conflict. We might need to pick something silly like \e[9001:25 q to avoid any existing conflicts, but I really like this idea.

@zadjii-msft commented on GitHub (Aug 25, 2020): @DHowett had a horrible idea in chat > if we did that, we could also add a subparameter to it > `\e[7:25 q` sets vintage at 25% > and therefore communicate the cursor state from conpty to terminal . . . which is actually an amazing idea IMO. We don't _currently_ support subparams in sequences, but we're not too far away from that. I'm gonna summon @j4james to sanity check that using these sequences like this don't have an existing conflict. We might need to pick something silly like `\e[9001:25 q` to avoid any existing conflicts, but I really like this idea.
Author
Owner

@j4james commented on GitHub (Aug 25, 2020):

I would generally not encourage the use of sub parameters, because they're non-standard, and tend to break parsers in unpredictable ways. If you were an app developer that wanted to use this option, you'd then have to detect the terminal type to determine whether it was safe to send the sequence or not.

So my preference would probably be to invent a completely new sequence for the size, if you really think you need it - something that would generally be treated as a no-op by terminals that don't support it (you can't always guarantee that, but the idea is to minimize the damage you're doing).

I should also add that I thought someone already had a sequence for this. I had a brief look yesterday when the issue was first raised and didn't find anything, but it's probably worth doing a bit more research before reinventing something that may already exist.

@j4james commented on GitHub (Aug 25, 2020): I would generally not encourage the use of sub parameters, because they're non-standard, and tend to break parsers in unpredictable ways. If you were an app developer that wanted to use this option, you'd then have to detect the terminal type to determine whether it was safe to send the sequence or not. So my preference would probably be to invent a completely new sequence for the size, if you really think you need it - something that would generally be treated as a no-op by terminals that don't support it (you can't always guarantee that, but the idea is to minimize the damage you're doing). I should also add that I thought someone already had a sequence for this. I had a brief look yesterday when the issue was first raised and didn't find anything, but it's probably worth doing a bit more research before reinventing something that may already exist.
Author
Owner

@vefatica commented on GitHub (Aug 25, 2020):

I just wanted to get back to my default (blinking "vintage"). In '\e[N q', N = 1/2 gives blink/non-blink block cursor, N = 3/4 the same for underscore, N = 5/6 the same for vertical bar. Since n = 8 gives the "vintage" size and shape, non-blinking, it seems reasonable that 7 give blinking "vintage" (it doesn't).

I don't know what your restrictions are. Returning to the default should be straightforward (maybe even '\e[0 q' which now duplicates '\e[1 q').

Where can I find the handling of control sequences in the code?

@vefatica commented on GitHub (Aug 25, 2020): I just wanted to get back to my default (blinking "vintage"). In '\e[N q', N = 1/2 gives blink/non-blink block cursor, N = 3/4 the same for underscore, N = 5/6 the same for vertical bar. Since n = 8 gives the "vintage" size and shape, non-blinking, it seems reasonable that 7 give blinking "vintage" (it doesn't). I don't know what your restrictions are. Returning to the default should be straightforward (maybe even '\e[0 q' which now duplicates '\e[1 q'). Where can I find the handling of control sequences in the code?
Author
Owner

@DHowett commented on GitHub (Aug 25, 2020):

@vefatica you may be interested in #7379

@DHowett commented on GitHub (Aug 25, 2020): @vefatica you may be interested in #7379
Author
Owner

@j4james commented on GitHub (Aug 25, 2020):

Since n = 8 gives the "vintage" size and shape, non-blinking, it seems reasonable that 7 give blinking "vintage" (it doesn't).

Just to be clear, we don't technically support parameter 8 as "vintage". Every number that isn't a recognised parameter just ends up as that by default. Personally I think that's a bug - if it's a not a supported parameter we should be ignoring it. If we want to use 7/8 as blinking and non-blinking vintage then those should be explicitly supported parameters.

@j4james commented on GitHub (Aug 25, 2020): > Since n = 8 gives the "vintage" size and shape, non-blinking, it seems reasonable that 7 give blinking "vintage" (it doesn't). Just to be clear, we don't technically support parameter 8 as "vintage". Every number that isn't a recognised parameter just ends up as that by default. Personally I think that's a bug - if it's a not a supported parameter we should be ignoring it. If we want to use 7/8 as blinking and non-blinking vintage then those should be explicitly supported parameters.
Author
Owner

@vefatica commented on GitHub (Aug 25, 2020):

Yes, I figured parameters greater than 6 weren't supported. If unknown parameters are not ignored, and are going to lead to the default, it should respect whether the default is blinking or not (or at least preserve the current blink state).

As for supported parameters, "vintage" (blinking/non-blinking) really should be among them.

@vefatica commented on GitHub (Aug 25, 2020): Yes, I figured parameters greater than 6 weren't supported. If unknown parameters are not ignored, and are going to lead to the default, it should respect whether the default is blinking or not (or at least preserve the current blink state). As for supported parameters, "vintage" (blinking/non-blinking) really should be among them.
Author
Owner

@j4james commented on GitHub (Aug 25, 2020):

We didn't invent this sequence - it's just a standard that we are a following. Parameters 0 to 4 were originally defined by DEC, and 5 and 6 were later added by XTerm, and have since become a de facto standard. "Vintage" isn't a style that anyone else supports, so that would require a proprietary extension, which is not something that we want to rush into.

@j4james commented on GitHub (Aug 25, 2020): We didn't invent this sequence - it's just a standard that we are a following. Parameters 0 to 4 were originally defined by DEC, and 5 and 6 were later added by XTerm, and have since become a de facto standard. "Vintage" isn't a style that anyone else supports, so that would require a proprietary extension, which is not something that we want to rush into.
Author
Owner

@vefatica commented on GitHub (Aug 25, 2020):

You have (I guess) respected the "de facto standard". What's the problem with augmenting it? [I'm serious.] I wonder if XTerm agonized over adding 5 and 6?

@vefatica commented on GitHub (Aug 25, 2020): You have (I guess) respected the "de facto standard". What's the problem with augmenting it? [I'm serious.] I wonder if XTerm agonized over adding 5 and 6?
Author
Owner

@zadjii-msft commented on GitHub (Aug 25, 2020):

We have a specific resistance to extending any existing protocols like this. We'd much rather entirely invent our own sequence to use, that isn't even sorta used by anyone else, rather than extend an existing one.

I agree with @j4james's assessment - using \e[8 q to restore to vintage is a bug, that we should probably fix, as well as introduce a vintage cursor shape sequence.

@zadjii-msft commented on GitHub (Aug 25, 2020): We have a specific resistance to extending any existing protocols like this. We'd much rather entirely invent our own sequence to use, that isn't even sorta used by anyone else, rather than extend an existing one. I agree with @j4james's assessment - using `\e[8 q` to restore to `vintage` is a bug, that we should probably _fix_, as well as introduce a vintage cursor shape sequence.
Author
Owner

@j4james commented on GitHub (Aug 27, 2020):

FWIW, I found the escape sequence I was thinking of. It's a private CSI that was used by SCO Unixware:

ESC[= s ; e C
    Sets cursor parameters (where s is the starting and e is the ending scanlines of the cursor).

Not exactly what we want, because I think we can only set the height rather than the scanline range (at least in conhost). Also there's the question of how many scanlines there are in a character (you assumedly wouldn't want it to depend on font size).

That said, it's worth noting that Kermit implemented this (when in "ANSI" mode) by calculating the requested height (i.e. e - s), and then mapping certain height ranges to cursor sizes.

  • "height" <= 1 is an underline cursor
  • "height" < 10 is a half block cursor
  • "height" >= 10 is a full block cursor

Assumedly this sequence would also function as a proxy for selecting the "vintage" cursor. And choosing whether the cursor should be blinking or not is already covered by the existing cursor blink mode (private mode 12).

I'm not sure about this, but it's at least something to consider.

@j4james commented on GitHub (Aug 27, 2020): FWIW, I found the escape sequence I was thinking of. It's a private CSI that was used by [SCO Unixware](http://uw714doc.sco.com/en/man/html.7/display.7.html): ESC[= s ; e C Sets cursor parameters (where s is the starting and e is the ending scanlines of the cursor). Not exactly what we want, because I think we can only set the height rather than the scanline range (at least in conhost). Also there's the question of how many scanlines there are in a character (you assumedly wouldn't want it to depend on font size). That said, it's worth noting that Kermit implemented this (when in "ANSI" mode) by calculating the requested height (i.e. `e - s`), and then mapping certain height ranges to cursor sizes. * "height" <= 1 is an underline cursor * "height" < 10 is a half block cursor * "height" >= 10 is a full block cursor Assumedly this sequence would also function as a proxy for selecting the "vintage" cursor. And choosing whether the cursor should be blinking or not is already covered by the existing cursor blink mode (private mode 12). I'm not sure about this, but it's at least something to consider.
Author
Owner

@jdebp commented on GitHub (Aug 29, 2020):

As I mentioned at https://unix.stackexchange.com/a/597558/5132 , I've extended this to support 4 more shapes, myself. They are an outline box, a star, underline+overline, and a reversed "L" shape, inspired by some literature on real terminals. So if you do ever extend DECSCUSR, I'd appreciate it if we were compatible.

@jdebp commented on GitHub (Aug 29, 2020): As I mentioned at https://unix.stackexchange.com/a/597558/5132 , I've extended this to support 4 more shapes, myself. They are an outline box, a star, underline+overline, and a reversed "L" shape, inspired by some literature on real terminals. So if you _do_ ever extend DECSCUSR, I'd appreciate it if we were compatible.
Author
Owner

@j4james commented on GitHub (Aug 29, 2020):

Thanks for the info - that's useful to know. We do have an "Empty Box" cursor style, which sounds the same as your "outline box", so that's something I think we could easily support if we were going to extend DECSCUSR. Am I right in assuming that 7 and 8 are the blinking and non-blinking versions of the outline box in your implementation?

@j4james commented on GitHub (Aug 29, 2020): Thanks for the info - that's useful to know. We do have an "Empty Box" cursor style, which sounds the same as your "outline box", so that's something I think we could easily support if we were going to extend DECSCUSR. Am I right in assuming that 7 and 8 are the blinking and non-blinking versions of the outline box in your implementation?
Author
Owner

@jdebp commented on GitHub (Sep 10, 2020):

Yes. 79b1c0aab9/source/SoftTerm.cpp (L1201)

@jdebp commented on GitHub (Sep 10, 2020): Yes. https://github.com/jdebp/nosh/blob/79b1c0aab9834a09a59e15d47710f355c5c0417a/source/SoftTerm.cpp#L1201
Author
Owner

@vefatica commented on GitHub (Sep 11, 2020):

What about these? (from https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) They work in the Windows console.

image

@vefatica commented on GitHub (Sep 11, 2020): What about these? (from https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) They work in the Windows console. ![image](https://user-images.githubusercontent.com/61856645/92949055-6e065780-f428-11ea-9fb1-41c821dde47b.png)
Author
Owner

@vefatica commented on GitHub (Sep 11, 2020):

And, after settings are reloaded, the cursor shape is restored but the blink state is not restored. This might be related to #7571

@vefatica commented on GitHub (Sep 11, 2020): And, after settings are reloaded, the cursor shape is restored but the blink state is not restored. This might be related to #7571
Author
Owner

@vefatica commented on GitHub (Sep 11, 2020):

Maybe there should be a "cursorBlink" (true/false) profile setting?

@vefatica commented on GitHub (Sep 11, 2020): Maybe there should be a "cursorBlink" (true/false) profile setting?
Author
Owner

@zadjii-msft commented on GitHub (Sep 27, 2021):

Moving to 2.0 b/c of #8560

@zadjii-msft commented on GitHub (Sep 27, 2021): Moving to 2.0 b/c of #8560
Author
Owner

@carlos-zamora commented on GitHub (Mar 6, 2024):

From #16785:

The blocking issue for this is https://github.com/microsoft/terminal/issues/7382. We need to pass on the request for the overwrite-mode cursor via conpty, which requires an equivalent escape sequence for the half-height block cursor, but there isn't a standard way to achieve that.

It's also worth noting that this particular cursor change is achieved with an internal SetCursorDBMode call, which toggles the "double cursor" mode, independent of the actual cursor size - it's not using the public SetConsoleCursorInfo API. So that's something we need to bear in mind if we want to get this working in conpty.

@carlos-zamora commented on GitHub (Mar 6, 2024): From #16785: > The blocking issue for this is https://github.com/microsoft/terminal/issues/7382. We need to pass on the request for the overwrite-mode cursor via conpty, which requires an equivalent escape sequence for the half-height block cursor, but there isn't a standard way to achieve that. > > It's also worth noting that this particular cursor change is achieved with an internal SetCursorDBMode call, which toggles the "double cursor" mode, independent of the actual cursor size - it's not using the public SetConsoleCursorInfo API. So that's something we need to bear in mind if we want to get this working in conpty.
Author
Owner

@j4james commented on GitHub (Mar 6, 2024):

I've been meaning to comment here that there's another escape sequence we could potentially use for this: CSI ? <size> c, which is used by the Linux kernel console to set the height of the cursor. It's very similar to the way the Windows vintage cursor works, and it's also supported by Mintty, which is another advantage.

The only negative is that it's not really an appropriate escape sequence, because CSI c is technically reserved by ANSI for device attribute queries, and on some terminals a CSI ? c sequence will trigger a DA report.

But it's at least something to consider if nobody has any better ideas.

@j4james commented on GitHub (Mar 6, 2024): I've been meaning to comment here that there's another escape sequence we could potentially use for this: `CSI ? <size> c`, which is used by the Linux kernel console to set the height of the cursor. It's very similar to the way the Windows vintage cursor works, and it's also supported by Mintty, which is another advantage. The only negative is that it's not really an appropriate escape sequence, because `CSI c` is technically reserved by ANSI for device attribute queries, and on some terminals a `CSI ? c` sequence will trigger a `DA` report. But it's at least something to consider if nobody has any better ideas.
Author
Owner

@UGD-Zephyr commented on GitHub (May 10, 2024):

Hello!

There are a lot of different issues I found online about vim in PowerShell 7 used in the Windows Terminal not displaying the correct cursor shape for insert mode, command mode, visual mode, replace mode et cetera. From what I could find, this thread is supposed to be the original one, I hope I am posting in the right place.

It's working by adding set termguicolors before the escape sequences in the C:\Program Files (x86)\Vim _vimrc file.

set termguicolors

let &t_SI = "\e[4 q"
let &t_SR = "\e[6 q"
let &t_EI = "\e[2 q"
let &t_ti .= "\e[1 q"
let &t_te .= "\e[0 q"

Without set termguicolors or set t_Co=256 it doesn't work, but with one of them it does. Hopefully the people in this thread that still has problems can solve them with this.

found it here: https://github.com/vim/vim/pull/11028

@UGD-Zephyr commented on GitHub (May 10, 2024): Hello! There are a lot of different issues I found online about vim in PowerShell 7 used in the Windows Terminal not displaying the correct cursor shape for insert mode, command mode, visual mode, replace mode et cetera. From what I could find, this thread is supposed to be the original one, I hope I am posting in the right place. It's working by adding set termguicolors before the escape sequences in the C:\Program Files (x86)\Vim _vimrc file. set termguicolors let &t_SI = "\e[4 q" let &t_SR = "\e[6 q" let &t_EI = "\e[2 q" let &t_ti .= "\e[1 q" let &t_te .= "\e[0 q" Without set termguicolors or set t_Co=256 it doesn't work, but with one of them it does. Hopefully the people in this thread that still has problems can solve them with this. found it here: https://github.com/vim/vim/pull/11028
Author
Owner

@ubaldot commented on GitHub (Sep 20, 2024):

I am also using the following:

&t_SI = "\e[6 q"
&t_EI = "\e[2 q"

and it works reasonably well, but:

  1. The cursor won't pick the color of the colorscheme. For example, if your colorscheme implies a yellow cursor color and the WT cursor color is black, then it stays black - if your colorscheme has a black background you won't see anything,
  2. At vim closure the cursor shape is not reset. That is, if in WT you have a bar and in vim you have a block, when exiting Vim the cursor stays in block shape,
  3. When entering Vim the cursor shape change don't happen immediately, but you have to go to insert mode and then back to normal mode to see the change.

The issues are present only in WT. In Windows bundled powershell/wsl terminals the issue is not present. I have the same setting for iTerm2 on MacOs and the described issues are not present.

@ubaldot commented on GitHub (Sep 20, 2024): I am also using the following: ``` &t_SI = "\e[6 q" &t_EI = "\e[2 q" ``` and it works reasonably well, but: 1. The cursor won't pick the color of the colorscheme. For example, if your colorscheme implies a yellow cursor color and the WT cursor color is black, then it stays black - if your colorscheme has a black background you won't see anything, 2. At vim closure the cursor shape is not reset. That is, if in WT you have a bar and in vim you have a block, when exiting Vim the cursor stays in block shape, 3. When entering Vim the cursor shape change don't happen immediately, but you have to go to insert mode and then back to normal mode to see the change. The issues are present only in WT. In Windows bundled powershell/wsl terminals the issue is not present. I have the same setting for iTerm2 on MacOs and the described issues are not present.
Author
Owner

@craigbarnes commented on GitHub (Feb 19, 2025):

I would generally not encourage the use of sub parameters, because they're non-standard, and tend to break parsers in unpredictable ways.

I don't dispute that last point, but FWIW "bit combination 03/10" (also known as 0x3A or :) is mentioned in ECMA-48 (5th ed.) 5.4.2b.

@craigbarnes commented on GitHub (Feb 19, 2025): > I would generally not encourage the use of sub parameters, because they're non-standard, and tend to break parsers in unpredictable ways. I don't dispute that last point, but FWIW "bit combination 03/10" (also known as `0x3A` or `:`) is mentioned in ECMA-48 (5th ed.) 5.4.2b.
Author
Owner

@j4james commented on GitHub (Feb 20, 2025):

@craigbarnes I meant at the VT level. This is from DEC STD 070 standard:

The bit combination 3/10 is reserved for future standardization. If 3/10 is received within a parameter string, the entire sequence up to and including the final character shall be ignored.

Of course if terminals actually followed that rule it would be much safer to add colon-based extensions, but that's not always the case. Although maybe things are better now than they were 5 years ago. It's been a while since I've tested.

I will say there's one nice advantage to using DECSCUSR with a subparmeter: in theory it could be saved and restored with a standard DECRQSS query, which wouldn't be the case with a SCO/Kermit/Mintty sequences. So maybe that is an option worth reconsidering. We'd need more research to see how badly current terminals react to it though.

@j4james commented on GitHub (Feb 20, 2025): @craigbarnes I meant at the VT level. This is from DEC STD 070 standard: > The bit combination 3/10 is reserved for future standardization. If 3/10 is received within a parameter string, the entire sequence up to and including the final character shall be ignored. Of course if terminals actually followed that rule it would be much safer to add colon-based extensions, but that's not always the case. Although maybe things are better now than they were 5 years ago. It's been a while since I've tested. I will say there's one nice advantage to using `DECSCUSR` with a subparmeter: in theory it could be saved and restored with a standard `DECRQSS` query, which wouldn't be the case with a SCO/Kermit/Mintty sequences. So maybe that is an option worth reconsidering. We'd need more research to see how badly current terminals react to it though.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#10272