"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>
Мне нужно одно из двух возможных решений:
Я понял, что это зависит от того, сколько символов напечатано в строке, где происходит ошибка. Любое исправление / обходной путь?
В качестве альтернативы, есть ли
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