7
votes

GNU Readline: Comment effacer la ligne d'entrée?

J'utilise gnu readline dans la mode "Select", en enregistrant une fonction de rappel, comme: xxx pré>

puis connecte rl_callback_read_char_chars code> comme rappel pour mon SELECT () CODE> BOUCLE POUR STDIN_FILENO CODE>. C'est toutes des choses assez standard et fonctionne bien. P>

Maintenant, mon programme imprime de manière asynchrone des messages à l'écran, parfois entrelacé avec une entrée de l'utilisateur. Une session "propre" ressemblerait à ceci: p> xxx pré>

Mais si l'utilisateur est à mi-chemin via une ligne lorsque la réponse du serveur arrive? Ensuite, il devient moche: p> xxx pré>

i Fixe cela simplement en imprimant une nouvelle ligne avant la sortie du serveur si l'utilisateur avait saisi quelque chose (il est facile à raconter en vérifiant rl_line_buffer code>), puis effectuez rl_forcedate_update_display () code> Après avoir imprimé la sortie du serveur. Maintenant, on dirait que ceci: p> xxx pré>

C'est mieux, mais toujours pas parfait. Le problème vient lorsque l'utilisateur a tapé une ligne entière mais n'a pas encore appuyé sur ENTER - alors il ressemble à ceci: p>

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


0 commentaires

6 Réponses :


3
votes

avec des espaces? Essayez d'imprimer "\ b \ b" code> pour chaque caractère que vous souhaitez "supprimer" plutôt qu'un seul '\ b' code>.

Edit em> p>

Comment ça marche fort>

Supposons que vous ayez écrit "Bonjour, monde!" au périphérique d'affichage et vous souhaitez remplacer "monde!" avec "Jim." p> xxx pré>

portabilité strong>

Je ne suis pas sûr, mais la norme décrit spécifiquement le comportement de '\ B' et '\ r' comme cela a été décrit dans les réponses à votre question. P>

Section 5.2.2 Affichage de caractères Sémantique P >

> 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 commentaires

Certains terminaux / émulateurs de terminaux ont un comportement différent pour le caractère arrière. PMG a la bonne idée.


Cela fonctionne dans mon terminal. Mais sans mieux comprendre pourquoi cela fonctionne et comment (ONU) portable, j'ai choisi d'utiliser "\ r" à la place (comme suggéré dans une autre réponse).


A changé d'avis après avoir utilisé le code "\ r" pendant un moment ... je fais mieux cela mieux, car il ne nécessite pas de surimpression avec des espaces à la fin (je préfère faire le surimpression avant la sortie du serveur, donc cette solution Me convient le mieux, sans oublier que c'est la réponse la plus directe à ma question initiale).



0
votes

J'ai essayé de séparer la sortie du serveur et l'entrée de l'utilisateur avec les fenêtres NCurses. La sortie du serveur est simulée avec un fil. Le programme fonctionne jusqu'à ce que vous entriez une ligne commençant par "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();
}


1 commentaires

Malheureusement, les malédictions et la lecture en lecture ne se mélangent pas. Voir Stackoverflow.com/questions/691652/... (également posé par moi).



1
votes

Une chose que vous pouvez faire est d'utiliser \ r code> pour passer au début de la ligne pour la sortie du serveur. Ensuite, vous pouvez utiliser des spécificateurs de largeur de champ vers la sortie de la sortie du reste de la ligne. Ceci écrasera, en fait, écraser tout ce que l'utilisateur avait déjà entré.

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


1 commentaires

Ceci est intelligent et je l'ai mis en place et utilisé pendant un moment. À la fin, j'ai trouvé que j'ai préféré la solution "\ b \ b" postée par PMG. Mais, bon!



0
votes

L'une de ces fonctions aidez-vous?

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

    En outre, pouvez-vous médiati à la sortie du serveur - avoir la sortie de serveur contrôlée de manière à ce qu'elle n'apparaisse que lorsque vous ne le souhaitez que, plutôt que de ressusciter ce que l'utilisateur tape? Par exemple, si votre application est exécutée en mode CURSESS, pourriez-vous avoir une fenêtre fractionnée avec une ligne ou deux en bas dans une sous-fenêtre réservée à l'entrée de l'utilisateur et le reste de la sortie (sortie du serveur et entrée d'utilisateur acceptée) dans une deuxième sous-fenêtre au-dessus de celle-ci?


3 commentaires

Si vous suggérez que je fais que ma demande de lecture en lecture soit également une application des malédictions, il semble impossible: Stackoverflow.com/questions/691652/...


J'ai essayé rl_reset_line_state () et rl_clear_message () ... aucun de ceux-ci n'est utile. Je vais essayer d'autres fonctions de lecture en lecture lorsque je peux, mais je pense que j'ai déjà passé beaucoup de choses intéressantes.


@John Zwinck: Je n'ai pas poussé la bibliothèque de lecture suffisante pour savoir si l'une de celles-ci étaient utiles. Et si readline ne fonctionnera pas avec des malédictions (pas une grosse surprise), il existe deux possibilités: (1) ignorer la suggestion, ou (2) réviser l'application à utiliser des malédictions au lieu de readline. Que (option 2) est définitivement plus de travail.



6
votes

Après assez de piratage, j'ai pu obtenir ce mécanisme. J'espère que d'autres personnes le trouveront utiles. Il n'utilise même pas Select (), mais j'espère que vous aurez le 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();
    }


1 commentaires

Cela devrait être la solution acceptée. Cela pourrait être bizarre, mais il doit gérer correctement les entrées multilignes.



0
votes

Cela semble également fonctionner:

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


0 commentaires