aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--pw.157
-rw-r--r--pw.c73
3 files changed, 109 insertions, 25 deletions
diff --git a/README.md b/README.md
index 768d49e..4fd6491 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/pw.1 b/pw.1
index edd613d..6729e47 100644
--- a/pw.1
+++ b/pw.1
@@ -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"
diff --git a/pw.c b/pw.c
index 8f2ee3c..287bd50 100644
--- a/pw.c
+++ b/pw.c
@@ -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;