top: enable true line input editing with paste support

This patch changes the TERMIO_PROXY define back to the
former TERMIOS_ONLY thus changing the top default too.

Plus we can now use true line input editing while also
retaining paste capability. That former native termios
support provided only a limited destructive backspace.

Now we exploit the Left/Right arrow keys, Home/End and
Delete. Plus, the Insert key can toggle overtype mode!

[ The stage is now set for a really huge improvement ]
[ to any user input terminated with the <Enter> key. ]
[ So please stay tuned for the next patch to arrive! ]

(everything is perfectly justified plus right margins)
(are completely filled, but of course it must be luck)

Reference(s):
commit fa21a6ca81

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2013-02-15 00:00:00 -06:00 committed by Craig Small
parent d04297843f
commit 477b10c0bd
2 changed files with 76 additions and 54 deletions

102
top/top.c
View File

@ -62,7 +62,7 @@
/* The original and new terminal definitions /* The original and new terminal definitions
(only set when not in 'Batch' mode) */ (only set when not in 'Batch' mode) */
static struct termios Tty_original, // our inherited terminal definition static struct termios Tty_original, // our inherited terminal definition
#ifndef TERMIO_PROXY #ifdef TERMIOS_ONLY
Tty_tweaked, // for interactive 'line' input Tty_tweaked, // for interactive 'line' input
#endif #endif
Tty_raw; // for unsolicited input Tty_raw; // for unsolicited input
@ -718,14 +718,14 @@ static int show_pmt (const char *str) {
PUTT("%s%s%.*s %s%s%s" PUTT("%s%s%.*s %s%s%s"
, tg2(0, Msg_row) , tg2(0, Msg_row)
, Curwin->capclr_pmt , Curwin->capclr_pmt
, Screen_cols - 3 , Screen_cols - 2
, str , str
, Cap_curs_huge , Cap_curs_huge
, Caps_off , Caps_off
, Cap_clr_eol); , Cap_clr_eol);
fflush(stdout); fflush(stdout);
// +2 for the ': ' chars we added or -1 for the cursor... // +1 for the space we added or -1 for the cursor...
return ((rc = (int)strlen(str)+2) < Screen_cols) ? rc : Screen_cols-1; return ((rc = (int)strlen(str)+1) < Screen_cols) ? rc : Screen_cols-1;
} // end: show_pmt } // end: show_pmt
@ -927,7 +927,7 @@ static inline int ioa (struct timespec *ts) {
static int ioch (int ech, char *buf, unsigned cnt) { static int ioch (int ech, char *buf, unsigned cnt) {
int rc = -1; int rc = -1;
#ifndef TERMIO_PROXY #ifdef TERMIOS_ONLY
if (ech) { if (ech) {
tcsetattr(STDIN_FILENO, TCSAFLUSH, &Tty_tweaked); tcsetattr(STDIN_FILENO, TCSAFLUSH, &Tty_tweaked);
rc = read(STDIN_FILENO, buf, cnt); rc = read(STDIN_FILENO, buf, cnt);
@ -954,10 +954,11 @@ static int ioch (int ech, char *buf, unsigned cnt) {
/* /*
* Support for single keystroke input AND escaped cursor motion keys * Support for single or multiple keystroke input AND
* escaped cursor motion keys.
* note: we support more keys than we currently need, in case * note: we support more keys than we currently need, in case
* we attract new consumers in the future */ * we attract new consumers in the future */
static int iokey (int init) { static int iokey (int action) {
static char buf12[CAPBUFSIZ], buf13[CAPBUFSIZ] static char buf12[CAPBUFSIZ], buf13[CAPBUFSIZ]
, buf14[CAPBUFSIZ], buf15[CAPBUFSIZ]; , buf14[CAPBUFSIZ], buf15[CAPBUFSIZ];
static struct { static struct {
@ -980,10 +981,16 @@ static int iokey (int init) {
{ "\033\013", kbd_PGUP }, { "\033\012", kbd_PGDN }, /* ctrl+meta+ k,j */ { "\033\013", kbd_PGUP }, { "\033\012", kbd_PGDN }, /* ctrl+meta+ k,j */
{ "\033\010", kbd_HOME }, { "\033\014", kbd_END } /* ctrl+meta+ h,l */ { "\033\010", kbd_HOME }, { "\033\014", kbd_END } /* ctrl+meta+ h,l */
}; };
#ifdef TERMIOS_ONLY
char buf[SMLBUFSIZ], *pb; char buf[SMLBUFSIZ], *pb;
#else
static char buf[SMLBUFSIZ];
static int pos, len;
char *pb;
#endif
int i; int i;
if (init) { if (action == 0) {
#define tOk(s) s ? s : "" #define tOk(s) s ? s : ""
tinfo_tab[1].str = tOk(key_up); tinfo_tab[1].str = tOk(key_up);
tinfo_tab[2].str = tOk(key_down); tinfo_tab[2].str = tOk(key_down);
@ -1007,8 +1014,25 @@ static int iokey (int init) {
#undef tOk #undef tOk
} }
memset(buf, '\0', sizeof(buf)); if (action == 1) {
if (1 > ioch(0, buf, sizeof(buf)-1)) return 0; memset(buf, '\0', sizeof(buf));
if (1 > ioch(0, buf, sizeof(buf)-1)) return 0;
}
#ifndef TERMIOS_ONLY
if (action == 2) {
if (pos < len)
return buf[pos++]; // exhaust prior keystrokes
pos = len = 0;
memset(buf, '\0', sizeof(buf));
if (1 > ioch(0, buf, sizeof(buf)-1)) return 0;
if (isprint(buf[0])) { // no need for translation
len = strlen(buf);
pos = 1;
return buf[0];
}
}
#endif
/* some emulators implement 'key repeat' too well and we get duplicate /* some emulators implement 'key repeat' too well and we get duplicate
key sequences -- so we'll focus on the last escaped sequence, while key sequences -- so we'll focus on the last escaped sequence, while
@ -1026,7 +1050,7 @@ static int iokey (int init) {
} // end: iokey } // end: iokey
#ifndef TERMIO_PROXY #ifdef TERMIOS_ONLY
/* /*
* Get line oriented interactive input from the user, * Get line oriented interactive input from the user,
* using native tty support */ * using native tty support */
@ -1047,13 +1071,9 @@ static char *ioline (const char *prompt) {
#else #else
/* /*
* Get line oriented interactive input from the user, * Get line oriented interactive input from the user,
* going way beyond native tty support ! * going way beyond native tty support by providing:
* Unlike native tty input support, this function provides:
* . true line editing, not just destructive backspace * . true line editing, not just destructive backspace
* . an input limit that's sensitive to current screen dimensions * . an input limit sensitive to current screen dimensions */
* . immediate signal response without the need to wait for '\n'
* However, the user will lose the ability to paste keystrokes
* when this function is chosen over the smaller alternative above! */
static char *ioline (const char *prompt) { static char *ioline (const char *prompt) {
// thank goodness memmove allows the two strings to overlap // thank goodness memmove allows the two strings to overlap
#define sqzSTR { memmove(&buf[pos], &buf[pos+1], bufMAX-pos); \ #define sqzSTR { memmove(&buf[pos], &buf[pos+1], bufMAX-pos); \
@ -1064,31 +1084,32 @@ static char *ioline (const char *prompt) {
#define phyCOL (beg+pos+1) #define phyCOL (beg+pos+1)
#define bufMAX ((int)sizeof(buf)-2) // -1 for '\0' string delimeter #define bufMAX ((int)sizeof(buf)-2) // -1 for '\0' string delimeter
static char buf[MEDBUFSIZ+1]; // +1 for '\0' string delimeter static char buf[MEDBUFSIZ+1]; // +1 for '\0' string delimeter
int beg, pos, len; int beg, pos, len, key, ovt;
int key;
pos = 0; pos = ovt = 0;
beg = show_pmt(prompt); beg = show_pmt(prompt);
memset(buf, '\0', sizeof(buf)); memset(buf, '\0', sizeof(buf));
putp(Cap_curs_norm);
do { do {
fflush(stdout);
len = strlen(buf); len = strlen(buf);
key = iokey(0); key = iokey(2);
switch (key) { switch (key) {
case kbd_ESC: case kbd_ESC:
buf[0] = '\0'; // fall through ! buf[0] = '\0'; // fall through !
case kbd_ENTER: case kbd_ENTER:
break; break;
case kbd_INS:
ovt = !ovt;
putp(ovt ? Cap_curs_huge : Cap_curs_norm);
break;
case kbd_DEL: case kbd_DEL:
case kbd_DOWN:
sqzSTR sqzSTR
break; break;
case kbd_BKSP : case kbd_BKSP :
if (0 < pos) { --pos; sqzSTR } if (0 < pos) { --pos; sqzSTR }
break; break;
case kbd_INS:
case kbd_UP:
expSTR
break;
case kbd_LEFT: case kbd_LEFT:
if (0 < pos) --pos; if (0 < pos) --pos;
break; break;
@ -1102,13 +1123,14 @@ static char *ioline (const char *prompt) {
pos = len; pos = len;
break; break;
default: // what we REALLY wanted (maybe) default: // what we REALLY wanted (maybe)
if (isprint(key) && logCOL < bufMAX && phyCOL < Screen_cols) if (isprint(key) && logCOL < bufMAX && phyCOL < Screen_cols) {
if (!ovt) expSTR
buf[pos++] = key; buf[pos++] = key;
}
break; break;
} }
putp(fmtmk("%s%s%s", tg2(beg, Msg_row), Cap_clr_eol, buf)); putp(fmtmk("%s%s%s", tg2(beg, Msg_row), Cap_clr_eol, buf));
putp(tg2(beg+pos, Msg_row)); putp(tg2(beg+pos, Msg_row));
fflush(stdout);
} while (key != kbd_ENTER && key != kbd_ESC); } while (key != kbd_ENTER && key != kbd_ESC);
return buf; return buf;
@ -1954,7 +1976,7 @@ signify_that:
fflush(stdout); fflush(stdout);
if (Frames_resize) goto signify_that; if (Frames_resize) goto signify_that;
key = iokey(0); key = iokey(1);
if (key < 1) goto signify_that; if (key < 1) goto signify_that;
switch (key) { switch (key) {
@ -2813,7 +2835,7 @@ signify_that:
tcflush(STDIN_FILENO, TCIFLUSH); tcflush(STDIN_FILENO, TCIFLUSH);
if (Frames_resize) goto signify_that; if (Frames_resize) goto signify_that;
key = iokey(0); key = iokey(1);
if (key < 1) goto signify_that; if (key < 1) goto signify_that;
switch (key) { switch (key) {
@ -2862,7 +2884,7 @@ signify_that:
case '=': case '=':
snprintf(buf, sizeof(buf), "%s: %s", Insp_sel->type, Insp_sel->fmts); snprintf(buf, sizeof(buf), "%s: %s", Insp_sel->type, Insp_sel->fmts);
INSP_MKSL(1, buf); // show an extended SL INSP_MKSL(1, buf); // show an extended SL
if (iokey(0) < 1) if (iokey(1) < 1)
goto signify_that; goto signify_that;
break; break;
default: // keep gcc happy default: // keep gcc happy
@ -2918,7 +2940,7 @@ signify_that:
INSP_MKSL(0, " "); INSP_MKSL(0, " ");
if (Frames_resize) goto signify_that; if (Frames_resize) goto signify_that;
if (key == INT_MAX) key = iokey(0); if (key == INT_MAX) key = iokey(1);
if (key < 1) goto signify_that; if (key < 1) goto signify_that;
switch (key) { switch (key) {
@ -3494,7 +3516,7 @@ static void whack_terminal (void) {
tmptty.c_iflag &= ~IGNBRK; tmptty.c_iflag &= ~IGNBRK;
if (key_backspace && 1 == strlen(key_backspace)) if (key_backspace && 1 == strlen(key_backspace))
tmptty.c_cc[VERASE] = *key_backspace; tmptty.c_cc[VERASE] = *key_backspace;
#ifndef TERMIO_PROXY #ifdef TERMIOS_ONLY
if (-1 == tcsetattr(STDIN_FILENO, TCSAFLUSH, &tmptty)) if (-1 == tcsetattr(STDIN_FILENO, TCSAFLUSH, &tmptty))
error_exit(fmtmk(N_fmt(FAIL_tty_set_fmt), strerror(errno))); error_exit(fmtmk(N_fmt(FAIL_tty_set_fmt), strerror(errno)));
tcgetattr(STDIN_FILENO, &Tty_tweaked); tcgetattr(STDIN_FILENO, &Tty_tweaked);
@ -3514,7 +3536,7 @@ static void whack_terminal (void) {
// this has the effect of disabling any troublesome scrollback buffer... // this has the effect of disabling any troublesome scrollback buffer...
if (enter_ca_mode) putp(enter_ca_mode); if (enter_ca_mode) putp(enter_ca_mode);
// and don't forget to ask iokey to initialize his tinfo_tab // and don't forget to ask iokey to initialize his tinfo_tab
iokey(1); iokey(0);
} // end: whack_terminal } // end: whack_terminal
/*###### Windows/Field Groups support #################################*/ /*###### Windows/Field Groups support #################################*/
@ -3539,7 +3561,7 @@ static WIN_t *win_select (int ch) {
so we must try to get our own darn ch by begging the user... */ so we must try to get our own darn ch by begging the user... */
if (!ch) { if (!ch) {
show_pmt(N_txt(CHOOSE_group_txt)); show_pmt(N_txt(CHOOSE_group_txt));
if (1 > (ch = iokey(0))) return w; if (1 > (ch = iokey(1))) return w;
} }
switch (ch) { switch (ch) {
case 'a': // we don't carry 'a' / 'w' in our case 'a': // we don't carry 'a' / 'w' in our
@ -3628,7 +3650,7 @@ signify_that:
fflush(stdout); fflush(stdout);
if (Frames_resize) goto signify_that; if (Frames_resize) goto signify_that;
key = iokey(0); key = iokey(1);
if (key < 1) goto signify_that; if (key < 1) goto signify_that;
switch (key) { switch (key) {
@ -3795,7 +3817,7 @@ static void file_writerc (void) {
if (Rc_questions) { if (Rc_questions) {
show_pmt(N_txt(XTRA_warncfg_txt)); show_pmt(N_txt(XTRA_warncfg_txt));
if ('y' != tolower(iokey(0))) if ('y' != tolower(iokey(1)))
return; return;
Rc_questions = 0; Rc_questions = 0;
} }
@ -3909,7 +3931,7 @@ signify_that:
fflush(stdout); fflush(stdout);
if (Frames_resize) goto signify_that; if (Frames_resize) goto signify_that;
key = iokey(0); key = iokey(1);
if (key < 1) goto signify_that; if (key < 1) goto signify_that;
switch (key) { switch (key) {
@ -3924,7 +3946,7 @@ signify_that:
, Winstk[2].rc.winname, Winstk[3].rc.winname)); , Winstk[2].rc.winname, Winstk[3].rc.winname));
putp(Cap_clr_eos); putp(Cap_clr_eos);
fflush(stdout); fflush(stdout);
if (Frames_resize || (key = iokey(0)) < 1) { if (Frames_resize || (key = iokey(1)) < 1) {
adj_geometry(); adj_geometry();
putp(Cap_clr_scr); putp(Cap_clr_scr);
} else w = win_select(key); } else w = win_select(key);
@ -5130,7 +5152,7 @@ int main (int dont_care_argc, char **argv) {
pselect(0, NULL, NULL, NULL, &ts, NULL); pselect(0, NULL, NULL, NULL, &ts, NULL);
else { else {
if (ioa(&ts)) if (ioa(&ts))
do_key(iokey(0)); do_key(iokey(1));
} }
/* note: that above ioa routine exists to consolidate all logic /* note: that above ioa routine exists to consolidate all logic
which is susceptible to signal interrupt and must then which is susceptible to signal interrupt and must then

View File

@ -48,7 +48,7 @@
//#define RMAN_IGNORED /* don't consider auto right margin glitch */ //#define RMAN_IGNORED /* don't consider auto right margin glitch */
//#define SCROLLVAR_NO /* disable intra-column horizontal scroll */ //#define SCROLLVAR_NO /* disable intra-column horizontal scroll */
//#define STRINGCASENO /* case insenstive compare/locate versions */ //#define STRINGCASENO /* case insenstive compare/locate versions */
//#define TERMIO_PROXY /* true line editing, beyond native input */ //#define TERMIOS_ONLY /* just limp along with native input only */
//#define TREE_NORESET /* sort keys do NOT force forest view OFF */ //#define TREE_NORESET /* sort keys do NOT force forest view OFF */
//#define USE_X_COLHDR /* emphasize header vs. whole col, for 'x' */ //#define USE_X_COLHDR /* emphasize header vs. whole col, for 'x' */
//#define VALIDATE_NLS /* validate the integrity of all nls tbls */ //#define VALIDATE_NLS /* validate the integrity of all nls tbls */
@ -140,18 +140,18 @@ char *strcasestr(const char *haystack, const char *needle);
// support for keyboard stuff (cursor motion keystrokes, mostly) // support for keyboard stuff (cursor motion keystrokes, mostly)
#define kbd_ESC '\033' #define kbd_ESC '\033'
#define kbd_SPACE ' ' #define kbd_SPACE ' '
#define kbd_UP 0x01 #define kbd_ENTER 128
#define kbd_DOWN 0x02 #define kbd_UP 129
#define kbd_RIGHT 0x03 #define kbd_DOWN 130
#define kbd_LEFT 0x04 #define kbd_LEFT 131
#define kbd_PGUP 0x05 #define kbd_RIGHT 132
#define kbd_PGDN 0x06 #define kbd_PGUP 133
#define kbd_END 0x07 #define kbd_PGDN 134
#define kbd_HOME 0x08 #define kbd_HOME 135
#define kbd_BKSP 0x09 #define kbd_END 136
#define kbd_ENTER 0x0a // this is also the real ^J #define kbd_BKSP 137
#define kbd_INS 0x0b #define kbd_INS 138
#define kbd_DEL 0x0c #define kbd_DEL 139
/* Special value in Pseudo_row to force an additional procs refresh /* Special value in Pseudo_row to force an additional procs refresh
-- used at startup and for task/thread mode transitions */ -- used at startup and for task/thread mode transitions */
@ -635,7 +635,7 @@ typedef struct WIN_t {
//atic char *alloc_s (const char *str); //atic char *alloc_s (const char *str);
//atic inline int ioa (struct timespec *ts); //atic inline int ioa (struct timespec *ts);
//atic int ioch (int ech, char *buf, unsigned cnt); //atic int ioch (int ech, char *buf, unsigned cnt);
//atic int iokey (int init); //atic int iokey (int action);
//atic char *ioline (const char *prompt); //atic char *ioline (const char *prompt);
//atic int readfile (FILE *fp, char **baddr, size_t *bsize, size_t *bread); //atic int readfile (FILE *fp, char **baddr, size_t *bsize, size_t *bread);
/*------ Small Utility routines ----------------------------------------*/ /*------ Small Utility routines ----------------------------------------*/