2016-12-17 2 views
3

Ich benutze die readline (Version 6.3, Standard [non-vi] Modus, Ubuntu 14.04) Bibliothek aus meinem eigenen Programm, läuft in einem Terminalfenster (auf einem PC). Es gibt ein Problem, wenn die vorherige Ausgabe nicht durch einen Zeilenumbruch beendet wird, wenn readline() aufgerufen wird."readline" wenn es am Zeilenanfang ausgegeben wird

#include <stdio.h> 
#include <readline/readline.h> 

void main(void) 
{ 
    // Previous output from some other part of application 
    // which *may* have output stuff *not* terminated with a '\n' 
    printf("Hello "); 
    fflush(stdout); 

    char *in = readline("OK> "); 
} 

So sieht die Zeile wie:

Hello OK> <caret here> 

Wenn Sie eine kleine Anzahl von Zeichen eingeben (? Bis zu 5) und dann, sagen wir, Ctrl+U (können andere sein), um Ihre Eingabe zu löschen, so weit scheint alles gut --- readline() verschiebt das Caret zurück nach seiner eigenen Aufforderung, dh 5 Zeichen zu löschen. Allerdings versucht Typisierung, sagen:

123456 <Ctrl+U> 

Jetzt löscht sie zurück in die Hello, nur Hell auf der Linie zu verlassen, durch die caret gefolgt, das heißt 6 + 6 == 12 zu löschen. Sie sehen also:

Hello OK> 123456 <Ctrl+U> 
Hell<caret here> 

Ich brauche eine von zwei möglichen Lösungen:

  1. ich erkannt haben, es hängt davon ab, wie viele Zeichen eingegeben werden, auf der Linie, wo es schief geht. Irgendeine Reparatur/Workaround?

  2. Alternativ gibt es einen readline Bibliotheksaufruf, den ich machen könnte, der mir sagen würde, welche Position/Spalte der Caret ist, bevor ich readline() aufrufen? Dann konnte ich zumindest erkennen, dass ich am Ende einer bestehenden Linie bin und eine \n ausgegeben habe, um mich am Anfang einer neuen Linie zu positionieren.

Ich glaube, ich kann irgendwie vermuten, dass bis zu 5 Zeichen eingegeben tut es bis zu 5 Marken zurück, aber über, dass es wählt etwas anderes, was vermasselt zu tun, wenn es nicht am Anfang der Zeile gestartet wird?

Ich sehe GNU Readline: how to clear the input line?. Ist das die gleiche Situation? Die Lösungen scheinen ziemlich komplex zu sein. Ist es nicht möglich zu fragen, in welcher Spalte Sie stehen, wenn Sie readline() starten, oder um zu sagen, dass Sie nicht versuchen sollten, so clever zu löschen und nur so viele Zeichen zu löschen, wie tatsächlich eingetippt wurden?

+0

Können Sie noch einmal überprüfen Sie mit Readline- 7.0? Ich habe es gerade installiert (standardmäßig auf die neueste Version) und kann das nicht replizieren. – usr2564301

+1

Oh! Ich bin ein bisschen Neuling bei Ubuntu. Ich benutze die Version 6, die mit 14.04 LTS installiert wurde, und habe ein 'sudo apt-get install libreadline-dev', das auch eine 6 hat und sagt 'libreadline-dev ist schon die neueste Version'. Tut mir leid, aber wie mache ich es bitte auf 7? – JonBrave

+0

Entschuldigung, ich bin auf einem Mac, der seine eigenen besonderen Möglichkeiten hat, Pakete zu installieren - ich habe brew zum Download verwendet und automatisch die neueste Quelle ausgewählt. Sind Sie selbstbewusst genug, um einen manuellen Download und Build zu versuchen? Sie können auch die neuesten Änderungsprotokolle suchen und prüfen, ob etwas Ähnliches bemerkt wurde. – usr2564301

Antwort

3

Es stellt sich heraus, dass readline kann nicht erkennen, wenn es nicht bei Spalte # 1 beginnt, und damit selbst aufhören, die vorherige Ausgabe auf der Linie zu verpfuschen.

Die einzige Möglichkeit, dies zu umgehen, besteht darin, die Startspalte selbst zu erkennen und zum Anfang der nächsten Zeile zu springen, wenn die aktuelle Position nicht Spalte 1 ist. Dann beginnt es immer von der Spalte ganz links, ohne eine unnötige neue Zeile auszugeben, wenn es bereits in Spalte 1 ist.

Wir können dies für den Standard "Terminal" tun, weil es eine ANSI-Escape-Sequenz versteht, um die aktuelle Zeile & Spalte des Terminals abzufragen. Die Abfrage wird über Zeichen an stdout gesendet und die Antwort wird über Zeichen gelesen, die das Terminal in stdin einfügt. Wir müssen das Terminal in den "rohen" Eingabemodus versetzen, so dass die Antwortzeichen sofort gelesen werden können und nicht wiederholt werden.

So, hier ist der Code:

rl_prep_terminal(1);  // put the terminal into "raw" mode 
fputs("\033[6n", stdout); // <ESC>[6n is ANSI sequence to query terminal position 
int row, col;    // terminal will reply with <ESC>[<row>;<col>R 
fscanf(stdin, "\033[%d;%dR", &row, &col); 
rl_deprep_terminal();  // restore terminal "cooked" mode 
if (col > 1)    // if beyond the first column... 
    fputc('\n', stdout);  // output '\n' to move to start of next line 

in = readline(prompt);  // now we can invoke readline() with our prompt 
Verwandte Themen