GNU Readline (libreadline): асинхронное отображение выходного сообщения - PullRequest
1 голос
/ 16 февраля 2012

При использовании readline (блокировка) для ввода данных пользователем, я хотел бы выводить строки текста на консоль асинхронно из другого потока.Кроме того, я хотел бы, чтобы приглашение readline и текущая частичная строка ввода были удалены из консоли, записана строка вывода, затем восстановлено приглашение readline и частичная строка пользователя - чтобы создать впечатление, что вывод был написан «выше»подсказка.

Каким образом (или иным образом) может быть достигнута комбинация функций повторного отображения readline?

(Документация по функциям повторного отображения: http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC35)

проблемная демонстрация :

    #include <readline/readline.h>
    #include <readline/history.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <pthread.h>

    bool run = true;

    void* log_thread(void*)
    {
            while (run)
            {
                    sleep(1);
                    // WHAT TO DO HERE?
                    write(1, "tick\n", 5);
            }
    }

    int main()
    {
            pthread_t t;
            pthread_create(&t, 0, log_thread, 0);

            while (true)
            {
                    char* p = readline("? ");
                    free(p);

                    if (!p)
                            break;
            }

            run = false;
            pthread_join(t,0);
    }

сборка :

$ g++ -pthread -lreadline test.cpp
$ ./a.out

наблюдаемый вывод : (ввод "foo \ nbar \ n" печатается медленно)

? tick
ftick
otick
otick

? tick
tick
bartick
tick

? tick
^C

желаемый вывод : (ввод "foo \ nbar"\ n "набирается медленно)

tick
tick
tick
tick
tick
? foo

tick
tick
tick
tick
tick
? bar

tick
? ^C

1 Ответ

1 голос
/ 11 июня 2012

Я делаю это в консольной версии моей программы omphalos (https://github.com/dankamongmen/omphalos). Этот конкретный код взят из https://github.com/dankamongmen/omphalos/blob/master/src/ui/tty/tty.c.

У меня есть:

// Call whenever we generate output, so that the prompt is updated
static inline void
wake_input_thread(void){
    if(input_tid){
            pthread_kill(*input_tid,SIGWINCH);
            rl_redisplay(); // FIXME probably need call from readline contex
    }
    pthread_mutex_unlock(&promptlock);

}

и

static inline void
clear_for_output(FILE *fp){
    assert(fputc('\r',fp) != EOF);
}

Всякий раз, когда что-то хочет напечатать, он берет блокировку и вызывает clear_for_output (), перемещая курсор в начало текущей строки. При необходимости он может изменить подсказку в это время, вызывая rl_set_prompt (). По завершении вызывается wake_input_thread (), освобождая блокировку и вызывая повторное отображение.

Я не уверен, работает ли это в случае, когда вы набрали больше, чем строкутекста, и сомневаюсь в этом, и не хочу формально обнаружить, что, вероятно, является новой и удручающей ошибкой прямо сейчас, так что вы можете поэкспериментировать с этим самостоятельно.

...