diff --git a/cmd/menu/Makefile b/cmd/menu/Makefile index e30304b4..abe55144 100644 --- a/cmd/menu/Makefile +++ b/cmd/menu/Makefile @@ -14,6 +14,7 @@ CFLAGS += $(INCX11) -DVERSION=\"$(VERSION)\" \ -DIXP_NEEDAPI=86 OBJ = main \ caret \ + history \ event \ menu \ ../wmii/geom \ diff --git a/cmd/menu/dat.h b/cmd/menu/dat.h index 209461d6..ee0d6e11 100644 --- a/cmd/menu/dat.h +++ b/cmd/menu/dat.h @@ -61,11 +61,15 @@ EXTERN Item* matchstart; EXTERN Item* matchend; EXTERN Item* matchidx; +EXTERN Item hist; EXTERN Item* histidx; EXTERN int maxwidth; EXTERN int result; +EXTERN char* (*find)(const char*, const char*); +EXTERN int (*compare)(const char*, const char*, size_t); + EXTERN char buffer[8092]; EXTERN char* _buffer; diff --git a/cmd/menu/fns.h b/cmd/menu/fns.h index ffdbc971..3fcc0005 100644 --- a/cmd/menu/fns.h +++ b/cmd/menu/fns.h @@ -9,6 +9,9 @@ void dispatch_event(XEvent*); Item* filter_list(Item*, char*); uint flushenterevents(void); uint flushevents(long, bool); +void history_dump(const char*, int); +char* history_search(int, char*, int); +char* histtext(Item*); void init_screens(void); void menu_init(void); void menu_show(void); diff --git a/cmd/menu/history.c b/cmd/menu/history.c new file mode 100644 index 00000000..5b0d490f --- /dev/null +++ b/cmd/menu/history.c @@ -0,0 +1,87 @@ +#include "dat.h" +#include +#include +#include +#include +#include +#include "fns.h" + +static void +splice(Item *i) { + i->next->prev = i->prev; + i->prev->next = i->next; +} + +char* +history_search(int dir, char *string, int n) { + Item *i; + + if(dir == FORWARD) { + if(histidx == &hist) + return hist.string; + for(i=histidx->next; i != hist.next; i=i->next) + if(!i->string || !compare(i->string, string, n)) { + histidx = i; + return i->string; + } + return string; + } + assert(dir == BACKWARD); + + if(histidx == &hist) { + free(hist.string); + hist.string = estrdup(input.string); + } + + for(i=histidx->prev; i != &hist; i=i->prev) + if(!compare(i->string, string, n)) { + histidx = i; + return i->string; + } + return string; +} + +void +history_dump(const char *path, int max) { + static char *items[20]; + static char *tmp; + Biobuf b; + Item *h, *first; + int i, n, fd; + + if(fork() != 0) + return; + + tmp = smprint("%s.XXXXXX", path); + fd = mkstemp(tmp); + if(fd < 0) { + fprint(2, "%s: Can't create temporary history file %q: %r\n", argv0, path); + return; + } + + hist.string = input.string; + n = 0; + hist.next->prev = nil; + for(h=&hist; h; h=h->prev) { + for(i=0; i < nelem(items); i++) + if(items[i] && !strcmp(h->string, items[i])) { + splice(h); + goto next; + } + items[n++ % nelem(items)] = h->string; + first = h; + if(!max || n >= max) + break; + next: + continue; + } + + Binit(&b, fd, OWRITE); + hist.next = nil; + for(h=first; h; h=h->next) + Bprint(&b, "%s\n", h->string); + Bterm(&b); + rename(tmp, path); + exit(0); +} + diff --git a/cmd/menu/main.c b/cmd/menu/main.c index 0eb4fa88..a1e9c18c 100644 --- a/cmd/menu/main.c +++ b/cmd/menu/main.c @@ -21,8 +21,6 @@ static Biobuf* inbuf; static char ctl[1024]; static char* ectl; -static char* (*find)(const char*, const char*); - static void usage(void) { fatal("usage: wimenu -i [-h ] [-a
]\n"); @@ -208,17 +206,21 @@ init_screens(void) { int main(int argc, char *argv[]) { - static Item hist; Item *item; char *address; char *histfile; int i; + long ndump; quotefmtinstall(); fmtinstall('r', errfmt); address = getenv("WMII_ADDRESS"); histfile = nil; + find = strstr; + compare = strncmp; + + ndump = -1; ARGBEGIN{ case 'a': @@ -227,8 +229,12 @@ main(int argc, char *argv[]) { case 'h': histfile = EARGF(usage()); break; + case 'n': + ndump = strtol(EARGF(usage()), nil, 10); + break; case 'i': find = strcasestr; + compare = strncasecmp; break; default: usage(); @@ -272,16 +278,17 @@ main(int argc, char *argv[]) { Bterm(inbuf); histidx = &hist; + link(&hist, &hist); if(histfile) { inbuf = Bopen(histfile, OREAD); - if(!inbuf) - fatal("Can't open history file %q: %r", histfile); - item = populate_list(inbuf, true); - if(item) { - link(item->prev, &hist); - item->prev = nil; + if(inbuf) { + item = populate_list(inbuf, true); + if(item) { + link(item->prev, &hist); + link(&hist, item); + } + Bterm(inbuf); } - Bterm(inbuf); } init_screens(); @@ -290,6 +297,10 @@ main(int argc, char *argv[]) { if(i) fprint(2, "%s: error: %r\n", argv0); XCloseDisplay(display); + + if(ndump >= 0 && histfile && result == 0) + history_dump(histfile, ndump); + return result; } diff --git a/cmd/menu/menu.c b/cmd/menu/menu.c index 8bde555b..53d07eae 100644 --- a/cmd/menu/menu.c +++ b/cmd/menu/menu.c @@ -14,8 +14,7 @@ static void menu_draw(void); enum { ACCEPT = CARET_LAST, REJECT, - HIST_NEXT, - HIST_PREV, + HIST, KILL, CMPL_NEXT, CMPL_PREV, @@ -49,32 +48,15 @@ menu_unmap(long id, void *p) { XFlush(display); } -static char* -histtext(Item *i) { - static char *orig; - - if(!histidx->string) { - free(orig); - orig = strdup(input.string); - } - return i->string ? i->string : orig; -} - static void menu_cmd(int op, int motion) { + int n; switch(op) { - case HIST_NEXT: - if(histidx->next) { - caret_insert(histtext(histidx->next), true); - histidx = histidx->next; - } - break; - case HIST_PREV: - if(histidx->prev) { - caret_insert(histtext(histidx->prev), true); - histidx = histidx->prev; - } + case HIST: + n = input.pos - input.string; + caret_insert(history_search(motion, input.string, n), true); + input.pos = input.string + n; break; case KILL: caret_delete(BACKWARD, motion); @@ -190,7 +172,7 @@ menu_draw(void) { r2.max.x = inputw; drawstring(ibuf, font, r2, West, input.string, cnorm.fg); - r2.min.x = textwidth_l(font, input.string, input.pos - input.string) + pad/2; + r2.min.x = textwidth_l(font, input.string, input.pos - input.string) + pad/2 - 1; r2.max.x = r2.min.x + 2; r2.min.y++; r2.max.y--; @@ -266,11 +248,11 @@ kdown_event(Window *w, XKeyEvent *e) { return; case XK_n: case XK_N: - menu_cmd(HIST_NEXT, 0); + menu_cmd(HIST, FORWARD); return; case XK_p: case XK_P: - menu_cmd(HIST_PREV, 0); + menu_cmd(HIST, BACKWARD); return; case XK_h: case XK_H: @@ -349,10 +331,10 @@ kdown_event(Window *w, XKeyEvent *e) { menu_cmd(FORWARD, CHAR); return; case XK_Up: - menu_cmd(HIST_PREV, 0); + menu_cmd(HIST, BACKWARD); return; case XK_Down: - menu_cmd(HIST_NEXT, 0); + menu_cmd(HIST, FORWARD); return; case XK_Home: menu_cmd(CMPL_FIRST, 0); diff --git a/cmd/wmii.rc.rc b/cmd/wmii.rc.rc index 773f86d7..9e81ae23 100755 --- a/cmd/wmii.rc.rc +++ b/cmd/wmii.rc.rc @@ -49,12 +49,6 @@ fn wi_9menu { -^(sf sb br)^$wmiifocuscol $* } -fn wi_addhist { - file = $1 len=$2 { shift 2 - { cat $file; echo $*; } | uniq | sed '/^$/d' \ - | tail -$len >$file.$pid - mv $file.$pid $file}} - fn wi_fnmenu { group=$1^Menu-$2 last=$group^_last fns=`{wi_getfuns $group} { shift 2 diff --git a/rc/rc.wmii.rc b/rc/rc.wmii.rc index 279b62ac..0c23ab94 100755 --- a/rc/rc.wmii.rc +++ b/rc/rc.wmii.rc @@ -215,19 +215,18 @@ key $MODKEY-Shift-c || fn $key { wmiir xwrite /client/sel/ctl kill} key $MODKEY-a || fn $key { - Action `{wi_actions | wimenu} &} + Action `{wi_actions | wimenu -h $hist.action -n $histlen} &} key $MODKEY-p || fn $key { - ifs=() { cmd = `{wimenu -h $progs_hist <$progs_file} } - wi_runcmd $cmd & - wi_addhist $hist.prog $histlen $cmd} + ifs=() { wi_runcmd `{wimenu -h $hist.prog -n $histlen <$progs_file} & }} + key $MODKEY-Return || fn $key { wi_runcmd $WMII_TERM &} key $MODKEY-t || fn $key { - wmiir xwrite /ctl view `{wi_tags | wimenu} &} + wmiir xwrite /ctl view `{wi_tags | wimenu -h $hist.tag -n 50} &} key $MODKEY-Shift-t || fn $key { sel = `{wmiir read /client/sel/ctl | sed 1q} \ - wmiir xwrite /client/$sel/tags `{wi_tags | wimenu} &} + wmiir xwrite /client/$sel/tags `{wi_tags | wimenu -h $hist.tag -n 50} &} key $MODKEY-^`{seq 0 9} || fn $key { wmiir xwrite /ctl view `{echo $1 | sed 's/.*-//'}}