彩色端子输出不会复位

时间:2022-11-23 18:17:41

While writing a larger program I stumbled upon a small problem with colored text output. Here's a much simpler program that reproduces this issue.

在编写更大的程序时,我偶然发现了彩色文本输出的小问题。这是一个更简单的程序,可以重现这个问题。

#include <stdio.h>

#define COL_RESET "\033[0m"
#define COL_BG_RED  "\x1B[41m"

char *str = "the quick brown fox jumped over the lazy dog";

int main(int argc, char *argv[])
{
    int i = 10;
    while (i) {
        puts(COL_BG_RED);
        puts(str);
        puts(COL_RESET);
        puts(str);
        i--;
    }
    return 0;
}

Now this is what I get when I run the program:

现在这是我运行程序时得到的:

First time - expected result

第一次 - 预期的结果

彩色端子输出不会复位

Second time

彩色端子输出不会复位

As you can tell, the program decides to randomly print lines even after resetting the colors in red. When started in a fresh terminal it always prints the expected result. Unless I run clear, there is no guarantee the output won't be mangled like in the second picture.

如您所知,即使重置红色后,程序也会决定随机打印行。在新终端中启动时,它始终打印预期结果。除非我运行清楚,否则无法保证输出不会像第二张图片那样受损。

In the pictures I'm using xterm, although other terminals do the same thing.

在我使用xterm的图片中,虽然其他终端做同样的事情。

What can I do to prevent this?

我该怎么做才能防止这种情况发生?

3 个解决方案

#1


3  

As commented, this is known behavior for some well-known terminals: when scrolling (or reverse-scrolling), the newly cleared area on the screen is filled with the current background color. Linux console does this (except for a glitch some years ago, noted in the terminal database). xterm does it.

如评论所述,这是一些众所周知的终端的已知行为:当滚动(或反向滚动)时,屏幕上新清除的区域用当前背景颜色填充。 Linux控制台执行此操作(除了几年前的故障,在终端数据库中注明)。 xterm做到了。

In ncurses, several related behaviors are lumped together as the bce (background color erase) feature:

在ncurses中,几个相关的行为被集中在一起作为bce(背景颜色擦除)功能:

  • filling newly-cleared rows due to scrolling
  • 由于滚动而填充新清除的行

  • erasing the display, as well as erasing the part ending with or beginning with the cursor.
  • 擦除显示,以及擦除以光标结尾或以光标开头的部分。

  • erasing a line, or erasing the part up to, or from the cursor to the end of the line
  • 擦除一条线,或将部分擦除到光标或从光标擦除到线的末尾

  • inserting (a blank) at the cursor position
  • 在光标位置插入(空白)

  • deleting a character
  • 删除一个字符

Normally ncurses fills in the blanks (and it is only a problem when the terminal entry is poorly chosen), and you would not see this. But using plain escape sequences means that you get to explore the nuances of bce a little.

通常ncurses填充空白(当终端条目选择不当时,这只是一个问题),你不会看到这个。但是使用普通的转义序列意味着你可以稍微探索一下bce的细微差别。

Terminal applications which use escape sequences directly for printing color should reset the color before writing any other text which is not intended to be colored. Other applications (such as line-editing in shells) have to keep this rule in mind when erasing text within the line

直接使用转义序列打印颜色的终端应用程序应在写入任何其他不打算着色的文本之前重置颜色。其他应用程序(例如shell中的行编辑)在删除行内的文本时必须牢记此规则

#2


3  

It seems that the issue occurs when the terminal starts scrolling.

似乎终端开始滚动时会出现问题。

The problem is probably caused by the fact that puts appends a new-line character. Modify your code by using printf.

问题可能是因为puts附加了换行符这一事实。使用printf修改代码。

printf(COL_BG_RED);
printf(str);
puts(COL_RESET);
puts(str);

#3


0  

When I run this locally, I also observe some odd behavior.

当我在本地运行时,我也观察到一些奇怪的行为。

Using:

#define COL_RESET      "\0x1b[39;49m" // reset fore/back ground to normal
#define COL_BG_RED     "\033[41m"

Output:

彩色端子输出不会复位

When changing my #define to use octal rather than hex I get a different (the expected) result.

当我将#define改为使用八进制而不是十六进制时,我得到一个不同的(预期的)结果。

Using:

#define COL_RESET "\033[39;49m"

#define COL_RESET“\ 033 [39; 49m”

Output:

彩色端子输出不会复位

Also you may look into creating a macro for using printf with colors.

您也可以考虑创建一个使用带有颜色的printf的宏。

#include <stdio.h>

#define COL_RESET      "\033[39;49m"
#define COL_BG_RED     "\033[41m"
#define COL_BG_NORMAL  "\033[49m"

#define COLOR_NORMAL    "\033[m"
#define COLOR_RESET     "\033[0m"
#define COLOR_BLACK     "\033[30m"
#define COLOR_RED       "\033[31m"
#define COLOR_GREEN     "\033[32m"
#define COLOR_YELLOW    "\033[33m"
#define COLOR_BLUE      "\033[34m"
#define COLOR_MAGENTA   "\033[35m"
#define COLOR_CYAN      "\033[36m"
#define COLOR_WHITE     "\033[37m"

#define COLOR_PRINTF(colorCode,fmt,...) printf("%s" fmt "%s", colorCode, __VA_ARGS__, COL_RESET)

char *str = "the quick brown fox jumped over the lazy dog";

int main(int argc, char *argv[])
{
    int i = 1;
    while (i) {
        COLOR_PRINTF(COLOR_GREEN, "%s\n", str);
        COLOR_PRINTF(COL_BG_RED, "%s\n", str);
        i--;
    }
    return 0;
}

#1


3  

As commented, this is known behavior for some well-known terminals: when scrolling (or reverse-scrolling), the newly cleared area on the screen is filled with the current background color. Linux console does this (except for a glitch some years ago, noted in the terminal database). xterm does it.

如评论所述,这是一些众所周知的终端的已知行为:当滚动(或反向滚动)时,屏幕上新清除的区域用当前背景颜色填充。 Linux控制台执行此操作(除了几年前的故障,在终端数据库中注明)。 xterm做到了。

In ncurses, several related behaviors are lumped together as the bce (background color erase) feature:

在ncurses中,几个相关的行为被集中在一起作为bce(背景颜色擦除)功能:

  • filling newly-cleared rows due to scrolling
  • 由于滚动而填充新清除的行

  • erasing the display, as well as erasing the part ending with or beginning with the cursor.
  • 擦除显示,以及擦除以光标结尾或以光标开头的部分。

  • erasing a line, or erasing the part up to, or from the cursor to the end of the line
  • 擦除一条线,或将部分擦除到光标或从光标擦除到线的末尾

  • inserting (a blank) at the cursor position
  • 在光标位置插入(空白)

  • deleting a character
  • 删除一个字符

Normally ncurses fills in the blanks (and it is only a problem when the terminal entry is poorly chosen), and you would not see this. But using plain escape sequences means that you get to explore the nuances of bce a little.

通常ncurses填充空白(当终端条目选择不当时,这只是一个问题),你不会看到这个。但是使用普通的转义序列意味着你可以稍微探索一下bce的细微差别。

Terminal applications which use escape sequences directly for printing color should reset the color before writing any other text which is not intended to be colored. Other applications (such as line-editing in shells) have to keep this rule in mind when erasing text within the line

直接使用转义序列打印颜色的终端应用程序应在写入任何其他不打算着色的文本之前重置颜色。其他应用程序(例如shell中的行编辑)在删除行内的文本时必须牢记此规则

#2


3  

It seems that the issue occurs when the terminal starts scrolling.

似乎终端开始滚动时会出现问题。

The problem is probably caused by the fact that puts appends a new-line character. Modify your code by using printf.

问题可能是因为puts附加了换行符这一事实。使用printf修改代码。

printf(COL_BG_RED);
printf(str);
puts(COL_RESET);
puts(str);

#3


0  

When I run this locally, I also observe some odd behavior.

当我在本地运行时,我也观察到一些奇怪的行为。

Using:

#define COL_RESET      "\0x1b[39;49m" // reset fore/back ground to normal
#define COL_BG_RED     "\033[41m"

Output:

彩色端子输出不会复位

When changing my #define to use octal rather than hex I get a different (the expected) result.

当我将#define改为使用八进制而不是十六进制时,我得到一个不同的(预期的)结果。

Using:

#define COL_RESET "\033[39;49m"

#define COL_RESET“\ 033 [39; 49m”

Output:

彩色端子输出不会复位

Also you may look into creating a macro for using printf with colors.

您也可以考虑创建一个使用带有颜色的printf的宏。

#include <stdio.h>

#define COL_RESET      "\033[39;49m"
#define COL_BG_RED     "\033[41m"
#define COL_BG_NORMAL  "\033[49m"

#define COLOR_NORMAL    "\033[m"
#define COLOR_RESET     "\033[0m"
#define COLOR_BLACK     "\033[30m"
#define COLOR_RED       "\033[31m"
#define COLOR_GREEN     "\033[32m"
#define COLOR_YELLOW    "\033[33m"
#define COLOR_BLUE      "\033[34m"
#define COLOR_MAGENTA   "\033[35m"
#define COLOR_CYAN      "\033[36m"
#define COLOR_WHITE     "\033[37m"

#define COLOR_PRINTF(colorCode,fmt,...) printf("%s" fmt "%s", colorCode, __VA_ARGS__, COL_RESET)

char *str = "the quick brown fox jumped over the lazy dog";

int main(int argc, char *argv[])
{
    int i = 1;
    while (i) {
        COLOR_PRINTF(COLOR_GREEN, "%s\n", str);
        COLOR_PRINTF(COL_BG_RED, "%s\n", str);
        i--;
    }
    return 0;
}