mirror of
https://github.com/0intro/wmii
synced 2025-02-14 05:14:30 +03:00
[menu] Add history search, and the ability to write history while removing dups within a 20 item sliding window.
This commit is contained in:
parent
cbc50a7d45
commit
8c99e0b722
@ -14,6 +14,7 @@ CFLAGS += $(INCX11) -DVERSION=\"$(VERSION)\" \
|
||||
-DIXP_NEEDAPI=86
|
||||
OBJ = main \
|
||||
caret \
|
||||
history \
|
||||
event \
|
||||
menu \
|
||||
../wmii/geom \
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
87
cmd/menu/history.c
Normal 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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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/.*-//'}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user