[hackers] [wmii] [menu] Add proper caret support || Kris Maglione

From: <hg_AT_suckless.org>
Date: Tue, 14 Oct 2008 20:57:52 +0000 (UTC)

changeset: 2365:812e1c20dddf
tag: tip
user: Kris Maglione <jg_AT_suckless.org>
date: Tue Oct 14 16:57:48 2008 -0400
files: cmd/menu/Makefile cmd/menu/caret.c cmd/menu/dat.h cmd/menu/fns.h cmd/menu/main.c cmd/menu/menu.c
description:
[menu] Add proper caret support

diff -r 23284ce3261e -r 812e1c20dddf cmd/menu/Makefile
--- a/cmd/menu/Makefile Tue Oct 14 04:54:35 2008 -0400
+++ b/cmd/menu/Makefile Tue Oct 14 16:57:48 2008 -0400
@@ -13,6 +13,7 @@
 CFLAGS += $(INCX11) -DVERSION=\"$(VERSION)\" \
           -DIXP_NEEDAPI=86
 OBJ = main \
+ caret \
         event \
         menu \
         ../wmii/geom \
diff -r 23284ce3261e -r 812e1c20dddf cmd/menu/caret.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/menu/caret.c Tue Oct 14 16:57:48 2008 -0400
@@ -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;
+}
+
diff -r 23284ce3261e -r 812e1c20dddf cmd/menu/dat.h
--- a/cmd/menu/dat.h Tue Oct 14 04:54:35 2008 -0400
+++ b/cmd/menu/dat.h Tue Oct 14 16:57:48 2008 -0400
@@ -15,6 +15,15 @@
 # define EXTERN extern
 #endif
 
+enum {
+ FORWARD,
+ BACKWARD,
+ LINE,
+ WORD,
+ CHAR,
+ CARET_LAST,
+};
+
 typedef struct Item Item;
 
 struct Item {
@@ -26,6 +35,14 @@
         int len;
         int width;
 };
+
+EXTERN struct {
+ char* string;
+ char* end;
+ char* pos;
+ int len;
+ int size;
+} input;
 
 EXTERN long xtime;
 EXTERN Image* ibuf;
@@ -46,8 +63,6 @@
 
 EXTERN Item* histidx;
 
-EXTERN char filter[1024];
-
 EXTERN int maxwidth;
 EXTERN int result;
 
diff -r 23284ce3261e -r 812e1c20dddf cmd/menu/fns.h
--- a/cmd/menu/fns.h Tue Oct 14 04:54:35 2008 -0400
+++ b/cmd/menu/fns.h Tue Oct 14 16:57:48 2008 -0400
@@ -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 debug(int, const char*, ...);
 void dispatch_event(XEvent*);
diff -r 23284ce3261e -r 812e1c20dddf cmd/menu/main.c
--- a/cmd/menu/main.c Tue Oct 14 04:54:35 2008 -0400
+++ b/cmd/menu/main.c Tue Oct 14 16:57:48 2008 -0400
@@ -151,7 +151,7 @@
         /* TODO: Perhaps filter only previous matches unless filter
          * has been truncated.
          */
- matchfirst = matchstart = matchidx = filter_list(items, filter);
+ matchfirst = matchstart = matchidx = filter_list(items, input.string);
 }
 
 /*
@@ -264,6 +264,7 @@
 
         inbuf = Bfdopen(0, OREAD);
         items = populate_list(inbuf, false);
+ caret_insert("", true);
         update_filter();
 
         Bterm(inbuf);
diff -r 23284ce3261e -r 812e1c20dddf cmd/menu/menu.c
--- a/cmd/menu/menu.c Tue Oct 14 04:54:35 2008 -0400
+++ b/cmd/menu/menu.c Tue Oct 14 16:57:48 2008 -0400
@@ -12,13 +12,11 @@
 static void menu_draw(void);
 
 enum {
- ACCEPT,
+ ACCEPT = CARET_LAST,
         REJECT,
         HIST_NEXT,
         HIST_PREV,
- KILL_CHAR,
- KILL_WORD,
- KILL_LINE,
+ KILL,
         CMPL_NEXT,
         CMPL_PREV,
         CMPL_FIRST,
@@ -57,47 +55,29 @@
 
         if(!histidx->string) {
                 free(orig);
- orig = strdup(filter);
+ orig = strdup(input.string);
         }
         return i->string ? i->string : orig;
 }
 
 static void
-menu_cmd(int op) {
- bool res;
- int i;
+menu_cmd(int op, int motion) {
 
- i = strlen(filter);
         switch(op) {
         case HIST_NEXT:
                 if(histidx->next) {
- strncpy(filter, histtext(histidx->next), sizeof filter);
+ caret_insert(histtext(histidx->next), true);
                         histidx = histidx->next;
                 }
                 break;
         case HIST_PREV:
                 if(histidx->prev) {
- strncpy(filter, histtext(histidx->prev), sizeof filter);
+ caret_insert(histtext(histidx->prev), true);
                         histidx = histidx->prev;
                 }
                 break;
- case KILL_CHAR:
- if(i > 0)
- 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';
+ case KILL:
+ caret_delete(BACKWARD, motion);
                 break;
         default:
                 goto next;
@@ -115,6 +95,10 @@
         case REJECT:
                 srv.running = false;
                 result = 1;
+ break;
+ case BACKWARD:
+ case FORWARD:
+ caret_move(op, motion);
                 break;
         case CMPL_NEXT:
                 matchidx = matchidx->next;
@@ -203,9 +187,9 @@
                 drawstring(ibuf, font, r2, East, ">", cnorm.fg);
         r2 = r;
         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.min.y++;
         r2.max.y--;
@@ -244,7 +228,7 @@
 static void
 kdown_event(Window *w, XKeyEvent *e) {
         char buf[32];
- int num, i;
+ int num;
         KeySym ksym;
 
         buf[0] = 0;
@@ -268,37 +252,41 @@
                 default:
                         return;
                 case XK_bracketleft: /* Esc */
- menu_cmd(REJECT);
+ menu_cmd(REJECT, 0);
                         return;
                 case XK_j:
                 case XK_J:
                 case XK_m:
                 case XK_M:
- menu_cmd(ACCEPT);
+ menu_cmd(ACCEPT, 0);
                         return;
                 case XK_n:
                 case XK_N:
- menu_cmd(HIST_NEXT);
+ menu_cmd(HIST_NEXT, 0);
                         return;
                 case XK_p:
                 case XK_P:
- menu_cmd(HIST_PREV);
+ menu_cmd(HIST_PREV, 0);
                         return;
                 case XK_i: /* Tab */
                 case XK_I:
- menu_cmd(CMPL_NEXT);
+ if(e->state & ShiftMask)
+ menu_cmd(CMPL_PREV, 0);
+ else
+ menu_cmd(CMPL_NEXT, 0);
                         return;
                 case XK_h:
                 case XK_H:
- menu_cmd(KILL_CHAR);
+ menu_cmd(KILL, CHAR);
                         return;
+ case XK_BackSpace:
                 case XK_w:
                 case XK_W:
- menu_cmd(KILL_WORD);
+ menu_cmd(KILL, WORD);
                         return;
                 case XK_u:
                 case XK_U:
- menu_cmd(KILL_LINE);
+ menu_cmd(KILL, LINE);
                         return;
                 }
         }
@@ -308,74 +296,70 @@
                 default:
                         return;
                 case XK_h:
- menu_cmd(CMPL_PREV);
+ menu_cmd(CMPL_PREV, 0);
                         return;
                 case XK_l:
- menu_cmd(CMPL_NEXT);
+ menu_cmd(CMPL_NEXT, 0);
                         return;
                 case XK_j:
- menu_cmd(CMPL_NEXT_PAGE);
+ menu_cmd(CMPL_NEXT_PAGE, 0);
                         return;
                 case XK_k:
- menu_cmd(CMPL_PREV_PAGE);
+ menu_cmd(CMPL_PREV_PAGE, 0);
                         return;
                 case XK_g:
- menu_cmd(CMPL_FIRST);
+ menu_cmd(CMPL_FIRST, 0);
                         return;
                 case XK_G:
- menu_cmd(CMPL_LAST);
+ menu_cmd(CMPL_LAST, 0);
                         return;
                 }
         }
         switch(ksym) {
         default:
                 if(num && !iscntrl(buf[0])) {
- i = strlen(filter);
- if(i < sizeof filter - 1) {
- filter[i] = buf[0];
- filter[i+1] = '\0';
- }
+ caret_insert(buf, false);
                         update_filter();
                         menu_draw();
                 }
                 break;
         case XK_Escape:
- menu_cmd(REJECT);
+ menu_cmd(REJECT, 0);
                 return;
         case XK_Return:
- menu_cmd(ACCEPT);
+ menu_cmd(ACCEPT, 0);
                 return;
         case XK_BackSpace:
- menu_cmd(KILL_CHAR);
+ menu_cmd(KILL, CHAR);
                 return;
         case XK_Up:
- menu_cmd(HIST_PREV);
+ menu_cmd(HIST_PREV, 0);
                 return;
         case XK_Down:
- menu_cmd(HIST_NEXT);
+ menu_cmd(HIST_NEXT, 0);
                 return;
         case XK_Home:
                 /* TODO: Caret. */
- menu_cmd(CMPL_FIRST);
+ menu_cmd(CMPL_FIRST, 0);
                 return;
         case XK_End:
                 /* TODO: Caret. */
- menu_cmd(CMPL_LAST);
+ menu_cmd(CMPL_LAST, 0);
                 return;
         case XK_Left:
- menu_cmd(CMPL_PREV);
+ menu_cmd(BACKWARD, CHAR);
                 return;
         case XK_Right:
- menu_cmd(CMPL_NEXT);
+ menu_cmd(FORWARD, CHAR);
                 return;
         case XK_Next:
- menu_cmd(CMPL_NEXT_PAGE);
+ menu_cmd(CMPL_NEXT_PAGE, 0);
                 return;
         case XK_Prior:
- menu_cmd(CMPL_PREV_PAGE);
+ menu_cmd(CMPL_PREV_PAGE, 0);
                 return;
         case XK_Tab:
- menu_cmd(CMPL_NEXT);
+ menu_cmd(CMPL_NEXT, 0);
                 return;
         }
 }
Received on Tue Oct 14 2008 - 20:57:52 UTC

This archive was generated by hypermail 2.2.0 : Tue Oct 14 2008 - 21:00:09 UTC