"Readline", когда есть вывод в начале строки

Я использую readline (версия 6.3, режим по умолчанию [не-vi], Ubuntu 14.04) изнутри моей собственной программы, запущенной в окне терминала (на ПК). Существует проблема, когда предыдущий вывод не завершен переводом строки, когда 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()? Тогда, по крайней мере, я мог бы признать тот факт, что я нахожусь в конце существующей строки и вывести \n чтобы сначала позиционировать себя в начале новой строки.

Я думаю, что могу предположить, что для до 5 набранных символов он делает до 5 пробелов, но из-за того, что он решает сделать что-то еще, что портится, если оно не начинается в начале строки?

Я вижу GNU Readline: как очистить строку ввода?, Это та же самая ситуация? Решения кажутся довольно сложными. Разве нельзя спрашивать, в каком столбце вы находитесь при запуске? readline()или сказать ему не пытаться быть настолько умным при удалении и придерживаться удаления только того количества символов, которое было в него введено?

1 ответ

Решение

Оказывается, что readline не может распознать, если он не начинается в столбце #1, и, таким образом, не позволяет ему испортить предыдущий вывод в строке.

Единственный способ справиться с этим - самостоятельно распознать начальный столбец и перейти к началу следующей строки, если текущая позиция не является столбцом № 1. Тогда он всегда будет начинаться с самого левого столбца, без вывода ненужного символа новой строки, когда он уже находится в столбце № 1.

Мы можем сделать это для стандартного "Терминала", потому что он понимает escape-последовательность 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
Другие вопросы по тегам