这里要编辑的内容不是输出行,它被发送到stdout,所以发送到打印机,并使用一些转义代码指示打印机元信息(粗体等).
您正在编辑的是来自键盘的输入行.
当然,现在(至少在过go 50年)没有实际涉及的打印机,模拟它的设备就是模拟输入的设备(终端;甚至终端模拟器,这是一个"控制台窗口",它是一个打印机模拟器模拟器).但是,这些ANSI代码是用于输出而不是用于输入.
当然,这是Readline.因此,在现实中,它只是模仿上述行为,并像打印其他输出一样打印rl_buffer_line
.但即使是这样,该模拟也是正确完成的,转义字符不会被解释.此外,它不一定会打印所有内容.
这更像是逆向工程,而不是我在文档中读到的东西,所以我不知道你能指望多少.但显然,rl_replace_line
只重写了更改的行的一部分(可能是因为READLINE很旧,可以追溯到物理终端时代,以9600 bps的速度打印东西).因此,在这种速度下,或者在没有这种速度的情况下,您不希望每次更改一行中的一个字节就重写整个行).
请看这段代码(我的tmp[100]
很难看,也不安全,但这只是一个实验)
#include <stdio.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
void linehandler(char *line)
{
printf("line: %s\n", line);
}
int main()
{
rl_callback_handler_install("> ", linehandler);
while (1)
{
rl_callback_read_char();
char tmp[100]={0};
if(strstr(rl_line_buffer, "red")){
printf("\033[31m");
fflush(stdout);
strcpy(tmp, rl_line_buffer);
for(int i=5; rl_line_buffer[i] && i<10; i++) tmp[i] = toupper(rl_line_buffer[i]);
rl_replace_line(tmp, 0);
}
rl_redisplay();
}
}
因此,它所做的就是扫描当前输入行中的三个字母red
.如果它找到它,它会暂时将 colored颜色 更改为红色(请注意,这只需通过printf发送ANSI控制即可完成.因此,Readline完全没有意识到这一点.所以它不会弄乱输入的唯一原因是因为我只打印那些控件,所以它们在屏幕上根本不会占据任何位置).
此外,一旦找到这个red
,它还会将5到10个字符大写.
如果您输入one two three red four
,您将看到输入字符串确实被更改为one tWO THree red four
.WO TH
和four
是红色的.
因此,只有在终端切换到红色后才会发生变化.
证明one t
和ree red
甚至在 colored颜色 切换之前就没有重印过.rl_replace_line
只印了WO TH
张.当我打字的时候four
已经打印出来了.
你甚至可以看到,如果你用箭头键回到,改变,比方说one
的n
乘以X
,所说的X(但没有其他)也将是红色的.
问题是,您在屏幕上看到的输入并不是真正打印为字符串,而是一个字符一个字符地打印.
现在,我不知道你到底想做什么.很难给出另一种方法的建议.是否只突出显示输入的一部分?还是在一定条件下突出整条线?
但我的小实验给了你一些可能的解决方案.
这是向终端发送控制字符(通过printf
、puts
或write
,而不是读取线),因此控制读取线以哪种 colored颜色 打印它打印的future 的东西.
而且,如果你不介意依赖一种没有记录的行为(嗯,也许它是有记录的.只是我通过逆向工程知道了这一点.而且,毕竟,打印ESC[33m
个代码也是UB:你不确定打印设备是否理解这一点),你甚至可以欺骗readline
只打印一个红色的单词
请参见以下代码:
#include <stdio.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
void linehandler(char *line)
{
printf("line: %s\n", line);
}
int main()
{
rl_callback_handler_install("> ", linehandler);
while (1)
{
rl_callback_read_char();
char tmp[100]={0};
strcpy(tmp, rl_line_buffer);
for(int i=0; tmp[i] && i<97; i++){
if(!strncmp(tmp+i, "red", 3)){
memcpy(tmp+i, "XXX", 3);
rl_replace_line(tmp, 0);
rl_redisplay();
printf("\033[31m"); fflush(stdout);
memcpy(tmp+i, "red", 3);
rl_replace_line(tmp, 0);
rl_redisplay();
printf("\033[m"); fflush(stdout);
}
}
rl_redisplay();
}
}
它在输入行中以红色打印单词"red".
请注意,它不会影响行本身(缓冲区).因此,如果您希望该行实际包含ANSI代码,和/或在验证时以红色打印,则必须在linehandler
中处理这一问题.