diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | pw.1 | 57 | ||||
-rw-r--r-- | pw.c | 73 |
3 files changed, 109 insertions, 25 deletions
@@ -57,8 +57,8 @@ for text streams. few GNU/Linuxes. It built on OpenBSD, but didn't run properly; I didn't investigate into it. Patches welcome. -* **`pw` is tiny:** it is under 2000 lines of C in a single source file, - compiling to an executable of around 25 kilobytes. +* **`pw` is tiny:** it is a little over 2000 lines of C in a single source + file, compiling to an executable of around 32 kilobytes. * **`pw` requires a very low amount of RAM:** Given inputs with typical line lengths, and 24 line snapshots, `pw` it needs less than 64 kilobytes of RAM @@ -301,18 +301,9 @@ Enter colon command mode. In colon command mode, the status line clears and a colon prompt appears there. An extended command can be entered. Pressing .I Enter -in colon mode dispatches the command. Simple editing is available: -backspace, -.B Ctrl-W -word erase and -.B Ctrl-U -line erase. If backspace is used in an empty colon line, colon mode -terminates without executing a command. -.B Ctrl-C -and -.B Esc -also terminate colon mode without executing a command. Colon commands -are documented in the COLON COMMANDS section below. +in colon mode dispatches the command. Colon commands are documented in the +COLON COMMANDS section below. Simple editing is available, described in the +EDITING COMMANDS section below. .IP "[\fIpos\fP]\fB/[!]\fP\fIpattern\fP, [\fIpos\fP]\fB?[!]\fP\fIpattern\fP" Set a trigger if a non-empty @@ -747,6 +738,48 @@ as the argument to the option, the grep stack, trigger state and display parameters will be stored to exactly the same configuration that existed at the time the state was saved. +.SH EDITING COMMANDS + +The colon command mode and trigger entry modes support rudimentary +editing. The commands are as follows: + +.IP "\fBCtrl-B\fP, \fILeft Arrow\fP" +Move the cursor one character to the left. + +.IP "\fBCtrl-F\fP, \fIRight Arrow\fP" +Move the cursor one character to the right. + +.IP "\fBCtrl-A\fP" +Move the cursor to the beginning of the line. + +.IP "\fBCtrl-E\fP" +Move the cursor to the end of the line. + +.IP \fBBackspace\fP +Erase the character to the left of the cursor. The ASCII BS and DEL +characters are both recognized as backspace (an amazing trick not +yet mastered by Unix TTY's). If backspace is used in an empty line, +the respective mode terminates without executing a command or setting +a trigger. + +.IP \fBCtrl-D\fP +Delete the character under the block cursor, or to the right of +a line or I-beam cursor. + +.IP \fBCtrl-W\fP +Delete the word to the left of the cursor, including any trailing +whitespace between the word and the cursor. + +.IP \fBCtrl-U\fP +Erase the all the characters to the left of the cursor. + +.IP \fBCtrl-K\fP +Erase the the character under the block cursor, or to the right +of a line or I-beam cursor, and all characters which follow. + +.IP "\fBCtrl-C\fP, \fBESC\fP" +Leave edit mode, without executing a colon command or setting a trigger. + .SH OPTIONS .IP "\fB-i\fP \fIreal\fP" @@ -100,6 +100,7 @@ typedef struct pwstate { unsigned stat; int sncount, tcount; char *curcmd, *savedcmd; + size_t editpos; char cmdbuf[cmdsize]; } pwstate; @@ -607,6 +608,13 @@ static void drawstatus(pwstate *pw) fputs(status, stdout); clreol(0); + if (pw->curcmd) { + if (pw->curcmd[pw->editpos] != 0) { + putchar('\r'); + if (pw->editpos > 0) + printf("\033[%dC", pw->editpos); + } + } fflush(stdout); } @@ -1708,6 +1716,7 @@ int main(int argc, char **argv) case ':': case '/': case '?': kbd_state = kbd_lcmd; histpos = 0; + pw.editpos = 1; pw.cmdbuf[0] = ch; pw.cmdbuf[1] = 0; pw.curcmd = pw.cmdbuf; @@ -1848,6 +1857,12 @@ int main(int argc, char **argv) case 'B': ch = ctrl('n'); goto fakecmd; + case 'D': + ch = ctrl('b'); + goto fakecmd; + case 'C': + ch = ctrl('f'); + goto fakecmd; } break; case kbd_lcmd: @@ -1890,29 +1905,62 @@ int main(int argc, char **argv) cmdcount = INT_MAX; prevcmd = 0; break; + case ctrl('b'): + if (pw.editpos > 1) + pw.editpos--; + break; + case ctrl('f'): + if (pw.cmdbuf[pw.editpos] != 0) + pw.editpos++; + break; + case ctrl('k'): + pw.cmdbuf[pw.editpos] = 0; + break; + case ctrl('a'): + pw.editpos = 1; + break; + case ctrl('e'): + pw.editpos = strlen(pw.cmdbuf); + break; case BS: case DEL: { size_t len = strlen(pw.cmdbuf); + if (pw.editpos > 1 || (pw.editpos == 1 && len == 1)) { + pw.editpos--; + memmove(pw.cmdbuf + pw.editpos, pw.cmdbuf + pw.editpos + 1, + len - pw.editpos); + } + if (len == 1) { kbd_state = kbd_cmd; pw.curcmd = 0; // cmdcount deliberately not reset to INT_MAX - } else { - pw.cmdbuf[--len] = 0; } } break; + case ctrl('d'): + { + size_t len = strlen(pw.cmdbuf); + if (pw.editpos < len) + memmove(pw.cmdbuf + pw.editpos, pw.cmdbuf + pw.editpos + 1, + len - pw.editpos + 1); + } + break; case ctrl('u'): - pw.cmdbuf[1] = 0; + memmove(pw.cmdbuf + 1, pw.cmdbuf + pw.editpos, + strlen(pw.cmdbuf + pw.editpos) + 1); + pw.editpos = 1; break; case ctrl('w'): { - size_t len = strlen(pw.cmdbuf); - while (len > 1 && isspace((unsigned char) pw.cmdbuf[len - 1])) - len--; - while (len > 1 && !isspace((unsigned char) pw.cmdbuf[len - 1])) - len--; - pw.cmdbuf[len] = 0; + size_t npos = pw.editpos; + while (npos > 1 && isspace((unsigned char) pw.cmdbuf[npos - 1])) + npos--; + while (npos > 1 && !isspace((unsigned char) pw.cmdbuf[npos - 1])) + npos--; + memmove(pw.cmdbuf + npos, pw.cmdbuf + pw.editpos, + strlen(pw.cmdbuf + pw.editpos) + 1); + pw.editpos = npos; } break; case ctrl('p'): @@ -1932,6 +1980,7 @@ int main(int argc, char **argv) if (histpos < nhist) { char *cmd = (*hist)[histpos++]; strcpy(pw.cmdbuf, cmd); + pw.editpos = strlen(cmd); } } else { if (histpos >= 1) { @@ -1941,6 +1990,7 @@ int main(int argc, char **argv) if (histpos > 1) { char *cmd = (*hist)[--histpos - 1]; strcpy(pw.cmdbuf, cmd); + pw.editpos = strlen(cmd); } else if (histpos == 1) { --histpos; strcpy(pw.cmdbuf, pw.savedcmd); @@ -1955,8 +2005,9 @@ int main(int argc, char **argv) { size_t len = strlen(pw.cmdbuf); if (len < sizeof pw.cmdbuf - 1 && (int) len < pw.columns - 1) { - pw.cmdbuf[len++] = ch; - pw.cmdbuf[len] = 0; + memmove(pw.cmdbuf + pw.editpos + 1, pw.cmdbuf + pw.editpos, + len - pw.editpos + 1); + pw.cmdbuf[pw.editpos++] = ch; } } break; |