ansi background color is consistently rendered outside of the proper area when dealing with multiple lines of double-height text #22129

Closed
opened 2026-01-31 08:04:19 +00:00 by claunia · 5 comments
Owner

Originally created by @ClaireCJS on GitHub (Aug 22, 2024).

Windows Terminal version

1.20.11781.0

Windows build number

10.0.19045.4651

Other Software

TCC command shell ( http://www.jpsoft.com )

Steps to reproduce

Open TCC command-prompt and run the following BAT file.

(Sorry, I tried to do it in CMD.EXE and absolutely could not get the ESC character to echo, and manually-pasted ansi did not work, so I had no choice but to use TCC to demonstrate this)

@echo off

rem note that "%@CHAR[27]" creates the ESC character
rem note that "repeat 2 echo." is how we make 2 blank lines
rem note that ANSI_RESET is a set of codes to reset all ANSI colors and formatting
rem note that BIG_TOP and BIG_BOT are the ANSI codes for double-height lines (top and bottom lines)


repeat 2 echo.

            
rem Define ANSI sequences:
        set ANSI_ESCAPE=%@CHAR[27][
        set ANSI_RESET=%ANSI_ESCAPE%39m%ANSI_ESCAPE%49m%ANSI_ESCAPE%0m

        set ANSI_FOREGROUND_BRIGHT_WHITE=%ANSI_ESCAPE%97m
        set ANSI_BACKGROUND_RED=%ANSI_ESCAPE%41m
        set ANSI_BRIGHT_WHITE_ON_RED=%ANSI_FOREGROUND_BRIGHT_WHITE%%ANSI_BACKGROUND_RED%

        set ANSI_ERASE_TO_END_OF_LINE=%ANSI_ESCAPE%0K                   
        set BIG_TOP=%ESCAPE%#3
        set BIG_BOT=%ESCAPE%#4
        set BIG_OFF=%ESCAPE%#0

echo ——— Verify our ansi codes: 
echo %ANSI_BRIGHT_WHITE_ON_RED% bright white on red %ANSI_RESET%  normal  %ansi_background_red% red background %ANSI_RESET%  normal %ANSI_FOREGROUND_BRIGHT_WHITE% bright white %ANSI_RESET% normal 
repeat 2 echo.

echo ——— Cosmetically correct (ends with big-off+ansi-reset on both lines, erase to EOL on bottom line): 
echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET%
echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET%%ANSI_ERASE_TO_END_OF_LINE%
echo.

echo ——— Cosmetically correct (ends with big-off+ansi-reset on both lines, NO erasing to EOL on bottom line): 
echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET%
echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET%
echo.

echo ——— Cosmetically incorrect (ends with only big_off on both lines, but no ansi-rest or erasing to EOL on either line)
echo ——— I do not think this 
echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%
echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%
echo %ANSI_RESET%[Ansi is reset here yet red bleeds to the right still even though the background color was reset to black/49m]
echo.

echo ——— Cosmetically incorrect (nothing at the end of the line, which is how I think most would do this)
echo ——— I do not think this 
echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE
echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE
echo %ANSI_RESET%[Ansi is reset here yet red bleeds through and we find ourselves one line lower than expected--SURPRISE BLANK LINE?!?!]
echo.

echo ——— Cosmetically correct (ends with ansi-reset on both lines, NO big-off or erasing to either line): 
echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %ANSI_RESET%
echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %ANSI_RESET%
echo.

Expected Behavior

I would expect all background colors to be rendered only in the correct place.

In layman's terms, I would expect the red background to stop at the end of " TEST MESSAGE ", like in the "correct" examples below.

I would expect "correctness" in this situation simply by:

  • Sending the ansi code for double-height top line
  • Sending the ansi code for a red background
  • echoing " TEST MESSAGE "
  • Sending the ansi code for double-height bottom line
  • Sending the ansi code for a red background
  • echoing " TEST MESSAGE "

However, in practice, this does not work.

One must attach more esoteric ansi codes to the end of the line to suppress this bug, and I don't think most people are going to figure it out. It took me hours. HOURS 🤣

Note that in the cases where the bug manifested, I echoed an ANSI_RESET on the following line. Why? To prove that the red bleedthrough was rendering PAST the point of the ANSI being rest. I think that makes it more easy to see that this is not the desired behavior.

Actual Behavior

This. Notice the red bleed-throughs. An extra blank line materializes out of thin air, too!
image

It gets even more interesting!

The behavior is different if you do it from the top of the screen after a cls!

The blank lines that incorrectly materialized out of thin air do NOT materialize when this is done from the top of the screen instead of the bottom.

However, errant red boxes still exist at the right of the screen, albeit much more tamely.

I've never seen anything like this:

image

Originally created by @ClaireCJS on GitHub (Aug 22, 2024). ### Windows Terminal version 1.20.11781.0 ### Windows build number 10.0.19045.4651 ### Other Software TCC command shell ( http://www.jpsoft.com ) ### Steps to reproduce Open TCC command-prompt and run the following BAT file. (Sorry, I tried to do it in ```CMD.EXE``` and absolutely could not get the ESC character to echo, and manually-pasted ansi did not work, so I had no choice but to use TCC to demonstrate this) ``` @echo off rem note that "%@CHAR[27]" creates the ESC character rem note that "repeat 2 echo." is how we make 2 blank lines rem note that ANSI_RESET is a set of codes to reset all ANSI colors and formatting rem note that BIG_TOP and BIG_BOT are the ANSI codes for double-height lines (top and bottom lines) repeat 2 echo. rem Define ANSI sequences: set ANSI_ESCAPE=%@CHAR[27][ set ANSI_RESET=%ANSI_ESCAPE%39m%ANSI_ESCAPE%49m%ANSI_ESCAPE%0m set ANSI_FOREGROUND_BRIGHT_WHITE=%ANSI_ESCAPE%97m set ANSI_BACKGROUND_RED=%ANSI_ESCAPE%41m set ANSI_BRIGHT_WHITE_ON_RED=%ANSI_FOREGROUND_BRIGHT_WHITE%%ANSI_BACKGROUND_RED% set ANSI_ERASE_TO_END_OF_LINE=%ANSI_ESCAPE%0K set BIG_TOP=%ESCAPE%#3 set BIG_BOT=%ESCAPE%#4 set BIG_OFF=%ESCAPE%#0 echo ——— Verify our ansi codes: echo %ANSI_BRIGHT_WHITE_ON_RED% bright white on red %ANSI_RESET% normal %ansi_background_red% red background %ANSI_RESET% normal %ANSI_FOREGROUND_BRIGHT_WHITE% bright white %ANSI_RESET% normal repeat 2 echo. echo ——— Cosmetically correct (ends with big-off+ansi-reset on both lines, erase to EOL on bottom line): echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET% echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET%%ANSI_ERASE_TO_END_OF_LINE% echo. echo ——— Cosmetically correct (ends with big-off+ansi-reset on both lines, NO erasing to EOL on bottom line): echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET% echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF%%ANSI_RESET% echo. echo ——— Cosmetically incorrect (ends with only big_off on both lines, but no ansi-rest or erasing to EOL on either line) echo ——— I do not think this echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF% echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %BIG_OFF% echo %ANSI_RESET%[Ansi is reset here yet red bleeds to the right still even though the background color was reset to black/49m] echo. echo ——— Cosmetically incorrect (nothing at the end of the line, which is how I think most would do this) echo ——— I do not think this echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE echo %ANSI_RESET%[Ansi is reset here yet red bleeds through and we find ourselves one line lower than expected--SURPRISE BLANK LINE?!?!] echo. echo ——— Cosmetically correct (ends with ansi-reset on both lines, NO big-off or erasing to either line): echo %BIG_TOP% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %ANSI_RESET% echo %BIG_BOT% %ANSI_BRIGHT_WHITE_ON_RED% TEST MESSAGE %ANSI_RESET% echo. ``` ### Expected Behavior I would expect all background colors to be rendered only in the correct place. In layman's terms, I would expect the red background to stop at the end of " TEST MESSAGE ", like in the "correct" examples below. I would expect "correctness" in this situation simply by: * Sending the ansi code for double-height top line * Sending the ansi code for a red background * echoing " TEST MESSAGE " * Sending the ansi code for double-height bottom line * Sending the ansi code for a red background * echoing " TEST MESSAGE " However, in practice, this does not work. One must attach more esoteric ansi codes to the end of the line to suppress this bug, and I don't think most people are going to figure it out. It took me hours. HOURS 🤣 Note that in the cases where the bug manifested, I echoed an ANSI_RESET on the following line. Why? To prove that the red bleedthrough was rendering PAST the point of the ANSI being rest. I think that makes it more easy to see that this is not the desired behavior. ### Actual Behavior This. Notice the red bleed-throughs. An extra blank line materializes out of thin air, too! ![image](https://github.com/user-attachments/assets/4509e64c-88f3-4524-81c7-f812e61eaf05) It gets even more interesting! The behavior is different if you do it from the top of the screen after a ```cls```! The blank lines that incorrectly materialized out of thin air do NOT materialize when this is done from the top of the screen instead of the bottom. However, errant red boxes still exist at the right of the screen, albeit much more tamely. I've never seen anything like this: ![image](https://github.com/user-attachments/assets/43d0a949-468f-4320-bd87-c19f3c64f5a2)
claunia added the Needs-TriageIssue-Bug labels 2026-01-31 08:04:19 +00:00
Author
Owner

@j4james commented on GitHub (Aug 23, 2024):

The reason for the lines with a red background, is because that's what happens when the screen scrolls while you have an active background color set - the newly revealed line is filled with that color. And that's why you don't see it when you clear the screen before running your test - there's no scrolling involved then.

This is expected behavior, but there's a mode you can set to disable that if you don't like it. It's called Erase Color Mode (DECECM). Just add something like this near the start of your script:

echo %ANSI_ESCAPE%?117h

But be aware that this changes the behavior of all erase operations. For example, if you wanted to erase the screen with a particular color, you'll need that mode to be reset. And there's a good chance you'll be using apps that rely on that behavior, so it's also a good idea to reset the mode at the end of any scripts that change it.

As for the extra blank lines, that is a bug in conpty that I think only occurs when your screen width is an odd number (I'm almost sure we had an issue for that, but I can't find it now). In any event, I think it has already been fixed, and should be working correctly in the next preview release (or the current Canary build if you want to give that a try).

I think that covers everything, but let me know if I've missed something.

@j4james commented on GitHub (Aug 23, 2024): The reason for the lines with a red background, is because that's what happens when the screen scrolls while you have an active background color set - the newly revealed line is filled with that color. And that's why you don't see it when you clear the screen before running your test - there's no scrolling involved then. This is expected behavior, but there's a mode you can set to disable that if you don't like it. It's called *Erase Color Mode* (`DECECM`). Just add something like this near the start of your script: ``` echo %ANSI_ESCAPE%?117h ``` But be aware that this changes the behavior of *all* erase operations. For example, if you wanted to erase the screen with a particular color, you'll need that mode to be reset. And there's a good chance you'll be using apps that rely on that behavior, so it's also a good idea to reset the mode at the end of any scripts that change it. As for the extra blank lines, that is a bug in conpty that I think only occurs when your screen width is an odd number (I'm almost sure we had an issue for that, but I can't find it now). In any event, I think it has already been fixed, and should be working correctly in the next preview release (or the current Canary build if you want to give that a try). I think that covers everything, but let me know if I've missed something.
Author
Owner

@ClaireCJS commented on GitHub (Aug 23, 2024):

Well... Dang. At least one half of the reported behavior was a bug. But it's already been fixed, so I think I've wasted time. Oops!

Anyway. That is an ANSI code i've never seen in any documentation ever. I went ahead and added it to mypresonal arsenal of ansi code environment variables:

While you're here —— Do you know the code to turn erase color mode back off?

            set ERASE_COLOR_MODE_ON=%ANSI_ESCAPE%?117h
            set ERASE_COLOR_MODE_OFF=????????????????????
@ClaireCJS commented on GitHub (Aug 23, 2024): Well... Dang. At least one half of the reported behavior was a bug. But it's already been fixed, so I think I've wasted time. Oops! Anyway. That is an ANSI code i've never seen in any documentation ever. I went ahead and added it to mypresonal arsenal of ansi code environment variables: While you're here —— Do you know the code to turn erase color mode back off? ``` set ERASE_COLOR_MODE_ON=%ANSI_ESCAPE%?117h set ERASE_COLOR_MODE_OFF=???????????????????? ```
Author
Owner

@j4james commented on GitHub (Aug 23, 2024):

Well... Dang. At least one half of the reported behavior was a bug. But it's already been fixed, so I think I've wasted time. Oops!

Not a problem. Even if it turns out to be a known issue, I'm always happy to have someone testing these sequences. They're not very commonly used, so it's easy for bugs to be missed.

Do you know the code to turn erase color mode back off?

That's just an l at the end of the sequence in place of the h.

set ERASE_COLOR_MODE_OFF=%ANSI_ESCAPE%?117l
@j4james commented on GitHub (Aug 23, 2024): > Well... Dang. At least one half of the reported behavior was a bug. But it's already been fixed, so I think I've wasted time. Oops! Not a problem. Even if it turns out to be a known issue, I'm always happy to have someone testing these sequences. They're not very commonly used, so it's easy for bugs to be missed. > Do you know the code to turn erase color mode back off? That's just an `l` at the end of the sequence in place of the `h`. ``` set ERASE_COLOR_MODE_OFF=%ANSI_ESCAPE%?117l ```
Author
Owner

@ClaireCJS commented on GitHub (Aug 23, 2024):

thank you very much!Message ID: <microsoft/terminal/issues/17771/2307841971@
github.com>

@ClaireCJS commented on GitHub (Aug 23, 2024): thank you very much!Message ID: <microsoft/terminal/issues/17771/2307841971@ github.com>
Author
Owner

@DHowett commented on GitHub (Aug 23, 2024):

Y'all are too fast for me to get a hand on the ball. Thanks James! And Claire, let us know if there's anything else 😄

@DHowett commented on GitHub (Aug 23, 2024): Y'all are too fast for me to get a hand on the ball. Thanks James! And Claire, let us know if there's anything else 😄
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#22129