GNU Readline: how to clear the input line?

前端 未结 6 1334
你的背包
你的背包 2021-01-05 14:35

I use GNU Readline in the \"select\" fashion, by registering a callback function like so:

rl_callback_handler_install(\"\", on_readline_input);
相关标签:
6条回答
  • 2021-01-05 15:12

    One thing you can do is to use \r to jump to the beginning of the line for the server output. Then you can use field width specifiers to right pad the output to the rest of the line. This will, in effect, overwrite whatever the user had already entered.

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

    You may want to fflush(stdout) to ensure that the buffers are in a consistent state before you do that.

    0 讨论(0)
  • 2021-01-05 15:13

    With spaces? Try to print "\b \b" for each character you want to "delete" rather than a single '\b'.


    Edit

    How it works
    Suppose you have written "Hello, world!" to the display device and you want to replace "world!" with "Jim."

    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 */
    

    Portability
    I'm not sure, but the Standard specifically describes the behaviour of '\b' and '\r' as has been described in answers to your question.

    Section 5.2.2 Character display semantics

    > 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.
    
    0 讨论(0)
  • 2021-01-05 15:21

    This also seems to work:

    rl_clear_visible_line();
    printf(...);
    rl_reset_line_state();
    rl_redisplay();
    
    0 讨论(0)
  • 2021-01-05 15:27

    After quite a lot of hacking I was able to get this mechanism. I hope other people will find it useful. It does not even use select(), but I hope you will get the point.

    #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();
        }
    
    0 讨论(0)
  • 2021-01-05 15:27

    I tried to separate server output and user input with ncurses windows. Server output is simulated with a thread. The program run until You enter a line beginning with '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 讨论(0)
  • 2021-01-05 15:28

    Do any of these functions help?

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

    Also, can you mediate the server output - have the server output controlled so that it only appears when and where you want it to, rather than just sprawling over what the user is typing? For example, if your application is running in curses mode, could you have a split 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 a second sub-window above it?

    0 讨论(0)
提交回复
热议问题