6

我在readline自己的程序中使用(版本 6.3,默认 [非 vi] 模式,Ubuntu 14.04)库,在终端窗口(在 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>

我需要两种可能的解决方案之一:

  1. 我已经意识到这取决于在出错的行上输入了多少个字符。任何修复/解决方法?

  2. 或者,是否有一个readline库调用可以告诉我插入符号在我调用之前的位置/列readline()?然后至少我可以认识到我在现有行的末尾并输出 a\n以便首先将自己定位在新行的开头。

我想我可以猜测,对于最多输入 5 个字符,它最多可以使用 5 个退格键,但是如果它不是从行首开始,它会选择做其他事情,这会造成混乱吗?

我看到GNU Readline:如何清除输入行?. 这是同样的情况吗?解决方案似乎相当复杂。开始时不能问你在哪一列readline(),或者告诉它不要试图在删除时那么聪明,只删除实际输入的字符?

4

1 回答 1

4

事实证明,readline如果它不是从第 1 列开始,它就无法识别,从而阻止自己弄乱行上的先前输出。

解决这个问题的唯一方法是我们自己识别起始列,如果当前位置不是第 1 列,则移动到下一行的开头。然后它将总是从最左边的列开始,当它已经在第 1 列时,不会输出不必要的换行符。

我们可以对标准“终端”执行此操作,因为它理解 ANSI 转义序列来查询终端的当前行和列。查询通过字符发送到stdout,响应通过终端插入的字符读取stdin。我们必须将终端置于“原始”输入模式,以便可以立即读取响应字符并且不会回显。

所以这里是代码:

rl_prep_terminal(1);       // put the terminal into "raw" mode
fputs("\033[6n", stdout);  // <ESC>[6n is ANSI sequence to query terminal position
int row, col;              // terminal will reply with <ESC>[<row>;<col>R
fscanf(stdin, "\033[%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
于 2016-12-24T09:24:56.477 回答