aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-04-27 19:34:48 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-04-27 19:34:48 -0700
commitcee49acbf13324bce50b4b8ef9c76fcca17790a0 (patch)
treed3da738182b8079f7db7299c91369b0ba4c158ea
parentbb28f2cd6687e100e52233c6cc58a1909a11c9b3 (diff)
downloadpw-cee49acbf13324bce50b4b8ef9c76fcca17790a0.tar.gz
pw-cee49acbf13324bce50b4b8ef9c76fcca17790a0.tar.bz2
pw-cee49acbf13324bce50b4b8ef9c76fcca17790a0.zip
New feature: trigger mode.
Prototype: does substring searching only: no regex.
-rw-r--r--pw.128
-rw-r--r--pw.c118
2 files changed, 119 insertions, 27 deletions
diff --git a/pw.1 b/pw.1
index 23c02a4..5fe9000 100644
--- a/pw.1
+++ b/pw.1
@@ -177,6 +177,34 @@ and
also terminate colon mode without executing a command. Colon commands
are documented in the COLON COMMANDS section below.
+.IP \fB/\fP\fIpattern\fP
+Activate head trigger mode if a non-empty
+.I pattern
+is specified, or else cancel trigger mode if an empty pattern is
+specified. Under head trigger mode,
+the display refreshes only when the most recent line in the FIFO
+matches the specified
+.IR pattern .
+That line at the head of the FIFO is the one which will appear at
+the bottom of the display, since newer lines appear at the bottom
+and scroll out toward the top.
+In head trigger mode, the status string
+.BI "TRIG (/" pattern ")"
+appears, showing the pattern preceded by a slash.
+
+.IP \fB?\fP\fIpattern\fP
+Activate tail trigger mode if a non-empty
+.I pattern
+is specified, or else cancel trigger mode if an empty pattern is
+specified. Under tail trigger mode,
+the display refreshes only when the least recent line in the FIFO
+matches the specified
+.IR pattern .
+That line at the tail of the FIFO is the one which will appear at
+the top of the display. In tail trigger mode, the status string
+.BI "TRIG (?" pattern ")"
+appears, showing the pattern preceded by a question mark.
+
.SH COLON COMMANDS
First, some general remarks. Display refresh doesn't pause during the editing
diff --git a/pw.c b/pw.c
index 7f39674..9e2a64a 100644
--- a/pw.c
+++ b/pw.c
@@ -13,9 +13,12 @@
#include <sys/time.h>
enum status_flags {
- stat_dirty = 1,
- stat_eof = 2,
- stat_susp = 4
+ stat_dirty = 1, // display needs refresh
+ stat_eof = 2, // end of data reached
+ stat_susp = 4, // display refresh suspended
+ stat_htmode = 8, // head trigger mode
+ stat_ttmode = 16, // tail trigger mode
+ stat_trgrd = 32 // triggered flag
};
typedef struct dstr {
@@ -28,6 +31,7 @@ typedef struct dstr {
char **snapshot;
int snaplines;
+char *trigpat;
static void panic(const char *fmt, ...)
{
@@ -88,6 +92,14 @@ static char *dsgrow(char *str, size_t len)
return ds->str;
}
+static char *dsdup(char *str)
+{
+ size_t len = strlen(str);
+ char *copy = dsgrow(0, len);
+ memcpy(copy, str, len);
+ return copy;
+}
+
static char *addch(char *line, int ch)
{
size_t len = line ? dslen(line) : 0;
@@ -178,9 +190,13 @@ static void drawstatus(unsigned stat, char *cmd)
{
if (cmd) {
printf("%s", cmd);
- } else if ((stat & (stat_eof | stat_susp))) {
+ } else if ((stat & (stat_eof | stat_susp | stat_htmode | stat_ttmode))) {
if ((stat & stat_eof))
printf("EOF ");
+ else if ((stat & stat_htmode))
+ printf("TRIG (/%s) ", trigpat);
+ else if ((stat & stat_ttmode))
+ printf("TRIG (?%s) ", trigpat);
if ((stat & stat_susp))
printf("SUSPENDED ");
} else {
@@ -192,7 +208,10 @@ static void drawstatus(unsigned stat, char *cmd)
static void redraw(char **circbuf, int nlines, int hpos,
int columns, unsigned stat, char *cmd)
{
- if ((stat & stat_susp) == 0) {
+ if ((stat & stat_susp) == 0 &&
+ (stat & (stat_htmode | stat_trgrd)) != stat_htmode &&
+ (stat & (stat_ttmode | stat_trgrd)) != stat_ttmode)
+ {
if (snapshot) {
for (int i = 0; i < snaplines; i++)
dsdrop(snapshot[i]);
@@ -204,7 +223,9 @@ static void redraw(char **circbuf, int nlines, int hpos,
snapshot[i] = dsref(circbuf[i]);
}
} else {
- clrline();
+ printf("\r\033[%dA\033[J", snaplines);
+ for (int i = 0; i < snaplines; i++)
+ drawline(snapshot[i], hpos, columns);
}
drawstatus(stat, cmd);
}
@@ -283,10 +304,13 @@ int main(int argc, char **argv)
struct termios tty_saved, tty_new;
struct winsize ws = { 0 };
int columns = 80;
- enum kbd_state { kbd_cmd, kbd_esc, kbd_bkt, kbd_exit, kbd_colon, kbd_result };
+ enum kbd_state {
+ kbd_cmd, kbd_esc, kbd_bkt, kbd_exit,
+ kbd_colon, kbd_result, kbd_htrig, kbd_ttrig
+ };
int auto_quit = 1;
int exit_status = EXIT_FAILURE;
- char cmdbuf[100], *colcmd = 0;
+ char cmdbuf[100], *curcmd = 0;
if (fd < 0)
panic("unable to obtain input file descriptor");
@@ -361,11 +385,16 @@ int main(int argc, char **argv)
for (unsigned stat = stat_dirty, hpos = 0, kbd_state = kbd_cmd, lasttime = ~0U;
kbd_state != kbd_exit ;)
{
+ int force = 0;
struct pollfd pe[2] = {
{ .fd = ttyfd, .events = POLLIN | POLLHUP | POLLERR },
{ .fd = fd, .events = POLLIN | POLLHUP | POLLERR },
};
+ if (stat & stat_trgrd)
+ force = 1;
+
+ if (!force)
{
struct timeval tv;
unsigned now;
@@ -374,38 +403,49 @@ int main(int argc, char **argv)
now = (((unsigned) tv.tv_sec)%1000000)*1000 + tv.tv_usec/1000;
if (lasttime == ~0U || now - lasttime > (unsigned) long_interval) {
if ((stat & stat_dirty) && nlines == maxlines)
- redraw(circbuf, nlines, hpos, columns, stat, colcmd);
+ force = 1;
lasttime = now;
stat &= ~stat_dirty;
}
}
+ if (force) {
+ redraw(circbuf, nlines, hpos, columns, stat, curcmd);
+ stat &= ~(stat_dirty | stat_trgrd);
+ }
+
if (poll(pe, ((stat & stat_eof)) ? 1 : 2, poll_interval) <= 0) {
if ((stat & stat_dirty) && nlines == maxlines) {
- redraw(circbuf, nlines, hpos, columns, stat, colcmd);
+ redraw(circbuf, nlines, hpos, columns, stat, curcmd);
stat &= ~stat_dirty;
}
if (kbd_state == kbd_esc || kbd_state == kbd_result) {
kbd_state = kbd_cmd;
- colcmd = 0;
+ curcmd = 0;
clrline();
- drawstatus(stat, colcmd);
+ drawstatus(stat, curcmd);
}
} else {
if ((stat & stat_eof) == 0 && pe[1].revents) {
if ((line = getln(stdin))) {
+ if ((stat & stat_htmode))
+ if (strstr(line, trigpat))
+ stat |= stat_trgrd;
if (nlines == maxlines) {
dsdrop(circbuf[0]);
memmove(circbuf, circbuf + 1, (nlines - 1) * sizeof *circbuf);
circbuf[nlines - 1] = line;
stat |= stat_dirty;
+ if ((stat & stat_ttmode))
+ if (strstr(circbuf[0], trigpat))
+ stat |= stat_trgrd;
} else {
circbuf[nlines++] = line;
if ((stat & stat_susp) == 0) {
snapshot[snaplines++] = dsref(line);
clrline();
drawline(line, hpos, columns);
- drawstatus(stat, colcmd);
+ drawstatus(stat, curcmd);
}
}
} else {
@@ -413,7 +453,7 @@ int main(int argc, char **argv)
kbd_state = kbd_exit;
else
stat |= stat_eof;
- redraw(circbuf, nlines, hpos, columns, stat, colcmd);
+ redraw(circbuf, nlines, hpos, columns, stat, curcmd);
stat |= stat_eof;
stat &= ~stat_dirty;
if (!ferror(stdin))
@@ -431,7 +471,7 @@ int main(int argc, char **argv)
switch (ch) {
case 'q': case 3:
kbd_state = kbd_exit;
- if ((stat & (stat_eof | stat_susp))) {
+ if ((stat & (stat_eof | stat_susp | stat_htmode | stat_ttmode))) {
clrline();
fflush(stdout);
}
@@ -467,7 +507,19 @@ int main(int argc, char **argv)
kbd_state = kbd_colon;
cmdbuf[0] = ch;
cmdbuf[1] = 0;
- colcmd = cmdbuf;
+ curcmd = cmdbuf;
+ break;
+ case '/':
+ kbd_state = kbd_htrig;
+ cmdbuf[0] = ch;
+ cmdbuf[1] = 0;
+ curcmd = cmdbuf;
+ break;
+ case '?':
+ kbd_state = kbd_ttrig;
+ cmdbuf[0] = ch;
+ cmdbuf[1] = 0;
+ curcmd = cmdbuf;
break;
}
break;
@@ -491,24 +543,35 @@ int main(int argc, char **argv)
}
break;
case kbd_colon:
+ case kbd_htrig:
+ case kbd_ttrig:
switch (ch) {
case 27: case 13: case 3:
kbd_state = kbd_cmd;
stat |= stat_dirty;
- if (ch == 13 && cmdbuf[1]) {
- execute(cmdbuf);
- stat &= ~stat_dirty;
- kbd_state = kbd_result;
- break;
+ if (ch == 13) {
+ if (kbd_state == kbd_colon && cmdbuf[1]) {
+ execute(cmdbuf);
+ stat &= ~stat_dirty;
+ kbd_state = kbd_result;
+ break;
+ } else if (cmdbuf[1]) {
+ dsdrop(trigpat);
+ trigpat = dsdup(cmdbuf + 1);
+ stat &= ~(stat_htmode | stat_ttmode);
+ stat |= (kbd_state == kbd_htrig) ? stat_htmode : stat_ttmode;
+ } else {
+ stat &= ~(stat_htmode | stat_ttmode);
+ }
}
- colcmd = 0;
+ curcmd = 0;
break;
case 8: case 127:
{
size_t len = strlen(cmdbuf);
if (len == 1) {
kbd_state = kbd_cmd;
- colcmd = 0;
+ curcmd = 0;
stat |= stat_dirty;
} else {
cmdbuf[--len] = 0;
@@ -543,18 +606,19 @@ int main(int argc, char **argv)
case kbd_result:
kbd_state = kbd_cmd;
stat |= stat_dirty;
- colcmd = 0;
+ curcmd = 0;
break;
case kbd_exit:
break;
}
if ((stat & stat_dirty)) {
- redraw(circbuf, nlines, hpos, columns, stat, colcmd);
+ redraw(circbuf, nlines, hpos, columns, stat, curcmd);
stat &= ~stat_dirty;
- } else if (kbd_state == kbd_colon || kbd_state == kbd_result) {
+ } else switch (kbd_state) {
+ case kbd_colon: case kbd_htrig: case kbd_ttrig: case kbd_result:
clrline();
- drawstatus(stat, colcmd);
+ drawstatus(stat, curcmd);
}
}
}