top: enable recall of previous input lines for re-edit

With this commit, users can now retrieve previous line
input for re-editing and/or re-input using the Up/Down
arrow keys (or their aliases). This mirrors the 'bash'
or 'less' interface and represents a major enhancement
achieved via a somewhat minor impact to our code base.

[ 33 lines of code, 5 closing braces & some comments ]
[ all in 1 function, when TERMIOS_ONLY isn't defined ]

Currently, the upper limit for such recallable strings
has been set at 50 but that could be easily increased.

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

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 477b10c0bd
commit 2efe275512
3 changed files with 75 additions and 12 deletions

View File

@ -90,7 +90,7 @@
.
.\" Document /////////////////////////////////////////////////////////////
.\" ----------------------------------------------------------------------
.TH TOP 1 "January 2013" "procps-ng" "User Commands"
.TH TOP 1 "February 2013" "procps-ng" "User Commands"
.\" ----------------------------------------------------------------------
.\" ----------------------------------------------------------------------
@ -208,6 +208,15 @@ Insert this command after \*(We has been suspended but before resuming it.
reset restore your \fBterminal settings\fR
.Ed
\*(NT the width of \*(We's display will be limited to \*(WX positions.
Displaying all fields requires \*(WF characters.
Remaining screen width is usually allocated to any variable width columns
currently visible.
The variable width columns, such as COMMAND, are noted in topic
3a. DESCRIPTIONS of Fields.
Actual output width may also be influenced by the \-w switch, which is
discussed in topic 1. COMMAND\-LINE Options.
Lastly, some of \*(We's screens or functions require the use of cursor
motion keys like the standard \*(KAs plus the Home, End, PgUp and PgDn keys.
If your terminal or emulator does not provide those keys, the following
@ -224,14 +233,20 @@ combinations are accepted as alternatives:
End alt +\fB Right\fR or alt + ctrl +\fB l \fR
.Ed
\*(NT the width of \*(We's display will be limited to \*(WX positions.
Displaying all fields requires \*(WF characters.
Remaining screen width is usually allocated to any variable width columns
currently visible.
The variable width columns, such as COMMAND, are noted in topic
3a. DESCRIPTIONS of Fields.
Actual output width may also be influenced by the \-w switch, which is
discussed in topic 1. COMMAND\-LINE Options.
The \fBUp\fR and \fBDown\fR \*(KAs have special significance when prompted
for line input terminated with the <Enter> key.
Those keys, or their aliases, can be used to retrieve previous input lines
which can then be edited and re-input.
And there are four additional keys available with line oriented input.
.Bd -literal -compact
\fI key special-significance \fR
Up recall \fBolder\fR strings for re-editing
Down recall \fBnewer\fR strings or \fBerase\fR entire line
Insert toggle between \fBinsert\fR and \fBovertype\fR modes
Delete character \fBremoved\fR at cursor, moving others left
Home jump to \fBbeginning\fR of input line
End jump to \fBend\fR of input line
.Ed
.\" ......................................................................
.SS Startup Defaults

View File

@ -1073,8 +1073,10 @@ static char *ioline (const char *prompt) {
* Get line oriented interactive input from the user,
* going way beyond native tty support by providing:
* . true line editing, not just destructive backspace
* . an input limit sensitive to current screen dimensions */
* . an input limit sensitive to current screen dimensions
* . ability to recall prior strings for re-input/re-editing */
static char *ioline (const char *prompt) {
#define savMAX 50
// thank goodness memmove allows the two strings to overlap
#define sqzSTR { memmove(&buf[pos], &buf[pos+1], bufMAX-pos); \
buf[sizeof(buf)-1] = '\0'; }
@ -1084,8 +1086,19 @@ static char *ioline (const char *prompt) {
#define phyCOL (beg+pos+1)
#define bufMAX ((int)sizeof(buf)-2) // -1 for '\0' string delimeter
static char buf[MEDBUFSIZ+1]; // +1 for '\0' string delimeter
int beg, pos, len, key, ovt;
int beg, pos, len, key, ovt, i;
struct lin_s {
struct lin_s *bkw; // ptr to older saved strs
struct lin_s *fwd; // ptr to newer saved strs
char *str; // the saved string
};
static struct lin_s *anchor, *plin;
if (!anchor) {
anchor = alloc_c(sizeof(struct lin_s));
anchor->str = alloc_s(""); // top-of-stack == empty str
}
plin = anchor;
pos = ovt = 0;
beg = show_pmt(prompt);
memset(buf, '\0', sizeof(buf));
@ -1122,6 +1135,18 @@ static char *ioline (const char *prompt) {
case kbd_END:
pos = len;
break;
case kbd_UP:
if (plin->bkw) {
plin = plin->bkw;
memset(buf, '\0', sizeof(buf));
pos = snprintf(buf, sizeof(buf), "%s", plin->str);
}
break;
case kbd_DOWN:
memset(buf, '\0', sizeof(buf));
if (plin->fwd) plin = plin->fwd;
pos = snprintf(buf, sizeof(buf), "%s", plin->str);
break;
default: // what we REALLY wanted (maybe)
if (isprint(key) && logCOL < bufMAX && phyCOL < Screen_cols) {
if (!ovt) expSTR
@ -1133,7 +1158,27 @@ static char *ioline (const char *prompt) {
putp(tg2(beg+pos, Msg_row));
} while (key != kbd_ENTER && key != kbd_ESC);
return buf;
// weed out duplicates, including empty strings (top-of-stack)...
for (i = 0, plin = anchor; ; i++) {
if (!STRCMP(plin->str, buf)) return buf;
if (!plin->bkw) break; // let i equal total stacked strings
plin = plin->bkw; // ( with plin representing bottom )
}
if (i < savMAX)
plin = alloc_c(sizeof(struct lin_s));
else { // when a new string causes overflow
plin->fwd->bkw = NULL; // make next-to-last string new last
free(plin->str); // and toss copy but keep the struct
}
plin->str = alloc_s(buf); // copy user's new unique input line
plin->bkw = anchor->bkw; // keep empty string as top-of-stack
if (plin->bkw) // did we have some already stacked?
plin->bkw->fwd = plin; // yep, so point prior to new string
plin->fwd = anchor; // and prepare to be a second banana
anchor->bkw = plin; // by sliding it in as new number 2!
return buf; // protect our copy, return original
#undef savMAX
#undef sqzSTR
#undef expSTR
#undef logCOL

View File

@ -600,6 +600,9 @@ typedef struct WIN_t {
#if (LRGBUFSIZ < SCREENMAX)
# error 'LRGBUFSIZ' must NOT be less than 'SCREENMAX'
#endif
#if defined(TERMIOS_ONLY)
# warning 'TERMIOS_ONLY' disables input recall and makes man doc incorrect
#endif
/*###### Some Prototypes (ha!) #########################################*/