mirror of https://github.com/0intro/wmii
[menu] Add proper caret support
This commit is contained in:
parent
5db3cf60bd
commit
318f180173
|
@ -13,6 +13,7 @@ LDFLAGS += -lm $(LIBX11) -lXext -lXrandr -lXinerama \
|
||||||
CFLAGS += $(INCX11) -DVERSION=\"$(VERSION)\" \
|
CFLAGS += $(INCX11) -DVERSION=\"$(VERSION)\" \
|
||||||
-DIXP_NEEDAPI=86
|
-DIXP_NEEDAPI=86
|
||||||
OBJ = main \
|
OBJ = main \
|
||||||
|
caret \
|
||||||
event \
|
event \
|
||||||
menu \
|
menu \
|
||||||
../wmii/geom \
|
../wmii/geom \
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include "dat.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
iswordrune(Rune r) {
|
||||||
|
if(isalpharune(r))
|
||||||
|
return 1;
|
||||||
|
return r < 0x80 && (r == '_' || isdigit(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
prev_rune(char *start, char *p, Rune *r) {
|
||||||
|
|
||||||
|
*r = 0;
|
||||||
|
if(p == start)
|
||||||
|
return p;
|
||||||
|
while(p > start && (*(--p)&0xC0) == 0x80)
|
||||||
|
;
|
||||||
|
chartorune(r, p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
next_rune(char *p, Rune *r) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*r = 0;
|
||||||
|
if(!*p)
|
||||||
|
return p;
|
||||||
|
i = chartorune(r, p);
|
||||||
|
return p + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
caret_find(int dir, int type) {
|
||||||
|
char *end;
|
||||||
|
char *next, *p;
|
||||||
|
Rune r;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
p = input.pos;
|
||||||
|
if(dir == FORWARD) {
|
||||||
|
end = input.end;
|
||||||
|
switch(type) {
|
||||||
|
case LINE:
|
||||||
|
return end;
|
||||||
|
case WORD:
|
||||||
|
chartorune(&r, p);
|
||||||
|
res = iswordrune(r);
|
||||||
|
while(next=next_rune(p, &r), r && iswordrune(r) == res && !isspacerune(r))
|
||||||
|
p = next;
|
||||||
|
while(next=next_rune(p, &r), r && isspacerune(r))
|
||||||
|
p = next;
|
||||||
|
return p;
|
||||||
|
case CHAR:
|
||||||
|
if(p < end)
|
||||||
|
return p+1;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(dir == BACKWARD) {
|
||||||
|
end = input.string;
|
||||||
|
switch(type) {
|
||||||
|
case LINE:
|
||||||
|
return end;
|
||||||
|
case WORD:
|
||||||
|
while(next=prev_rune(end, p, &r), r && isspacerune(r))
|
||||||
|
p = next;
|
||||||
|
prev_rune(end, p, &r);
|
||||||
|
res = iswordrune(r);
|
||||||
|
while(next=prev_rune(end, p, &r), r && iswordrune(r) == res && !isspacerune(r))
|
||||||
|
p = next;
|
||||||
|
return p;
|
||||||
|
case CHAR:
|
||||||
|
if(p > end)
|
||||||
|
return p-1;
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die("not reached");
|
||||||
|
return nil; /* shut up ken */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
caret_move(int dir, int type) {
|
||||||
|
input.pos = caret_find(dir, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
caret_delete(int dir, int type) {
|
||||||
|
char *pos, *p;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
p = caret_find(dir, type);
|
||||||
|
pos = input.pos;
|
||||||
|
if(p == input.end)
|
||||||
|
input.end = pos;
|
||||||
|
else {
|
||||||
|
if(p < pos) {
|
||||||
|
pos = p;
|
||||||
|
p = input.pos;
|
||||||
|
}
|
||||||
|
n = input.end - p;
|
||||||
|
memmove(pos, p, n);
|
||||||
|
input.pos = pos;
|
||||||
|
input.end = pos + n;
|
||||||
|
}
|
||||||
|
*input.end = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
caret_insert(char *s, bool clear) {
|
||||||
|
int pos, end, len, size;
|
||||||
|
|
||||||
|
if(clear) {
|
||||||
|
input.pos = input.string;
|
||||||
|
input.end = input.string;
|
||||||
|
}
|
||||||
|
len = strlen(s);
|
||||||
|
pos = input.pos - input.string;
|
||||||
|
end = input.end - input.string;
|
||||||
|
|
||||||
|
size = input.size;
|
||||||
|
if(input.size == 0)
|
||||||
|
input.size = 1;
|
||||||
|
while(input.size < end + len + 1)
|
||||||
|
input.size <<= 2;
|
||||||
|
if(input.size != size)
|
||||||
|
input.string = erealloc(input.string, input.size);
|
||||||
|
|
||||||
|
input.pos = input.string + pos;
|
||||||
|
input.end = input.string + end + len;
|
||||||
|
*input.end = '\0';
|
||||||
|
memmove(input.pos + len, input.pos, end - pos);
|
||||||
|
memmove(input.pos, s, len);
|
||||||
|
input.pos += len;
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,15 @@
|
||||||
# define EXTERN extern
|
# define EXTERN extern
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FORWARD,
|
||||||
|
BACKWARD,
|
||||||
|
LINE,
|
||||||
|
WORD,
|
||||||
|
CHAR,
|
||||||
|
CARET_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct Item Item;
|
typedef struct Item Item;
|
||||||
|
|
||||||
struct Item {
|
struct Item {
|
||||||
|
@ -27,6 +36,14 @@ struct Item {
|
||||||
int width;
|
int width;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EXTERN struct {
|
||||||
|
char* string;
|
||||||
|
char* end;
|
||||||
|
char* pos;
|
||||||
|
int len;
|
||||||
|
int size;
|
||||||
|
} input;
|
||||||
|
|
||||||
EXTERN long xtime;
|
EXTERN long xtime;
|
||||||
EXTERN Image* ibuf;
|
EXTERN Image* ibuf;
|
||||||
EXTERN Font* font;
|
EXTERN Font* font;
|
||||||
|
@ -46,8 +63,6 @@ EXTERN Item* matchidx;
|
||||||
|
|
||||||
EXTERN Item* histidx;
|
EXTERN Item* histidx;
|
||||||
|
|
||||||
EXTERN char filter[1024];
|
|
||||||
|
|
||||||
EXTERN int maxwidth;
|
EXTERN int maxwidth;
|
||||||
EXTERN int result;
|
EXTERN int result;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
|
|
||||||
|
void caret_delete(int, int);
|
||||||
|
char* caret_find(int, int);
|
||||||
|
void caret_insert(char*, bool);
|
||||||
|
void caret_move(int, int);
|
||||||
void check_x_event(IxpConn*);
|
void check_x_event(IxpConn*);
|
||||||
void debug(int, const char*, ...);
|
void debug(int, const char*, ...);
|
||||||
void dispatch_event(XEvent*);
|
void dispatch_event(XEvent*);
|
||||||
|
|
|
@ -151,7 +151,7 @@ update_filter(void) {
|
||||||
/* TODO: Perhaps filter only previous matches unless filter
|
/* TODO: Perhaps filter only previous matches unless filter
|
||||||
* has been truncated.
|
* has been truncated.
|
||||||
*/
|
*/
|
||||||
matchfirst = matchstart = matchidx = filter_list(items, filter);
|
matchfirst = matchstart = matchidx = filter_list(items, input.string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -264,6 +264,7 @@ main(int argc, char *argv[]) {
|
||||||
|
|
||||||
inbuf = Bfdopen(0, OREAD);
|
inbuf = Bfdopen(0, OREAD);
|
||||||
items = populate_list(inbuf, false);
|
items = populate_list(inbuf, false);
|
||||||
|
caret_insert("", true);
|
||||||
update_filter();
|
update_filter();
|
||||||
|
|
||||||
Bterm(inbuf);
|
Bterm(inbuf);
|
||||||
|
|
108
cmd/menu/menu.c
108
cmd/menu/menu.c
|
@ -12,13 +12,11 @@ static int numlock;
|
||||||
static void menu_draw(void);
|
static void menu_draw(void);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ACCEPT,
|
ACCEPT = CARET_LAST,
|
||||||
REJECT,
|
REJECT,
|
||||||
HIST_NEXT,
|
HIST_NEXT,
|
||||||
HIST_PREV,
|
HIST_PREV,
|
||||||
KILL_CHAR,
|
KILL,
|
||||||
KILL_WORD,
|
|
||||||
KILL_LINE,
|
|
||||||
CMPL_NEXT,
|
CMPL_NEXT,
|
||||||
CMPL_PREV,
|
CMPL_PREV,
|
||||||
CMPL_FIRST,
|
CMPL_FIRST,
|
||||||
|
@ -57,47 +55,29 @@ histtext(Item *i) {
|
||||||
|
|
||||||
if(!histidx->string) {
|
if(!histidx->string) {
|
||||||
free(orig);
|
free(orig);
|
||||||
orig = strdup(filter);
|
orig = strdup(input.string);
|
||||||
}
|
}
|
||||||
return i->string ? i->string : orig;
|
return i->string ? i->string : orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
menu_cmd(int op) {
|
menu_cmd(int op, int motion) {
|
||||||
bool res;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = strlen(filter);
|
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case HIST_NEXT:
|
case HIST_NEXT:
|
||||||
if(histidx->next) {
|
if(histidx->next) {
|
||||||
strncpy(filter, histtext(histidx->next), sizeof filter);
|
caret_insert(histtext(histidx->next), true);
|
||||||
histidx = histidx->next;
|
histidx = histidx->next;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HIST_PREV:
|
case HIST_PREV:
|
||||||
if(histidx->prev) {
|
if(histidx->prev) {
|
||||||
strncpy(filter, histtext(histidx->prev), sizeof filter);
|
caret_insert(histtext(histidx->prev), true);
|
||||||
histidx = histidx->prev;
|
histidx = histidx->prev;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KILL_CHAR:
|
case KILL:
|
||||||
if(i > 0)
|
caret_delete(BACKWARD, motion);
|
||||||
filter[i-1] = '\0';
|
|
||||||
break;
|
|
||||||
case KILL_WORD:
|
|
||||||
if(i == 0)
|
|
||||||
break;
|
|
||||||
for(i--; i >= 0 && isspace(filter[i]); i--)
|
|
||||||
filter[i] = '\0';
|
|
||||||
if(i >= 0)
|
|
||||||
res = !isalnum(filter[i]);
|
|
||||||
for(; i >= 0 && !isalnum(filter[i]) == res && !isspace(filter[i]); i--)
|
|
||||||
filter[i] = '\0';
|
|
||||||
break;
|
|
||||||
case KILL_LINE:
|
|
||||||
/* TODO: Add a caret. */
|
|
||||||
filter[0] = '\0';
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto next;
|
goto next;
|
||||||
|
@ -116,6 +96,10 @@ next:
|
||||||
srv.running = false;
|
srv.running = false;
|
||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
|
case BACKWARD:
|
||||||
|
case FORWARD:
|
||||||
|
caret_move(op, motion);
|
||||||
|
break;
|
||||||
case CMPL_NEXT:
|
case CMPL_NEXT:
|
||||||
matchidx = matchidx->next;
|
matchidx = matchidx->next;
|
||||||
break;
|
break;
|
||||||
|
@ -203,9 +187,9 @@ menu_draw(void) {
|
||||||
drawstring(ibuf, font, r2, East, ">", cnorm.fg);
|
drawstring(ibuf, font, r2, East, ">", cnorm.fg);
|
||||||
r2 = r;
|
r2 = r;
|
||||||
r2.max.x = inputw;
|
r2.max.x = inputw;
|
||||||
drawstring(ibuf, font, r2, West, filter, cnorm.fg);
|
drawstring(ibuf, font, r2, West, input.string, cnorm.fg);
|
||||||
|
|
||||||
r2.min.x = textwidth(font, filter) + pad/2;
|
r2.min.x = textwidth_l(font, input.string, input.pos - input.string) + pad/2;
|
||||||
r2.max.x = r2.min.x + 2;
|
r2.max.x = r2.min.x + 2;
|
||||||
r2.min.y++;
|
r2.min.y++;
|
||||||
r2.max.y--;
|
r2.max.y--;
|
||||||
|
@ -244,7 +228,7 @@ menu_show(void) {
|
||||||
static void
|
static void
|
||||||
kdown_event(Window *w, XKeyEvent *e) {
|
kdown_event(Window *w, XKeyEvent *e) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int num, i;
|
int num;
|
||||||
KeySym ksym;
|
KeySym ksym;
|
||||||
|
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
|
@ -268,37 +252,41 @@ kdown_event(Window *w, XKeyEvent *e) {
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
case XK_bracketleft: /* Esc */
|
case XK_bracketleft: /* Esc */
|
||||||
menu_cmd(REJECT);
|
menu_cmd(REJECT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_j:
|
case XK_j:
|
||||||
case XK_J:
|
case XK_J:
|
||||||
case XK_m:
|
case XK_m:
|
||||||
case XK_M:
|
case XK_M:
|
||||||
menu_cmd(ACCEPT);
|
menu_cmd(ACCEPT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_n:
|
case XK_n:
|
||||||
case XK_N:
|
case XK_N:
|
||||||
menu_cmd(HIST_NEXT);
|
menu_cmd(HIST_NEXT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_p:
|
case XK_p:
|
||||||
case XK_P:
|
case XK_P:
|
||||||
menu_cmd(HIST_PREV);
|
menu_cmd(HIST_PREV, 0);
|
||||||
return;
|
return;
|
||||||
case XK_i: /* Tab */
|
case XK_i: /* Tab */
|
||||||
case XK_I:
|
case XK_I:
|
||||||
menu_cmd(CMPL_NEXT);
|
if(e->state & ShiftMask)
|
||||||
|
menu_cmd(CMPL_PREV, 0);
|
||||||
|
else
|
||||||
|
menu_cmd(CMPL_NEXT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_h:
|
case XK_h:
|
||||||
case XK_H:
|
case XK_H:
|
||||||
menu_cmd(KILL_CHAR);
|
menu_cmd(KILL, CHAR);
|
||||||
return;
|
return;
|
||||||
|
case XK_BackSpace:
|
||||||
case XK_w:
|
case XK_w:
|
||||||
case XK_W:
|
case XK_W:
|
||||||
menu_cmd(KILL_WORD);
|
menu_cmd(KILL, WORD);
|
||||||
return;
|
return;
|
||||||
case XK_u:
|
case XK_u:
|
||||||
case XK_U:
|
case XK_U:
|
||||||
menu_cmd(KILL_LINE);
|
menu_cmd(KILL, LINE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,74 +296,70 @@ kdown_event(Window *w, XKeyEvent *e) {
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
case XK_h:
|
case XK_h:
|
||||||
menu_cmd(CMPL_PREV);
|
menu_cmd(CMPL_PREV, 0);
|
||||||
return;
|
return;
|
||||||
case XK_l:
|
case XK_l:
|
||||||
menu_cmd(CMPL_NEXT);
|
menu_cmd(CMPL_NEXT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_j:
|
case XK_j:
|
||||||
menu_cmd(CMPL_NEXT_PAGE);
|
menu_cmd(CMPL_NEXT_PAGE, 0);
|
||||||
return;
|
return;
|
||||||
case XK_k:
|
case XK_k:
|
||||||
menu_cmd(CMPL_PREV_PAGE);
|
menu_cmd(CMPL_PREV_PAGE, 0);
|
||||||
return;
|
return;
|
||||||
case XK_g:
|
case XK_g:
|
||||||
menu_cmd(CMPL_FIRST);
|
menu_cmd(CMPL_FIRST, 0);
|
||||||
return;
|
return;
|
||||||
case XK_G:
|
case XK_G:
|
||||||
menu_cmd(CMPL_LAST);
|
menu_cmd(CMPL_LAST, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch(ksym) {
|
switch(ksym) {
|
||||||
default:
|
default:
|
||||||
if(num && !iscntrl(buf[0])) {
|
if(num && !iscntrl(buf[0])) {
|
||||||
i = strlen(filter);
|
caret_insert(buf, false);
|
||||||
if(i < sizeof filter - 1) {
|
|
||||||
filter[i] = buf[0];
|
|
||||||
filter[i+1] = '\0';
|
|
||||||
}
|
|
||||||
update_filter();
|
update_filter();
|
||||||
menu_draw();
|
menu_draw();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XK_Escape:
|
case XK_Escape:
|
||||||
menu_cmd(REJECT);
|
menu_cmd(REJECT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_Return:
|
case XK_Return:
|
||||||
menu_cmd(ACCEPT);
|
menu_cmd(ACCEPT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_BackSpace:
|
case XK_BackSpace:
|
||||||
menu_cmd(KILL_CHAR);
|
menu_cmd(KILL, CHAR);
|
||||||
return;
|
return;
|
||||||
case XK_Up:
|
case XK_Up:
|
||||||
menu_cmd(HIST_PREV);
|
menu_cmd(HIST_PREV, 0);
|
||||||
return;
|
return;
|
||||||
case XK_Down:
|
case XK_Down:
|
||||||
menu_cmd(HIST_NEXT);
|
menu_cmd(HIST_NEXT, 0);
|
||||||
return;
|
return;
|
||||||
case XK_Home:
|
case XK_Home:
|
||||||
/* TODO: Caret. */
|
/* TODO: Caret. */
|
||||||
menu_cmd(CMPL_FIRST);
|
menu_cmd(CMPL_FIRST, 0);
|
||||||
return;
|
return;
|
||||||
case XK_End:
|
case XK_End:
|
||||||
/* TODO: Caret. */
|
/* TODO: Caret. */
|
||||||
menu_cmd(CMPL_LAST);
|
menu_cmd(CMPL_LAST, 0);
|
||||||
return;
|
return;
|
||||||
case XK_Left:
|
case XK_Left:
|
||||||
menu_cmd(CMPL_PREV);
|
menu_cmd(BACKWARD, CHAR);
|
||||||
return;
|
return;
|
||||||
case XK_Right:
|
case XK_Right:
|
||||||
menu_cmd(CMPL_NEXT);
|
menu_cmd(FORWARD, CHAR);
|
||||||
return;
|
return;
|
||||||
case XK_Next:
|
case XK_Next:
|
||||||
menu_cmd(CMPL_NEXT_PAGE);
|
menu_cmd(CMPL_NEXT_PAGE, 0);
|
||||||
return;
|
return;
|
||||||
case XK_Prior:
|
case XK_Prior:
|
||||||
menu_cmd(CMPL_PREV_PAGE);
|
menu_cmd(CMPL_PREV_PAGE, 0);
|
||||||
return;
|
return;
|
||||||
case XK_Tab:
|
case XK_Tab:
|
||||||
menu_cmd(CMPL_NEXT);
|
menu_cmd(CMPL_NEXT, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue