keyboardselect_reflow_st.c (18521B)
1 #include <wctype.h> 2 3 enum keyboardselect_mode { 4 KBDS_MODE_MOVE = 0, 5 KBDS_MODE_SELECT = 1<<1, 6 KBDS_MODE_LSELECT = 1<<2, 7 KBDS_MODE_FIND = 1<<3, 8 KBDS_MODE_SEARCH = 1<<4, 9 }; 10 11 enum cursor_wrap { 12 KBDS_WRAP_NONE = 0, 13 KBDS_WRAP_LINE = 1<<0, 14 KBDS_WRAP_EDGE = 1<<1, 15 }; 16 17 typedef struct { 18 int x; 19 int y; 20 Line line; 21 int len; 22 } KCursor; 23 24 static int kbds_in_use, kbds_quant; 25 static int kbds_seltype = SEL_REGULAR; 26 static int kbds_mode, kbds_directsearch; 27 static int kbds_searchlen, kbds_searchdir, kbds_searchcase; 28 static int kbds_finddir, kbds_findtill; 29 static Glyph *kbds_searchstr; 30 static Rune kbds_findchar; 31 static KCursor kbds_c, kbds_oc; 32 33 void 34 kbds_drawstatusbar(int y) 35 { 36 static char *modes[] = { " MOVE ", "", " SELECT ", " RSELECT ", " LSELECT ", 37 " SEARCH FW ", " SEARCH BW ", " FIND FW ", " FIND BW " }; 38 static char quant[20] = { ' ' }; 39 static Glyph g; 40 int i, n, m; 41 int mlen, qlen; 42 43 if (!kbds_in_use) 44 return; 45 46 g.mode = ATTR_REVERSE; 47 g.fg = defaultfg; 48 g.bg = defaultbg; 49 50 if (y == 0) { 51 if (kbds_issearchmode()) 52 m = 5 + (kbds_searchdir < 0 ? 1 : 0); 53 else if (kbds_mode & KBDS_MODE_FIND) 54 m = 7 + (kbds_finddir < 0 ? 1 : 0); 55 else if (kbds_mode & KBDS_MODE_SELECT) 56 m = 2 + (kbds_seltype == SEL_RECTANGULAR ? 1 : 0); 57 else 58 m = kbds_mode; 59 mlen = strlen(modes[m]); 60 qlen = kbds_quant ? snprintf(quant+1, sizeof quant-1, "%i", kbds_quant) + 1 : 0; 61 if (kbds_c.y != y || kbds_c.x < term.col - qlen - mlen) { 62 for (n = mlen, i = term.col-1; i >= 0 && n > 0; i--) { 63 g.u = modes[m][--n]; 64 xdrawglyph(g, i, y); 65 } 66 for (n = qlen; i >= 0 && n > 0; i--) { 67 g.u = quant[--n]; 68 xdrawglyph(g, i, y); 69 } 70 } 71 } 72 73 if (y == term.row-1 && kbds_issearchmode()) { 74 for (g.u = ' ', i = 0; i < term.col; i++) 75 xdrawglyph(g, i, y); 76 g.u = (kbds_searchdir > 0) ? '/' : '?'; 77 xdrawglyph(g, 0, y); 78 for (i = 0; i < kbds_searchlen; i++) { 79 g.u = kbds_searchstr[i].u; 80 g.mode = kbds_searchstr[i].mode | ATTR_WIDE | ATTR_REVERSE; 81 if (g.u == ' ' || g.mode & ATTR_WDUMMY) 82 continue; 83 xdrawglyph(g, i + 1, y); 84 } 85 g.u = ' '; 86 g.mode = ATTR_NULL; 87 xdrawglyph(g, i + 1, y); 88 } 89 } 90 91 void 92 kbds_pasteintosearch(const char *data, int len, int append) 93 { 94 static char buf[BUFSIZ]; 95 static int buflen; 96 Rune u; 97 int l, n, charsize; 98 99 if (!append) 100 buflen = 0; 101 102 for (; len > 0; len -= l, data += l) { 103 l = MIN(sizeof(buf) - buflen, len); 104 memmove(buf + buflen, data, l); 105 buflen += l; 106 for (n = 0; n < buflen; n += charsize) { 107 if (IS_SET(MODE_UTF8)) { 108 /* process a complete utf8 char */ 109 charsize = utf8decode(buf + n, &u, buflen - n); 110 if (charsize == 0) 111 break; 112 } else { 113 u = buf[n] & 0xFF; 114 charsize = 1; 115 } 116 if (u > 0x1f && kbds_searchlen < term.col-2) { 117 kbds_searchstr[kbds_searchlen].u = u; 118 kbds_searchstr[kbds_searchlen++].mode = ATTR_NULL; 119 if (wcwidth(u) > 1) { 120 kbds_searchstr[kbds_searchlen-1].mode = ATTR_WIDE; 121 if (kbds_searchlen < term.col-2) { 122 kbds_searchstr[kbds_searchlen].u = 0; 123 kbds_searchstr[kbds_searchlen++].mode = ATTR_WDUMMY; 124 } 125 } 126 } 127 } 128 buflen -= n; 129 /* keep any incomplete UTF-8 byte sequence for the next call */ 130 if (buflen > 0) 131 memmove(buf, buf + n, buflen); 132 } 133 term.dirty[term.row-1] = 1; 134 } 135 136 int 137 kbds_top(void) 138 { 139 return IS_SET(MODE_ALTSCREEN) ? 0 : -term.histf + term.scr; 140 } 141 142 int 143 kbds_bot(void) 144 { 145 return IS_SET(MODE_ALTSCREEN) ? term.row-1 : term.row-1 + term.scr; 146 } 147 148 int 149 kbds_iswrapped(KCursor *c) 150 { 151 return c->len > 0 && (c->line[c->len-1].mode & ATTR_WRAP); 152 } 153 154 int 155 kbds_isselectmode(void) 156 { 157 return kbds_in_use && (kbds_mode & (KBDS_MODE_SELECT | KBDS_MODE_LSELECT)); 158 } 159 160 int 161 kbds_issearchmode(void) 162 { 163 return kbds_in_use && (kbds_mode & KBDS_MODE_SEARCH); 164 } 165 166 void 167 kbds_setmode(int mode) 168 { 169 kbds_mode = mode; 170 term.dirty[0] = 1; 171 } 172 173 void 174 kbds_selecttext(void) 175 { 176 if (kbds_isselectmode()) { 177 if (kbds_mode & KBDS_MODE_LSELECT) 178 selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0); 179 else 180 selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0); 181 if (sel.mode == SEL_IDLE) 182 kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT)); 183 } 184 } 185 186 void 187 kbds_copytoclipboard(void) 188 { 189 if (kbds_mode & KBDS_MODE_LSELECT) { 190 selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 1); 191 sel.type = SEL_REGULAR; 192 } else { 193 selextend(kbds_c.x, kbds_c.y, kbds_seltype, 1); 194 } 195 xsetsel(getsel()); 196 197 #if !CLIPBOARD_PATCH 198 xclipcopy(); 199 #endif // CLIPBOARD_PATCH 200 } 201 202 void 203 kbds_clearhighlights(void) 204 { 205 int x, y; 206 Line line; 207 208 for (y = (IS_SET(MODE_ALTSCREEN) ? 0 : -term.histf); y < term.row; y++) { 209 line = TLINEABS(y); 210 for (x = 0; x < term.col; x++) 211 line[x].mode &= ~ATTR_HIGHLIGHT; 212 } 213 tfulldirt(); 214 } 215 216 int 217 kbds_moveto(int x, int y) 218 { 219 if (y < 0) 220 kscrollup(&((Arg){ .i = -y })); 221 else if (y >= term.row) 222 kscrolldown(&((Arg){ .i = y - term.row + 1 })); 223 kbds_c.x = (x < 0) ? 0 : (x > term.col-1) ? term.col-1 : x; 224 kbds_c.y = (y < 0) ? 0 : (y > term.row-1) ? term.row-1 : y; 225 kbds_c.line = TLINE(kbds_c.y); 226 kbds_c.len = tlinelen(kbds_c.line); 227 if (kbds_c.x > 0 && (kbds_c.line[kbds_c.x].mode & ATTR_WDUMMY)) 228 kbds_c.x--; 229 } 230 231 int 232 kbds_moveforward(KCursor *c, int dx, int wrap) 233 { 234 KCursor n = *c; 235 236 n.x += dx; 237 if (n.x >= 0 && n.x < term.col && (n.line[n.x].mode & ATTR_WDUMMY)) 238 n.x += dx; 239 240 if (n.x < 0) { 241 if (!wrap || --n.y < kbds_top()) 242 return 0; 243 n.line = TLINE(n.y); 244 n.len = tlinelen(n.line); 245 if ((wrap & KBDS_WRAP_LINE) && kbds_iswrapped(&n)) 246 n.x = n.len-1; 247 else if (wrap & KBDS_WRAP_EDGE) 248 n.x = term.col-1; 249 else 250 return 0; 251 n.x -= (n.x > 0 && (n.line[n.x].mode & ATTR_WDUMMY)) ? 1 : 0; 252 } else if (n.x >= term.col) { 253 if (((wrap & KBDS_WRAP_EDGE) || 254 ((wrap & KBDS_WRAP_LINE) && kbds_iswrapped(&n))) && ++n.y <= kbds_bot()) { 255 n.line = TLINE(n.y); 256 n.len = tlinelen(n.line); 257 n.x = 0; 258 } else { 259 return 0; 260 } 261 } else if (n.x >= n.len && dx > 0 && (wrap & KBDS_WRAP_LINE)) { 262 if (n.x == n.len && kbds_iswrapped(&n) && n.y < kbds_bot()) { 263 ++n.y; 264 n.line = TLINE(n.y); 265 n.len = tlinelen(n.line); 266 n.x = 0; 267 } else if (!(wrap & KBDS_WRAP_EDGE)) { 268 return 0; 269 } 270 } 271 *c = n; 272 return 1; 273 } 274 275 int 276 kbds_ismatch(KCursor c) 277 { 278 KCursor m = c; 279 int i, next; 280 281 if (c.x + kbds_searchlen > c.len && (!kbds_iswrapped(&c) || c.y >= kbds_bot())) 282 return 0; 283 284 for (next = 0, i = 0; i < kbds_searchlen; i++) { 285 if (kbds_searchstr[i].mode & ATTR_WDUMMY) 286 continue; 287 if ((next++ && !kbds_moveforward(&c, 1, KBDS_WRAP_LINE)) || 288 (kbds_searchcase && kbds_searchstr[i].u != c.line[c.x].u) || 289 (!kbds_searchcase && kbds_searchstr[i].u != towlower(c.line[c.x].u))) 290 return 0; 291 } 292 293 for (i = 0; i < kbds_searchlen; i++) { 294 if (!(kbds_searchstr[i].mode & ATTR_WDUMMY)) { 295 m.line[m.x].mode |= ATTR_HIGHLIGHT; 296 kbds_moveforward(&m, 1, KBDS_WRAP_LINE); 297 } 298 } 299 return 1; 300 } 301 302 int 303 kbds_searchall(void) 304 { 305 KCursor c; 306 int count = 0; 307 308 if (!kbds_searchlen) 309 return 0; 310 311 for (c.y = kbds_top(); c.y <= kbds_bot(); c.y++) { 312 c.line = TLINE(c.y); 313 c.len = tlinelen(c.line); 314 for (c.x = 0; c.x < c.len; c.x++) 315 count += kbds_ismatch(c); 316 } 317 tfulldirt(); 318 319 return count; 320 } 321 322 void 323 kbds_searchnext(int dir) 324 { 325 KCursor c = kbds_c, n = kbds_c; 326 int wrapped = 0; 327 328 if (!kbds_searchlen) { 329 kbds_quant = 0; 330 return; 331 } 332 333 if (dir < 0 && c.x > c.len) 334 c.x = c.len; 335 336 for (kbds_quant = MAX(kbds_quant, 1); kbds_quant > 0;) { 337 if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE)) { 338 c.y += dir; 339 if (c.y < kbds_top()) 340 c.y = kbds_bot(), wrapped++; 341 else if (c.y > kbds_bot()) 342 c.y = kbds_top(), wrapped++; 343 if (wrapped > 1) 344 break;; 345 c.line = TLINE(c.y); 346 c.len = tlinelen(c.line); 347 c.x = (dir < 0 && c.len > 0) ? c.len-1 : 0; 348 c.x -= (c.x > 0 && (c.line[c.x].mode & ATTR_WDUMMY)) ? 1 : 0; 349 } 350 if (kbds_ismatch(c)) { 351 n = c; 352 kbds_quant--; 353 } 354 } 355 356 kbds_moveto(n.x, n.y); 357 kbds_quant = 0; 358 } 359 360 void 361 kbds_findnext(int dir, int repeat) 362 { 363 KCursor prev, c = kbds_c, n = kbds_c; 364 int skipfirst, yoff = 0; 365 366 if (c.len <= 0 || kbds_findchar == 0) { 367 kbds_quant = 0; 368 return; 369 } 370 371 if (dir < 0 && c.x > c.len) 372 c.x = c.len; 373 374 kbds_quant = MAX(kbds_quant, 1); 375 skipfirst = (kbds_quant == 1 && repeat && kbds_findtill); 376 377 while (kbds_quant > 0) { 378 prev = c; 379 if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE)) 380 break; 381 if (c.line[c.x].u == kbds_findchar) { 382 if (skipfirst && prev.x == kbds_c.x && prev.y == kbds_c.y) { 383 skipfirst = 0; 384 continue; 385 } 386 n.x = kbds_findtill ? prev.x : c.x; 387 n.y = c.y; 388 yoff = kbds_findtill ? prev.y - c.y : 0; 389 kbds_quant--; 390 } 391 } 392 393 kbds_moveto(n.x, n.y); 394 kbds_moveto(kbds_c.x, kbds_c.y + yoff); 395 kbds_quant = 0; 396 } 397 398 int 399 kbds_isdelim(KCursor c, int xoff, wchar_t *delims) 400 { 401 if (xoff && !kbds_moveforward(&c, xoff, KBDS_WRAP_LINE)) 402 return 1; 403 return wcschr(delims, c.line[c.x].u) != NULL; 404 } 405 406 void 407 kbds_nextword(int start, int dir, wchar_t *delims) 408 { 409 KCursor c = kbds_c, n = kbds_c; 410 int xoff = start ? -1 : 1; 411 412 if (dir < 0 && c.x > c.len) 413 c.x = c.len; 414 else if (dir > 0 && c.x >= c.len && c.len > 0) 415 c.x = c.len-1; 416 417 for (kbds_quant = MAX(kbds_quant, 1); kbds_quant > 0;) { 418 if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE)) { 419 c.y += dir; 420 if (c.y < kbds_top() || c.y > kbds_bot()) 421 break; 422 c.line = TLINE(c.y); 423 c.len = tlinelen(c.line); 424 c.x = (dir < 0 && c.len > 0) ? c.len-1 : 0; 425 c.x -= (c.x > 0 && (c.line[c.x].mode & ATTR_WDUMMY)) ? 1 : 0; 426 } 427 if (c.len > 0 && 428 !kbds_isdelim(c, 0, delims) && kbds_isdelim(c, xoff, delims)) { 429 n = c; 430 kbds_quant--; 431 } 432 } 433 434 kbds_moveto(n.x, n.y); 435 kbds_quant = 0; 436 } 437 438 int 439 kbds_drawcursor(void) 440 { 441 if (kbds_in_use && (!kbds_issearchmode() || kbds_c.y != term.row-1)) { 442 #if LIGATURES_PATCH 443 xdrawcursor(kbds_c.x, kbds_c.y, TLINE(kbds_c.y)[kbds_c.x], 444 kbds_oc.x, kbds_oc.y, TLINE(kbds_oc.y)[kbds_oc.x], 445 TLINE(kbds_oc.y), term.col); 446 #else 447 xdrawcursor(kbds_c.x, kbds_c.y, TLINE(kbds_c.y)[kbds_c.x], 448 kbds_oc.x, kbds_oc.y, TLINE(kbds_oc.y)[kbds_oc.x]); 449 #endif // LIGATURES_PATCH 450 kbds_moveto(kbds_c.x, kbds_c.y); 451 kbds_oc = kbds_c; 452 } 453 return term.scr != 0 || kbds_in_use; 454 } 455 456 int 457 kbds_keyboardhandler(KeySym ksym, char *buf, int len, int forcequit) 458 { 459 int i, q, dy, eol, islast, prevscr, count, wrap; 460 int alt = IS_SET(MODE_ALTSCREEN); 461 Line line; 462 Rune u; 463 464 if (kbds_issearchmode() && !forcequit) { 465 switch (ksym) { 466 case XK_Escape: 467 kbds_searchlen = 0; 468 /* FALLTHROUGH */ 469 case XK_Return: 470 for (kbds_searchcase = 0, i = 0; i < kbds_searchlen; i++) { 471 if (kbds_searchstr[i].u != towlower(kbds_searchstr[i].u)) { 472 kbds_searchcase = 1; 473 break; 474 } 475 } 476 count = kbds_searchall(); 477 kbds_searchnext(kbds_searchdir); 478 kbds_selecttext(); 479 kbds_setmode(kbds_mode & ~KBDS_MODE_SEARCH); 480 if (count == 0 && kbds_directsearch) 481 ksym = XK_Escape; 482 break; 483 case XK_BackSpace: 484 if (kbds_searchlen) { 485 kbds_searchlen--; 486 if (kbds_searchlen && (kbds_searchstr[kbds_searchlen].mode & ATTR_WDUMMY)) 487 kbds_searchlen--; 488 } 489 break; 490 default: 491 if (len < 1 || kbds_searchlen >= term.col-2) 492 return 0; 493 utf8decode(buf, &u, len); 494 kbds_searchstr[kbds_searchlen].u = u; 495 kbds_searchstr[kbds_searchlen++].mode = ATTR_NULL; 496 if (wcwidth(u) > 1) { 497 kbds_searchstr[kbds_searchlen-1].mode = ATTR_WIDE; 498 if (kbds_searchlen < term.col-2) { 499 kbds_searchstr[kbds_searchlen].u = 0; 500 kbds_searchstr[kbds_searchlen++].mode = ATTR_WDUMMY; 501 } 502 } 503 break; 504 } 505 /* If the direct search is aborted, we just go to the next switch 506 * statement and exit the keyboard selection mode immediately */ 507 if (!(ksym == XK_Escape && kbds_directsearch)) { 508 term.dirty[term.row-1] = 1; 509 return 0; 510 } 511 } else if ((kbds_mode & KBDS_MODE_FIND) && !forcequit) { 512 kbds_findchar = 0; 513 switch (ksym) { 514 case XK_Escape: 515 case XK_Return: 516 kbds_quant = 0; 517 break; 518 default: 519 if (len < 1) 520 return 0; 521 utf8decode(buf, &kbds_findchar, len); 522 kbds_findnext(kbds_finddir, 0); 523 kbds_selecttext(); 524 break; 525 } 526 kbds_setmode(kbds_mode & ~KBDS_MODE_FIND); 527 return 0; 528 } 529 530 switch (ksym) { 531 case -1: 532 kbds_searchstr = xmalloc(term.col * sizeof(Glyph)); 533 kbds_in_use = 1; 534 kbds_moveto(term.c.x, term.c.y); 535 kbds_oc = kbds_c; 536 kbds_setmode(KBDS_MODE_MOVE); 537 return MODE_KBDSELECT; 538 case XK_V: 539 if (kbds_mode & KBDS_MODE_LSELECT) { 540 selclear(); 541 kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT)); 542 } else if (kbds_mode & KBDS_MODE_SELECT) { 543 selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0); 544 sel.ob.x = 0; 545 tfulldirt(); 546 kbds_setmode((kbds_mode ^ KBDS_MODE_SELECT) | KBDS_MODE_LSELECT); 547 } else { 548 selstart(0, kbds_c.y, 0); 549 selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0); 550 kbds_setmode(kbds_mode | KBDS_MODE_LSELECT); 551 } 552 break; 553 case XK_v: 554 if (kbds_mode & KBDS_MODE_SELECT) { 555 selclear(); 556 kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT)); 557 } else if (kbds_mode & KBDS_MODE_LSELECT) { 558 selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0); 559 kbds_setmode((kbds_mode ^ KBDS_MODE_LSELECT) | KBDS_MODE_SELECT); 560 } else { 561 selstart(kbds_c.x, kbds_c.y, 0); 562 kbds_setmode(kbds_mode | KBDS_MODE_SELECT); 563 } 564 break; 565 case XK_s: 566 if (!(kbds_mode & KBDS_MODE_LSELECT)) { 567 kbds_seltype ^= (SEL_REGULAR | SEL_RECTANGULAR); 568 selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0); 569 } 570 break; 571 case XK_y: 572 case XK_Y: 573 if (kbds_isselectmode()) { 574 kbds_copytoclipboard(); 575 selclear(); 576 kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT)); 577 } 578 break; 579 case -2: 580 case -3: 581 case XK_slash: 582 case XK_KP_Divide: 583 case XK_question: 584 kbds_directsearch = (ksym == -2 || ksym == -3); 585 kbds_searchdir = (ksym == XK_question || ksym == -3) ? -1 : 1; 586 kbds_searchlen = 0; 587 kbds_setmode(kbds_mode | KBDS_MODE_SEARCH); 588 kbds_clearhighlights(); 589 return 0; 590 case XK_q: 591 case XK_Escape: 592 if (!kbds_in_use) 593 return 0; 594 if (kbds_quant && !forcequit) { 595 kbds_quant = 0; 596 break; 597 } 598 selclear(); 599 if (kbds_isselectmode() && !forcequit) { 600 kbds_setmode(KBDS_MODE_MOVE); 601 break; 602 } 603 kbds_setmode(KBDS_MODE_MOVE); 604 /* FALLTHROUGH */ 605 case XK_Return: 606 if (kbds_isselectmode()) 607 kbds_copytoclipboard(); 608 kbds_in_use = kbds_quant = 0; 609 free(kbds_searchstr); 610 kscrolldown(&((Arg){ .i = term.histf })); 611 kbds_clearhighlights(); 612 return MODE_KBDSELECT; 613 case XK_n: 614 case XK_N: 615 kbds_searchnext(ksym == XK_n ? kbds_searchdir : -kbds_searchdir); 616 break; 617 case XK_BackSpace: 618 kbds_moveto(0, kbds_c.y); 619 break; 620 case XK_exclam: 621 kbds_moveto(term.col/2, kbds_c.y); 622 break; 623 case XK_underscore: 624 kbds_moveto(term.col-1, kbds_c.y); 625 break; 626 case XK_dollar: 627 case XK_A: 628 eol = kbds_c.len-1; 629 line = kbds_c.line; 630 islast = (kbds_c.x == eol || (kbds_c.x == eol-1 && (line[eol-1].mode & ATTR_WIDE))); 631 if (islast && kbds_iswrapped(&kbds_c) && kbds_c.y < kbds_bot()) 632 kbds_moveto(tlinelen(TLINE(kbds_c.y+1))-1, kbds_c.y+1); 633 else 634 kbds_moveto(islast ? term.col-1 : eol, kbds_c.y); 635 break; 636 case XK_asciicircum: 637 case XK_I: 638 for (i = 0; i < kbds_c.len && kbds_c.line[i].u == ' '; i++) 639 ; 640 kbds_moveto((i < kbds_c.len) ? i : 0, kbds_c.y); 641 break; 642 case XK_End: 643 case XK_KP_End: 644 kbds_moveto(kbds_c.x, term.row-1); 645 break; 646 case XK_Home: 647 case XK_KP_Home: 648 case XK_H: 649 kbds_moveto(kbds_c.x, 0); 650 break; 651 case XK_M: 652 kbds_moveto(kbds_c.x, alt ? (term.row-1) / 2 653 : MIN(term.c.y + term.scr, term.row-1) / 2); 654 break; 655 case XK_L: 656 kbds_moveto(kbds_c.x, alt ? term.row-1 657 : MIN(term.c.y + term.scr, term.row-1)); 658 break; 659 case XK_Page_Up: 660 case XK_KP_Page_Up: 661 case XK_K: 662 prevscr = term.scr; 663 kscrollup(&((Arg){ .i = term.row })); 664 kbds_moveto(kbds_c.x, alt ? 0 665 : MAX(0, kbds_c.y - term.row + term.scr - prevscr)); 666 break; 667 case XK_Page_Down: 668 case XK_KP_Page_Down: 669 case XK_J: 670 prevscr = term.scr; 671 kscrolldown(&((Arg){ .i = term.row })); 672 kbds_moveto(kbds_c.x, alt ? term.row-1 673 : MIN(MIN(term.c.y + term.scr, term.row-1), 674 kbds_c.y + term.row + term.scr - prevscr)); 675 break; 676 case XK_asterisk: 677 case XK_KP_Multiply: 678 kbds_moveto(term.col/2, (term.row-1) / 2); 679 break; 680 case XK_g: 681 kscrollup(&((Arg){ .i = term.histf })); 682 kbds_moveto(kbds_c.x, 0); 683 break; 684 case XK_G: 685 kscrolldown(&((Arg){ .i = term.histf })); 686 kbds_moveto(kbds_c.x, alt ? term.row-1 : term.c.y); 687 break; 688 case XK_b: 689 case XK_B: 690 kbds_nextword(1, -1, (ksym == XK_b) ? kbds_sdelim : kbds_ldelim); 691 break; 692 case XK_w: 693 case XK_W: 694 kbds_nextword(1, +1, (ksym == XK_w) ? kbds_sdelim : kbds_ldelim); 695 break; 696 case XK_e: 697 case XK_E: 698 kbds_nextword(0, +1, (ksym == XK_e) ? kbds_sdelim : kbds_ldelim); 699 break; 700 case XK_z: 701 prevscr = term.scr; 702 dy = kbds_c.y - (term.row-1) / 2; 703 if (dy <= 0) 704 kscrollup(&((Arg){ .i = -dy })); 705 else 706 kscrolldown(&((Arg){ .i = dy })); 707 kbds_moveto(kbds_c.x, kbds_c.y + term.scr - prevscr); 708 break; 709 case XK_f: 710 case XK_F: 711 case XK_t: 712 case XK_T: 713 kbds_finddir = (ksym == XK_f || ksym == XK_t) ? 1 : -1; 714 kbds_findtill = (ksym == XK_t || ksym == XK_T) ? 1 : 0; 715 kbds_setmode(kbds_mode | KBDS_MODE_FIND); 716 return 0; 717 case XK_semicolon: 718 case XK_r: 719 kbds_findnext(kbds_finddir, 1); 720 break; 721 case XK_comma: 722 case XK_R: 723 kbds_findnext(-kbds_finddir, 1); 724 break; 725 case XK_0: 726 case XK_KP_0: 727 if (!kbds_quant) { 728 kbds_moveto(0, kbds_c.y); 729 break; 730 } 731 /* FALLTHROUGH */ 732 default: 733 if (ksym >= XK_0 && ksym <= XK_9) { /* 0-9 keyboard */ 734 q = (kbds_quant * 10) + (ksym ^ XK_0); 735 kbds_quant = q <= 99999999 ? q : kbds_quant; 736 term.dirty[0] = 1; 737 return 0; 738 } else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) { /* 0-9 numpad */ 739 q = (kbds_quant * 10) + (ksym ^ XK_KP_0); 740 kbds_quant = q <= 99999999 ? q : kbds_quant; 741 term.dirty[0] = 1; 742 return 0; 743 } else if (ksym == XK_k || ksym == XK_h) 744 i = ksym & 1; 745 else if (ksym == XK_l || ksym == XK_j) 746 i = ((ksym & 6) | 4) >> 1; 747 else if (ksym >= XK_KP_Left && ksym <= XK_KP_Down) 748 i = ksym - XK_KP_Left; 749 else if ((XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3) 750 return 0; 751 752 kbds_quant = (kbds_quant ? kbds_quant : 1); 753 754 if (i & 1) { 755 kbds_c.y += kbds_quant * (i & 2 ? 1 : -1); 756 } else { 757 for (;kbds_quant > 0; kbds_quant--) { 758 if (!kbds_moveforward(&kbds_c, (i & 2) ? 1 : -1, 759 KBDS_WRAP_LINE | KBDS_WRAP_EDGE)) 760 break; 761 } 762 } 763 kbds_moveto(kbds_c.x, kbds_c.y); 764 } 765 kbds_selecttext(); 766 kbds_quant = 0; 767 term.dirty[0] = 1; 768 return 0; 769 }