GNU Readline: how to clear input line?

I use the GNU Readline in select mode by registering a callback function as follows:

rl_callback_handler_install("", on_readline_input);

And then hook rl_callback_read_charas a callback for the loop select()for STDIN_FILENO. This is all pretty standard stuff and works great.

Now my program prints messages on the screen asynchronously, sometimes alternating with user input. A “clean” session will look like this:

user input
SERVER OUTPUT
SERVER OUTPUT
user input
SERVER OUTPUT

But what if the user is halfway through the line when a server response arrives? Then it gets ugly:

user input
SERVER OUTPUT
user inSERVER OUTPUT
put
SERVER OUTPUT

, , - ( , rl_line_buffer), rl_forced_update_display() . :

user input
SERVER OUTPUT
user in
SERVER OUTPUT
user input
SERVER OUTPUT

, . , , Enter - :

user input
SERVER OUTPUT
user input
SERVER OUTPUT
user input
SERVER OUTPUT

, , ( , , ).

( ) :

user input
SERVER OUTPUT
user input - INCOMPLETE
SERVER OUTPUT
user input
SERVER OUTPUT

, , backspace ('\ b') " - INCOMPLETE", , , (gnome-terminal Ubuntu Hardy). printf("ABC\b"); ABC .

, ? backspaces - ( , - strlen(rl_line_buffer)), Readline, ?

+5
6

? "\b \b" , "", '\b'.



, ", !". , "!". "".

Hello, world!
             ^ /* active position */ /* now write "\b \b" */
               /* '\b' moves the active position back;
               // ' ' writes a space (erases the '!')
               // and another '\b' to go back again */
Hello, world
            ^ /* active position */ /* now write "\b \b" again */
Hello, worl
           ^ /* active position */ /* now write "\b \b" 4 times ... */
Hello, 
       ^ /* active position */ /* now write "Jim." */
Hello, Jim.
           ^ /* active position */


, "\ b" "\ r", .

5.2.2

> 1   The active position is that location on a display device where the next character output by
>     the fputc function would appear. The intent of writing a printing character (as defined
>     by the isprint function) to a display device is to display a graphic representation of
>     that character at the active position and then advance the active position to the next
>     position on the current line. The direction of writing is locale-specific. If the active
>     position is at the final position of a line (if there is one), the behavior of the display devic e
>     is unspecified.
>  
> 2   Alphabetic escape sequences representing nongraphic characters in the execution
>     character set are intended to produce actions on display devices as follows:
>     \a (alert) Produces an audible or visible alert without changing the active position.
>     \b (backspace) Moves the active position to the previous position on the current line. If
>        the active position is at the initial position of a line, the behavior of the display
>        device is unspecified.
>     \f ( form feed) Moves the active position to the initial position at the start of the next
>        logical page.
>     \n (new line) Moves the active position to the initial position of the next line.
>     \r (carriage return) Moves the active position to the initial position of the current line.
>     \t (horizontal tab) Moves the active position to the next horizontal tabulation position
>        on the current line. If the active position is at or past the last defined horizontal
>        tabulation position, the behavior of the display device is unspecified.
>     \v (vertical tab) Moves the active position to the initial position of the next vertical
>         tabulation position. If the active position is at or past the last defined vertical
>         tabulation position, the behavior of the display device is unspecified.
>  
> 3   Each of these escape sequences shall produce a unique implementation-defined value
>     which can be stored in a single char object. The external representations in a text file
>     need not be identical to the internal representations, and are outside the scope of this
>     International Standard.
+3

. , . select(), , .

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

    const char const* prompt = "PROMPT> ";

    void printlog(int c) {
        char* saved_line;
        int saved_point;
        saved_point = rl_point;
        saved_line = rl_copy_text(0, rl_end);
        rl_set_prompt("");
        rl_replace_line("", 0);
        rl_redisplay();
        printf("Message: %d\n", c);
        rl_set_prompt(prompt);
        rl_replace_line(saved_line, 0);
        rl_point = saved_point;
        rl_redisplay();
        free(saved_line);
    }


    void handle_line(char* ch) {
        printf("%s\n", ch);
        add_history(ch);
    }

    int main() {
        int c = 1;

        printf("Start.\n");
        rl_callback_handler_install(prompt, handle_line);

        while (1) {
            if (((++c) % 5) == 0) {
                printlog(c);
            }

            usleep(10);
            rl_callback_read_char();
        }
        rl_callback_handler_remove();
    }
+3

\r . . , , , .

fprintf (stdout, "\r%-20s\n", "SERVER OUTPUT");

fflush(stdout), , , .

+1

ncurses. . , , "q".

#include <unistd.h> 
#include <curses.h> 
#include <pthread.h> 

WINDOW *top, *bottom;

int win_update( WINDOW *win, void *data ){
  wprintw(win,"%s", (char*)data ); wrefresh(win);
  return 0;
}

void *top_thread( void *data ){
  char buff[1024];
  int i=0;
  while(1){
    snprintf(buff, 1024, "SERVER OUTPUT: %i\n", i++ );
    use_window( top, win_update, (void*)buff );
    sleep(1);
  }
  return NULL;
}

int main(){
  initscr();
  int maxy, maxx;
  getmaxyx( stdscr, maxy, maxx );

  top = newwin(maxy-1,maxx,0,0);
  wsetscrreg(top,0,maxy-1); idlok(top,1); scrollok(top,1);
  pthread_t top_tid;
  pthread_create(&top_tid, NULL, top_thread, NULL);

  bottom = newwin(1,maxx,maxy-1,0);
  char buff[1024], input[maxx];
  do{
    werase(bottom); wmove(bottom,0,0);
    wprintw(bottom,"input> " ); wrefresh(bottom);
    wgetnstr(bottom,input,sizeof(input));
    snprintf(buff, 1024, "user input: '%s'\n", input );
    use_window( top, win_update, (void*)buff );
  }while( input[0] != 'q' );

  endwin();
}
0

?

  • rl_reset_line_state()
  • rl_clear_message()
  • rl_delete_text()
  • rl_kill_text()

In addition, can you notify the server output - is the server output controlled so that it is displayed only when and where you want, and not just stretched over what the user enters? For example, if your application runs in curses mode, can you have a broken window with a line or two at the bottom in one sub-window reserved for user input, and the rest of the output (server output and accepted user input) in the second above the window above it?

0
source

This also works:

rl_clear_visible_line();
printf(...);
rl_reset_line_state();
rl_redisplay();
0
source

All Articles