Как я могу отключить readline, чтобы напечатать что-то и затем восстановить это?

Я пытаюсь написать консольный чат-клиент, используя только readline и escape-коды ANSI.

Моя цель - просто позволить терминалу обрабатывать прокрутку и прокрутку истории чата, всегда предоставляя подсказку readline после сообщений для нового ввода.

Я попробовал следующее с моими двумя потоками. Мой поток ввода с консоли делает:

printf("\x1B[s"); // Save cursor position
message = readline("Prompt > ");

И мой поток получения сообщений делает:

message = receive_message(); // Blocks for next message
printf("\x1B[u"); // Restore cursor to before the prompt
printf("\x1B[J"); // Erase readline prompt and input (down to bottom of screen)
printf("%s\n", message); // Print the message (where readline was)
printf("\x1B[s"); // Save new cursor position
rl_forced_update_display(); // Restore readline

Вышеприведенное работает, пока ввод readline не переносится. Когда оно оборачивается, восстановление сохраненной позиции курсора не работает должным образом, кажется, что восстанавливается только горизонтальное положение, а не вертикальное положение.

Как я могу адаптировать вышеуказанный код для работы, даже если строка ввода переносится?

2 ответа

Решение

Этот вопрос оказывается гораздо лучшим решением. Я воспроизвел код из приведенного решения, относящегося к ответу на этот вопрос здесь:

message = receive_message();

// Solution
int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0;

int saved_point = rl_point;
char *saved_line = rl_copy_text(0, rl_end);
rl_save_prompt();
rl_replace_line("", 0);
rl_redisplay();

printf(message);

rl_restore_prompt();
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
free(saved_line);

Для полноты входной поток очищается от сохранения курсора и становится простым:

message = readline("Prompt > ");

Я не знаю, как я не видел, прежде чем опубликовать свой вопрос.

Я был вдохновлен тем, как получить ширину терминала в C, чтобы выяснить вручную, завернут ли я или нет.

Теперь я делаю следующее, когда мне нужно что-то напечатать перед приглашением readline:

message = receive_message(); // Blocks for next message

/* Solution */
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); // Get terminal dimensions
printf("\r"); // Move cursor to the begining of the line
// Calculate the length of the prompt and cursor position
int readline_length = rl_point + strlen(rl_prompt);
// Integer divide cursor position by the terminal width
int wrapped_lines = readline_length/w.ws_col;
// If there are wraped lines
if (wrapped_lines > 0)
    // move the cursor up by that number of lines
    printf("\x1B[%dA", wrapped_lines);
printf("\r"); // Move cursor to the beginning of the line
printf("\x1B[J"); // Erase readline prompt and input (down to bottom of screen)

printf("%s\n", message); // Print the message (where readline was)
rl_forced_update_display(); // Restore readline

Для полноты входной поток очищается от сохранения курсора и становится простым:

message = readline("Prompt > ");
Другие вопросы по тегам