Add cursorTextColor attribute to colour schemes #20292

Open
opened 2026-01-31 07:09:15 +00:00 by claunia · 4 comments
Owner

Originally created by @weibeld on GitHub (Jul 26, 2023).

Description of the new feature/enhancement

Colour schemes allow setting the cursor colour (cursorColor), however, they don't allow setting the text colour of the character under the cursor. The character under the cursor just keeps its native colour. This is a problem for the Filled Box cursor type because the character under the cursor may become very illegible if the cursor colour and character colour don't happen to naturally contrast.

This problem is exacerbated in applications like Vim where the text that the cursor moves over comes in many different colours. Thus, the problem can't be generally solved by changing the cursor colour because there might always be some combination of cursor and text colour that remain illegible.

The best solution to this problem would be to always change the colour of the character under the cursor to a colour that contrasts well with the cursor colour. In this way, it's guaranteed that the character under the cursor is always legible.

This could be implemented by adding a cursor text colour attribute to the colour scheme (e.g. cursorTextColor attribute), so that colour scheme designers can choose a good combination.

That's also exactly how it is done in iTerm2:

unnamed

Considerations:

  • This applies only to the Filled Box cursor type. For the other cursor types, it's not necessary to change the colour of the character under the cursor.
  • Thus, the attribute could maybe be named cursorFilledBoxTextColor to make this clear.

Related:

  • #1203 addressed a similar issue, however, it only solved printing the character on top of the cursor instead of below it. It does not change the colour of the character, and thus the problem of illegible colour combinations remains.
Originally created by @weibeld on GitHub (Jul 26, 2023). <!-- 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨 I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING: 1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement. 2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement. 3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number). 4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement. 5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement. All good? Then proceed! --> # Description of the new feature/enhancement Colour schemes allow setting the cursor colour (`cursorColor`), however, they don't allow setting the text colour of the character under the cursor. The character under the cursor just keeps its native colour. This is a problem for the _Filled Box_ cursor type because the character under the cursor may become very illegible if the cursor colour and character colour don't happen to naturally contrast. This problem is exacerbated in applications like Vim where the text that the cursor moves over comes in many different colours. Thus, the problem can't be generally solved by changing the cursor colour because there might always be some combination of cursor and text colour that remain illegible. The best solution to this problem would be to always change the colour of the character under the cursor to a colour that contrasts well with the cursor colour. In this way, it's guaranteed that the character under the cursor is always legible. This could be implemented by adding a cursor text colour attribute to the colour scheme (e.g. `cursorTextColor` attribute), so that colour scheme designers can choose a good combination. That's also exactly how it is done in iTerm2: ![unnamed](https://github.com/microsoft/terminal/assets/2396208/d7a9741c-efe1-43b5-90d7-ba8da960b078) Considerations: - This applies only to the _Filled Box_ cursor type. For the other cursor types, it's not necessary to change the colour of the character under the cursor. - Thus, the attribute could maybe be named `cursorFilledBoxTextColor` to make this clear. Related: - #1203 addressed a similar issue, however, it only solved printing the character on top of the cursor instead of below it. It does not change the colour of the character, and thus the problem of illegible colour combinations remains.
claunia added the Issue-FeatureArea-RenderingArea-SettingsProduct-Terminal labels 2026-01-31 07:09:15 +00:00
Author
Owner

@zadjii-msft commented on GitHub (Jul 26, 2023):

After some discussion, I think we did end up losing this over the course of #1203 and #9610. Rather than resurrect one of those, we thought it best to use this fresh thread to track this again. That way we won't have any of the old legacy notes about DxEngine-specific implementation details.

🚧 This space to be updated 🚧

I too have not paged this back in yet, but IIRC there was a collection of related issues:

  • Allow filled box cursors to display the glyph under them in
    • a sane color contrast
    • the terminalBackground color
    • inverted colors (like, rgb(255, 255, 255) - pixelColor or whatever)
    • an arbitrary color (cursorForeground)

again, long since paged this out 😕

notes:


@DHowett proposal

  1. {scheme}.cursorColor and {profile}.cursorColor gain support for inverse and (later) reverse
    • Eventually, this means cursorColor will support foreground+background, inverse, reverse.
    • This requires some UI work around pickable things that are not colors. It is somewhat unclear: these are not colors.
    • Color schemes are no longer color schemes; they are forced to decide the visual properties of the cursor
  2. {profile}.cursorColor becomes deprecated¹ (as well as .foreground, .background, and .selectionColor; it only seems right) and we add the {profile}.cursorStyle enum, which supports color, inverse, and reverse.
    • I am hesitant to introduce a new setting for 1.7, but it would be in our best interest to do so.
  3. As yet unexplored option 3. Proposals welcome.

@zadjii-msft proposal from #6151

We'll introduce cursorTextColor as a setting that accepts the following
values:

  • "#rrggbb" (a color): paint the character the cursor is on in the given color
  • "textForeground": paint the character the cursor is on on top of the cursor in the text foreground color.
  • "textBackground": paint the character the cursor is on on top of the cursor in the text background color. (This is like what gVim does, see this comment).
  • null: Paint the cursor on top of the character always.

@zadjii-msft commented on GitHub (Jul 26, 2023): After some discussion, I think we did end up losing this over the course of #1203 and #9610. Rather than resurrect one of those, we thought it best to use this fresh thread to track this again. That way we won't have any of the old legacy notes about DxEngine-specific implementation details. 🚧 _This space to be updated_ 🚧 I too have not paged this back in yet, but IIRC there was a collection of related issues: * Allow filled box cursors to display the glyph under them in * a sane color contrast * the terminalBackground color * inverted colors (like, `rgb(255, 255, 255) - pixelColor` or whatever) * an arbitrary color (`cursorForeground`) again, long since paged this out 😕 notes: * https://github.com/microsoft/terminal/issues/9610#issuecomment-817896747 * https://github.com/microsoft/terminal/issues/9610#issuecomment-806557824 * https://github.com/microsoft/terminal/pull/6151 --- @DHowett proposal 1. `{scheme}.cursorColor` and `{profile}.cursorColor` gain support for `inverse` and (later) `reverse` * Eventually, this means `cursorColor` will support foreground+background, inverse, reverse. * This requires some UI work around pickable _things_ that are not colors. It is somewhat unclear: these are not colors. * _Color schemes are no longer color schemes; they are forced to decide the visual properties of the cursor_ 2. `{profile}.cursorColor` becomes deprecated¹ (as well as `.foreground`, `.background`, and `.selectionColor`; it only seems right) and we add the **`{profile}.cursorStyle`** enum, which supports `color`, `inverse`, and `reverse`. * I am hesitant to introduce a new setting for 1.7, but it would be in our best interest to do so. 3. As yet unexplored option 3. Proposals welcome. --- @zadjii-msft proposal from #6151 We'll introduce `cursorTextColor` as a setting that accepts the following values: * `"#rrggbb"` (a color): paint the character the cursor is on in the given color * `"textForeground"`: paint the character the cursor is on _on top of the cursor_ in the text foreground color. * `"textBackground"`: paint the character the cursor is on _on top of the cursor_ in the text _background_ color. (This is like what gVim does, see [this comment](https://github.com/microsoft/terminal/issues/1203#issuecomment-618754090)). * `null`: Paint the cursor _on top of the character_ always. ----
Author
Owner

@klausman commented on GitHub (Jul 27, 2023):

The easiest and most user-friendly option is to let the user choose. Guessing/auto-computing the 'right" color is not trivial and may completely miss some needs of the user, e.g. vision impairment, or output-device-specific constraints.

On the other bugs, a lot of time was spent on finding the perfect algorithm to determine the right color, to the point of exasperation of several users that just wanted to set the color themselves for their own needs. Please just implement user choice. It's the right thing to do.

@klausman commented on GitHub (Jul 27, 2023): The easiest and most user-friendly option is to _let the user choose._ Guessing/auto-computing the 'right" color is not trivial and may completely miss some needs of the user, e.g. vision impairment, or output-device-specific constraints. On the other bugs, a lot of time was spent on finding the perfect algorithm to determine the right color, to the point of exasperation of several users that just wanted to set the color themselves for their own needs. _Please_ just implement user choice. It's the right thing to do.
Author
Owner

@weibeld commented on GitHub (Jul 27, 2023):

I also support the proposition by @klausman. There's nothing more needed than a cursorTextColour attribute in the colour scheme specification so that colour scheme designers can choose an appropriate value and users never need to worry about it (this also supports the use case of designing special colour schemes, such as for visual impairment, etc.)

As mentioned, this is exactly how it's done in iTerm2, and in fact after many years of using iTerm2, I never even noticed that the separate cursor text colour is a thing until I noticed the absence of it in Windows Terminal.

Actually, the v1.18 preview version implements a separate colour for the character under the cursor (also discussed in #7118), however, the colour is automatically determined and it changes based on the native colour of the text. It seems to be sometimes the inverse of the text colour (e.g. blue becomes red, purple becomes green, etc.), in other cases it's just a colour that contrasts well with the cursor. This actually almost solves the problem, however, contrast could sometimes still be better and the changing of the colour might be more distracting than helpful.

So, in summary, the added complexity of determining the colour automatically doesn't really provide any benefit, and the much simpler solution of just setting the cursor text colour explicitly would most probably provide the better result, including being more transparent and deterministic.

@weibeld commented on GitHub (Jul 27, 2023): I also support the proposition by @klausman. There's nothing more needed than a `cursorTextColour` attribute in the colour scheme specification so that colour scheme designers can choose an appropriate value and users never need to worry about it (this also supports the use case of designing special colour schemes, such as for visual impairment, etc.) As mentioned, this is exactly how it's done in iTerm2, and in fact after many years of using iTerm2, I never even noticed that the separate cursor text colour is a thing until I noticed the _absence_ of it in Windows Terminal. Actually, the [v1.18 preview](https://github.com/microsoft/terminal/releases/tag/v1.18.1462.0) version implements a separate colour for the character under the cursor (also discussed in #7118), however, the colour is automatically determined and it changes based on the native colour of the text. It seems to be sometimes the inverse of the text colour (e.g. blue becomes red, purple becomes green, etc.), in other cases it's just a colour that contrasts well with the cursor. This actually almost solves the problem, however, contrast could sometimes still be better and the changing of the colour might be more distracting than helpful. So, in summary, the added complexity of determining the colour automatically doesn't really provide any benefit, and the much simpler solution of just setting the cursor text colour explicitly would most probably provide the better result, including being more transparent and deterministic.
Author
Owner

@avih commented on GitHub (Aug 25, 2023):

Allow filled box cursors to display the glyph under them in

an arbitrary color (cursorForeground)

Except for cases where the block cursor background color can change (are there such cases?) this might be the most bullet-proof solution. It might require some user input in choosing that color, but it guarantees fit for purpose for this user.

However, it does have one disadvantage: the original fg color is lost completely. For some it might be still fine, while others might prefer to show the original color (or some variant of it) where possible.

the terminalBackground color

This would probably be a good simple solution if the user doesn't have control over it. It would fit with the theme, and, assuming the chosen cursor bg color has reasonable contrast with the terminal bg (which might not be true), would result in useful contrast.

inverted colors (like, rgb(255, 255, 255) - pixelColor or whatever)

This might sound reasonable, but actually, IMHO this never worked as a general solution in practice. For instance, red is never a good contrast to cyan (blue+green), etc. Also, obviously, 127,127,127 might not be the best contrast to 128,128,128...

a sane color contrast

As history shows in the other bugs, this is much much tricker than it seems at first.

The biggest contrast is when the chosen color is either exactly white or exactly black. These are the luminance extremes, and one of them would have the greatest distance from the luminance value of the BG color.

However, at these extremes, it could feel out of place with the theme. For instance, with a muted theme, a full white or full black could be jarring (but might also be exactly what the user prefers, who knows?!)

But if we stick to this approach, then it might be best to allow some configuration of the desired minimum contrast to the FG text.

As such, the final FG color is probably someplace between the original FG color and white or black (whichever has the biggest contrast to the BG).

But, it's important to keep in mind that the luminance value is not (R+G+B)/3. That's because the channels don't have the same brightness.

For instance, green is about 6 times brighter than blue.

A simplified formula to get the brightness is:
Grayscale = 0.299R + 0.587G + 0.114B

(I'm not a colorspace expert, so this formula should be taken with a grain of salt)

And so, the best contrast for full-green might be black, while the best contrast to full-blue might be white.

So a solution based on such approach might "push" the original FG color towards either white or black until it reaches some desirable luminance distance from the configured BG color.

This would both keep the original FG color where it already has enough contrast, and might also keep the general fg color even when it's modified to increase the contrast.

So bottom line, the best solution is probably to allow two modes of FG color:

  1. Let the user choose one.
  2. Apply automatic contrast of the FG to some configurable level.
@avih commented on GitHub (Aug 25, 2023): > Allow filled box cursors to display the glyph under them in > an arbitrary color (`cursorForeground`) Except for cases where the block cursor background color can change (are there such cases?) this might be the most bullet-proof solution. It might require some user input in choosing that color, but it guarantees fit for purpose for this user. However, it does have one disadvantage: the original fg color is lost completely. For some it might be still fine, while others might prefer to show the original color (or some variant of it) where possible. > the terminalBackground color This would probably be a good simple solution if the user doesn't have control over it. It would fit with the theme, and, assuming the chosen cursor bg color has reasonable contrast with the terminal bg (which might not be true), would result in useful contrast. > inverted colors (like, `rgb(255, 255, 255) - pixelColor` or whatever) This might sound reasonable, but actually, IMHO this never worked as a general solution in practice. For instance, red is never a good contrast to cyan (blue+green), etc. Also, obviously, 127,127,127 might not be the best contrast to 128,128,128... > a sane color contrast As history shows in the other bugs, this is much much tricker than it seems at first. The biggest contrast is when the chosen color is either exactly white or exactly black. These are the luminance extremes, and one of them would have the greatest distance from the luminance value of the BG color. However, at these extremes, it could feel out of place with the theme. For instance, with a muted theme, a full white or full black could be jarring (but might also be exactly what the user prefers, who knows?!) But if we stick to this approach, then it might be best to allow some configuration of the desired minimum contrast to the FG text. As such, the final FG color is probably someplace between the original FG color and white or black (whichever has the biggest contrast to the BG). But, it's important to keep in mind that the luminance value is not (R+G+B)/3. That's because the channels don't have the same brightness. For instance, green is about 6 times brighter than blue. A simplified formula to get the brightness is: Grayscale = 0.299R + 0.587G + 0.114B (I'm not a colorspace expert, so this formula should be taken with a grain of salt) And so, the best contrast for full-green might be black, while the best contrast to full-blue might be white. So a solution based on such approach might "push" the original FG color towards either white or black until it reaches some desirable luminance distance from the configured BG color. This would both keep the original FG color where it already has enough contrast, and might also keep the general fg color even when it's modified to increase the contrast. So bottom line, the best solution is probably to allow two modes of FG color: 1. Let the user choose one. 2. Apply automatic contrast of the FG to some configurable level.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#20292