“readline” 当行首有输出时
“readline” when there is output at beginning of line
我在我自己的程序中使用 readline
(版本 6.3,默认 [非 vi] 模式,Ubuntu 14.04)库,运行 在终端 window(在 PC 上)。当调用 readline()
时,先前的输出未被换行符终止时出现问题。
#include <stdio.h>
#include <readline/readline.h>
void main(void)
{
// Previous output from some other part of application
// which *may* have output stuff *not* terminated with a '\n'
printf("Hello ");
fflush(stdout);
char *in = readline("OK> ");
}
因此该行看起来像:
Hello OK> <caret here>
如果您键入少量字符(最多 5 个?),然后说 Ctrl+U
(可能是其他字符)来删除您的输入,到目前为止一切似乎都很好 --- readline()
将插入符移回到它自己的提示之后,即删除 5 个字符。但是,请尝试输入:
123456 <Ctrl+U>
现在它删除回 到 和 Hello
,只留下 Hell
行,然后是插入符号,即删除 6+6== 12.所以你看:
Hello OK> 123456 <Ctrl+U>
Hell<caret here>
我需要两种可能的解决方案之一:
我意识到这取决于在出错的那一行输入了多少个字符。任何 fix/workaround?
或者,是否有一个 readline
库调用可以告诉我 position/column 在我调用 readline()
之前插入符所在的位置?然后至少我可以认识到我在现有行的末尾并输出 \n
以便首先将自己定位在新行的开头。
我想我可以猜测,对于最多 5 个字符的输入,它会执行最多 5 个退格键,但除此之外,它会选择执行其他操作,如果它不是从行首开始就会搞砸吗?
我明白了GNU Readline: how to clear the input line?。这是同样的情况吗?解决方案似乎非常复杂。难道不能在开始 readline()
时询问你在哪一列,或者告诉它不要试图在删除时如此聪明并坚持只删除实际输入的字符数?
事实证明,readline
无法识别它是否不是从第 1 列开始,从而阻止自己弄乱该行的先前输出。
处理这个问题的唯一方法是我们自己识别起始列,如果当前位置不是列#1,则移动到下一行的开头。然后它总是从最左边的列开始,当它已经在第 1 列时不会输出不必要的换行符。
我们可以为标准 "Terminal" 执行此操作,因为它理解 ANSI 转义序列以查询终端的当前行和列。查询通过字符发送到 stdout
,响应通过终端插入到 stdin
的字符读取。我们必须将终端置于 "raw" 输入模式,以便响应字符可以立即读取并且不会被回显。
代码如下:
rl_prep_terminal(1); // put the terminal into "raw" mode
fputs("3[6n", stdout); // <ESC>[6n is ANSI sequence to query terminal position
int row, col; // terminal will reply with <ESC>[<row>;<col>R
fscanf(stdin, "3[%d;%dR", &row, &col);
rl_deprep_terminal(); // restore terminal "cooked" mode
if (col > 1) // if beyond the first column...
fputc('\n', stdout); // output '\n' to move to start of next line
in = readline(prompt); // now we can invoke readline() with our prompt
我在我自己的程序中使用 readline
(版本 6.3,默认 [非 vi] 模式,Ubuntu 14.04)库,运行 在终端 window(在 PC 上)。当调用 readline()
时,先前的输出未被换行符终止时出现问题。
#include <stdio.h>
#include <readline/readline.h>
void main(void)
{
// Previous output from some other part of application
// which *may* have output stuff *not* terminated with a '\n'
printf("Hello ");
fflush(stdout);
char *in = readline("OK> ");
}
因此该行看起来像:
Hello OK> <caret here>
如果您键入少量字符(最多 5 个?),然后说 Ctrl+U
(可能是其他字符)来删除您的输入,到目前为止一切似乎都很好 --- readline()
将插入符移回到它自己的提示之后,即删除 5 个字符。但是,请尝试输入:
123456 <Ctrl+U>
现在它删除回 到 和 Hello
,只留下 Hell
行,然后是插入符号,即删除 6+6== 12.所以你看:
Hello OK> 123456 <Ctrl+U>
Hell<caret here>
我需要两种可能的解决方案之一:
我意识到这取决于在出错的那一行输入了多少个字符。任何 fix/workaround?
或者,是否有一个
readline
库调用可以告诉我 position/column 在我调用readline()
之前插入符所在的位置?然后至少我可以认识到我在现有行的末尾并输出\n
以便首先将自己定位在新行的开头。
我想我可以猜测,对于最多 5 个字符的输入,它会执行最多 5 个退格键,但除此之外,它会选择执行其他操作,如果它不是从行首开始就会搞砸吗?
我明白了GNU Readline: how to clear the input line?。这是同样的情况吗?解决方案似乎非常复杂。难道不能在开始 readline()
时询问你在哪一列,或者告诉它不要试图在删除时如此聪明并坚持只删除实际输入的字符数?
事实证明,readline
无法识别它是否不是从第 1 列开始,从而阻止自己弄乱该行的先前输出。
处理这个问题的唯一方法是我们自己识别起始列,如果当前位置不是列#1,则移动到下一行的开头。然后它总是从最左边的列开始,当它已经在第 1 列时不会输出不必要的换行符。
我们可以为标准 "Terminal" 执行此操作,因为它理解 ANSI 转义序列以查询终端的当前行和列。查询通过字符发送到 stdout
,响应通过终端插入到 stdin
的字符读取。我们必须将终端置于 "raw" 输入模式,以便响应字符可以立即读取并且不会被回显。
代码如下:
rl_prep_terminal(1); // put the terminal into "raw" mode
fputs("3[6n", stdout); // <ESC>[6n is ANSI sequence to query terminal position
int row, col; // terminal will reply with <ESC>[<row>;<col>R
fscanf(stdin, "3[%d;%dR", &row, &col);
rl_deprep_terminal(); // restore terminal "cooked" mode
if (col > 1) // if beyond the first column...
fputc('\n', stdout); // output '\n' to move to start of next line
in = readline(prompt); // now we can invoke readline() with our prompt