st-keyboard_select-20200617-9ba7ecf.diff (8543B)
1 diff --git a/config.def.h b/config.def.h 2 index 6f05dce..54612d1 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -199,6 +199,7 @@ static Shortcut shortcuts[] = { 6 { TERMMOD, XK_Y, selpaste, {.i = 0} }, 7 { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 8 { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 9 + { TERMMOD, XK_Escape, keyboard_select,{.i = 0} }, 10 }; 11 12 /* 13 diff --git a/st.c b/st.c 14 index ef8abd5..0c6c6ca 100644 15 --- a/st.c 16 +++ b/st.c 17 @@ -16,6 +16,8 @@ 18 #include <termios.h> 19 #include <unistd.h> 20 #include <wchar.h> 21 +#include <X11/keysym.h> 22 +#include <X11/X.h> 23 24 #include "st.h" 25 #include "win.h" 26 @@ -2487,6 +2489,9 @@ tresize(int col, int row) 27 int *bp; 28 TCursor c; 29 30 + if ( row < term.row || col < term.col ) 31 + toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0)); 32 + 33 if (col < 1 || row < 1) { 34 fprintf(stderr, 35 "tresize: error resizing to %dx%d\n", col, row); 36 @@ -2612,3 +2617,220 @@ redraw(void) 37 tfulldirt(); 38 draw(); 39 } 40 + 41 +void set_notifmode(int type, KeySym ksym) { 42 + static char *lib[] = { " MOVE ", " SEL "}; 43 + static Glyph *g, *deb, *fin; 44 + static int col, bot; 45 + 46 + if ( ksym == -1 ) { 47 + free(g); 48 + col = term.col, bot = term.bot; 49 + g = xmalloc(col * sizeof(Glyph)); 50 + memcpy(g, term.line[bot], col * sizeof(Glyph)); 51 + 52 + } 53 + else if ( ksym == -2 ) 54 + memcpy(term.line[bot], g, col * sizeof(Glyph)); 55 + 56 + if ( type < 2 ) { 57 + char *z = lib[type]; 58 + for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++) 59 + deb->mode = ATTR_REVERSE, 60 + deb->u = *z, 61 + deb->fg = defaultfg, deb->bg = defaultbg; 62 + } 63 + else if ( type < 5 ) 64 + memcpy(term.line[bot], g, col * sizeof(Glyph)); 65 + else { 66 + for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++) 67 + deb->mode = ATTR_REVERSE, 68 + deb->u = ' ', 69 + deb->fg = defaultfg, deb->bg = defaultbg; 70 + term.line[bot][0].u = ksym; 71 + } 72 + 73 + term.dirty[bot] = 1; 74 + drawregion(0, bot, col, bot + 1); 75 +} 76 + 77 +void select_or_drawcursor(int selectsearch_mode, int type) { 78 + int done = 0; 79 + 80 + if ( selectsearch_mode & 1 ) { 81 + selextend(term.c.x, term.c.y, type, done); 82 + xsetsel(getsel()); 83 + } 84 + else 85 + xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x], 86 + term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 87 +} 88 + 89 +void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) { 90 + Rune *r; 91 + int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr; 92 + 93 + for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) { 94 + for (r = target; r - target < ptarget; r++) { 95 + if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) { 96 + if ( r - target == ptarget - 1 ) break; 97 + } else { 98 + r = NULL; 99 + break; 100 + } 101 + } 102 + if ( r != NULL ) break; 103 + } 104 + 105 + if ( i != bound ) { 106 + term.c.y = i / term.col, term.c.x = i % term.col; 107 + select_or_drawcursor(selectsearch_mode, type); 108 + } 109 +} 110 + 111 +int trt_kbdselect(KeySym ksym, char *buf, int len) { 112 + static TCursor cu; 113 + static Rune target[64]; 114 + static int type = 1, ptarget, in_use; 115 + static int sens, quant; 116 + static char selectsearch_mode; 117 + int i, bound, *xy; 118 + 119 + 120 + if ( selectsearch_mode & 2 ) { 121 + if ( ksym == XK_Return ) { 122 + selectsearch_mode ^= 2; 123 + set_notifmode(selectsearch_mode, -2); 124 + if ( ksym == XK_Escape ) ptarget = 0; 125 + return 0; 126 + } 127 + else if ( ksym == XK_BackSpace ) { 128 + if ( !ptarget ) return 0; 129 + term.line[term.bot][ptarget--].u = ' '; 130 + } 131 + else if ( len < 1 ) { 132 + return 0; 133 + } 134 + else if ( ptarget == term.col || ksym == XK_Escape ) { 135 + return 0; 136 + } 137 + else { 138 + utf8decode(buf, &target[ptarget++], len); 139 + term.line[term.bot][ptarget].u = target[ptarget - 1]; 140 + } 141 + 142 + if ( ksym != XK_BackSpace ) 143 + search(selectsearch_mode, &target[0], ptarget, sens, type, &cu); 144 + 145 + term.dirty[term.bot] = 1; 146 + drawregion(0, term.bot, term.col, term.bot + 1); 147 + return 0; 148 + } 149 + 150 + switch ( ksym ) { 151 + case -1 : 152 + in_use = 1; 153 + cu.x = term.c.x, cu.y = term.c.y; 154 + set_notifmode(0, ksym); 155 + return MODE_KBDSELECT; 156 + case XK_s : 157 + if ( selectsearch_mode & 1 ) 158 + selclear(); 159 + else 160 + selstart(term.c.x, term.c.y, 0); 161 + set_notifmode(selectsearch_mode ^= 1, ksym); 162 + break; 163 + case XK_t : 164 + selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */ 165 + selextend(term.c.x, term.c.y, type, i = 0); 166 + break; 167 + case XK_slash : 168 + case XK_KP_Divide : 169 + case XK_question : 170 + ksym &= XK_question; /* Divide to slash */ 171 + sens = (ksym == XK_slash) ? -1 : 1; 172 + ptarget = 0; 173 + set_notifmode(15, ksym); 174 + selectsearch_mode ^= 2; 175 + break; 176 + case XK_Escape : 177 + if ( !in_use ) break; 178 + selclear(); 179 + case XK_Return : 180 + set_notifmode(4, ksym); 181 + term.c.x = cu.x, term.c.y = cu.y; 182 + select_or_drawcursor(selectsearch_mode = 0, type); 183 + in_use = quant = 0; 184 + return MODE_KBDSELECT; 185 + case XK_n : 186 + case XK_N : 187 + if ( ptarget ) 188 + search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu); 189 + break; 190 + case XK_BackSpace : 191 + term.c.x = 0; 192 + select_or_drawcursor(selectsearch_mode, type); 193 + break; 194 + case XK_dollar : 195 + term.c.x = term.col - 1; 196 + select_or_drawcursor(selectsearch_mode, type); 197 + break; 198 + case XK_Home : 199 + term.c.x = 0, term.c.y = 0; 200 + select_or_drawcursor(selectsearch_mode, type); 201 + break; 202 + case XK_End : 203 + term.c.x = cu.x, term.c.y = cu.y; 204 + select_or_drawcursor(selectsearch_mode, type); 205 + break; 206 + case XK_Page_Up : 207 + case XK_Page_Down : 208 + term.c.y = (ksym == XK_Prior ) ? 0 : cu.y; 209 + select_or_drawcursor(selectsearch_mode, type); 210 + break; 211 + case XK_exclam : 212 + term.c.x = term.col >> 1; 213 + select_or_drawcursor(selectsearch_mode, type); 214 + break; 215 + case XK_asterisk : 216 + case XK_KP_Multiply : 217 + term.c.x = term.col >> 1; 218 + case XK_underscore : 219 + term.c.y = cu.y >> 1; 220 + select_or_drawcursor(selectsearch_mode, type); 221 + break; 222 + default : 223 + if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */ 224 + quant = (quant * 10) + (ksym ^ XK_0); 225 + return 0; 226 + } 227 + else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */ 228 + quant = (quant * 10) + (ksym ^ XK_KP_0); 229 + return 0; 230 + } 231 + else if ( ksym == XK_k || ksym == XK_h ) 232 + i = ksym & 1; 233 + else if ( ksym == XK_l || ksym == XK_j ) 234 + i = ((ksym & 6) | 4) >> 1; 235 + else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 ) 236 + break; 237 + 238 + xy = (i & 1) ? &term.c.y : &term.c.x; 239 + sens = (i & 2) ? 1 : -1; 240 + bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot; 241 + 242 + if ( quant == 0 ) 243 + quant++; 244 + 245 + if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) ) 246 + break; 247 + 248 + *xy += quant * sens; 249 + if ( *xy < 0 || ( bound > 0 && *xy > bound) ) 250 + *xy = bound; 251 + 252 + select_or_drawcursor(selectsearch_mode, type); 253 + } 254 + quant = 0; 255 + return 0; 256 +} 257 diff --git a/st.h b/st.h 258 index 3d351b6..2d1a11b 100644 259 --- a/st.h 260 +++ b/st.h 261 @@ -110,6 +110,7 @@ size_t utf8encode(Rune, char *); 262 void *xmalloc(size_t); 263 void *xrealloc(void *, size_t); 264 char *xstrdup(char *); 265 +int trt_kbdselect(KeySym, char *, int); 266 267 /* config.h globals */ 268 extern char *utmp; 269 diff --git a/win.h b/win.h 270 index a6ef1b9..9a47fbb 100644 271 --- a/win.h 272 +++ b/win.h 273 @@ -21,6 +21,7 @@ enum win_mode { 274 MODE_NUMLOCK = 1 << 17, 275 MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ 276 |MODE_MOUSEMANY, 277 + MODE_KBDSELECT = 1 << 18, 278 }; 279 280 void xbell(void); 281 @@ -36,4 +37,6 @@ void xsetmode(int, unsigned int); 282 void xsetpointermotion(int); 283 void xsetsel(char *); 284 int xstartdraw(void); 285 +void toggle_winmode(int); 286 +void keyboard_select(const Arg *); 287 void xximspot(int, int); 288 diff --git a/x.c b/x.c 289 index 210f184..b77ce54 100644 290 --- a/x.c 291 +++ b/x.c 292 @@ -1800,6 +1800,12 @@ kpress(XEvent *ev) 293 len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); 294 else 295 len = XLookupString(e, buf, sizeof buf, &ksym, NULL); 296 + if ( IS_SET(MODE_KBDSELECT) ) { 297 + if ( match(XK_NO_MOD, e->state) || 298 + (XK_Shift_L | XK_Shift_R) & e->state ) 299 + win.mode ^= trt_kbdselect(ksym, buf, len); 300 + return; 301 + } 302 /* 1. shortcuts */ 303 for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { 304 if (ksym == bp->keysym && match(bp->mod, e->state)) { 305 @@ -1977,6 +1983,14 @@ usage(void) 306 " [stty_args ...]\n", argv0, argv0); 307 } 308 309 +void toggle_winmode(int flag) { 310 + win.mode ^= flag; 311 +} 312 + 313 +void keyboard_select(const Arg *dummy) { 314 + win.mode ^= trt_kbdselect(-1, NULL, 0); 315 +} 316 + 317 int 318 main(int argc, char *argv[]) 319 {