[menu] Add history search, and the ability to write history while removing dups within a 20 item sliding window.

This commit is contained in:
Kris Maglione 2008-10-15 23:15:42 -04:00
parent cbc50a7d45
commit 8c99e0b722
8 changed files with 132 additions and 51 deletions

View File

@ -14,6 +14,7 @@ CFLAGS += $(INCX11) -DVERSION=\"$(VERSION)\" \
-DIXP_NEEDAPI=86
OBJ = main \
caret \
history \
event \
menu \
../wmii/geom \

View File

@ -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;

View File

@ -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);

87
cmd/menu/history.c Normal file
View File

@ -0,0 +1,87 @@
#include "dat.h"
#include <assert.h>
#include <bio.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#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);
}

View File

@ -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 <history>] [-a <address>]\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;
}

View File

@ -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);

View File

@ -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

View File

@ -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/.*-//'}}