Annotation of src/usr.bin/vim/normal.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2: /* vi:set ts=4 sw=4:
! 3: *
! 4: * VIM - Vi IMproved by Bram Moolenaar
! 5: *
! 6: * Do ":help uganda" in Vim to read copying and usage conditions.
! 7: * Do ":help credits" in Vim to see a list of people who contributed.
! 8: */
! 9:
! 10: /*
! 11: * Contains the main routine for processing characters in command mode.
! 12: * Communicates closely with the code in ops.c to handle the operators.
! 13: */
! 14:
! 15: #include "vim.h"
! 16: #include "globals.h"
! 17: #include "proto.h"
! 18: #include "option.h"
! 19:
! 20: #undef EXTERN
! 21: #undef INIT
! 22: #define EXTERN
! 23: #define INIT(x) x
! 24: #include "ops.h"
! 25:
! 26: /*
! 27: * Generally speaking, every command in normal() should either clear any
! 28: * pending operator (with clearop()), or set the motion type variable.
! 29: */
! 30:
! 31: /*
! 32: * If a count is given before the operator, it is saved in opnum.
! 33: */
! 34: static linenr_t opnum = 0;
! 35: static linenr_t Prenum; /* The (optional) number before a command. */
! 36: static int prechar = NUL; /* prepended command char */
! 37: /*
! 38: * The visual area is remembered for reselection.
! 39: */
! 40: static int resel_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
! 41: static linenr_t resel_VIsual_line_count; /* number of lines */
! 42: static colnr_t resel_VIsual_col; /* number of cols or end column */
! 43:
! 44: #ifdef USE_MOUSE
! 45: static void find_start_of_word __ARGS((FPOS *));
! 46: static void find_end_of_word __ARGS((FPOS *));
! 47: static int get_mouse_class __ARGS((int));
! 48: #endif
! 49: static void prep_redo __ARGS((long, int, int, int, int));
! 50: static int checkclearop __ARGS((void));
! 51: static int checkclearopq __ARGS((void));
! 52: static void clearop __ARGS((void));
! 53: static void clearopbeep __ARGS((void));
! 54: static void del_from_showcmd __ARGS((int));
! 55: static void do_gd __ARGS((int nchar));
! 56:
! 57: /*
! 58: * normal
! 59: *
! 60: * Execute a command in normal mode.
! 61: *
! 62: * This is basically a big switch with the cases arranged in rough categories
! 63: * in the following order:
! 64: *
! 65: * 0. Macros (q, @)
! 66: * 1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
! 67: * 2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
! 68: * 3. Cursor motions (G, H, M, L, l, K_RIGHT, , h, K_LEFT, ^H, k, K_UP,
! 69: * ^P, +, CR, LF, j, K_DOWN, ^N, _, |, B, b, W, w, E, e, $, ^, 0)
! 70: * 4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
! 71: * 5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
! 72: * 6. Inserts (A, a, I, i, o, O, R)
! 73: * 7. Operators (~, d, c, y, >, <, !, =, Q)
! 74: * 8. Abbreviations (x, X, D, C, s, S, Y, &)
! 75: * 9. Marks (m, ', `, ^O, ^I)
! 76: * 10. Buffer setting (")
! 77: * 11. Visual (v, V, ^V)
! 78: * 12. Suspend (^Z)
! 79: * 13. Window commands (^W)
! 80: * 14. extended commands (starting with 'g')
! 81: * 15. mouse click
! 82: * 16. scrollbar movement
! 83: * 17. The end (ESC)
! 84: */
! 85:
! 86: void
! 87: normal()
! 88: {
! 89: register int c;
! 90: long n = 0; /* init for GCC */
! 91: int flag = FALSE;
! 92: int flag2 = FALSE;
! 93: int type = 0; /* type of operation */
! 94: int dir = FORWARD; /* search direction */
! 95: int nchar = NUL; /* next command char */
! 96: int finish_op;
! 97: linenr_t Prenum1;
! 98: char_u *searchbuff = NULL; /* buffer for search string */
! 99: FPOS *pos = NULL; /* init for gcc */
! 100: char_u *ptr = NULL;
! 101: int command_busy = FALSE;
! 102: int ctrl_w = FALSE; /* got CTRL-W command */
! 103: int old_col = 0;
! 104: int dont_adjust_op_end = FALSE;
! 105:
! 106: Prenum = 0;
! 107: /*
! 108: * If there is an operator pending, then the command we take this time
! 109: * will terminate it. Finish_op tells us to finish the operation before
! 110: * returning this time (unless the operation was cancelled).
! 111: */
! 112: finish_op = (op_type != NOP);
! 113:
! 114: if (!finish_op && !yankbuffer)
! 115: opnum = 0;
! 116:
! 117: State = NORMAL_BUSY;
! 118: c = vgetc();
! 119: #ifdef HAVE_LANGMAP
! 120: LANGMAP_ADJUST(c, TRUE);
! 121: #endif
! 122: if (c == NUL)
! 123: c = K_ZERO;
! 124: (void)add_to_showcmd(c, FALSE);
! 125:
! 126: getcount:
! 127: /* Pick up any leading digits and compute 'Prenum' */
! 128: while ((c >= '1' && c <= '9') || (Prenum != 0 && (c == K_DEL || c == '0')))
! 129: {
! 130: if (c == K_DEL)
! 131: {
! 132: Prenum /= 10;
! 133: del_from_showcmd(4); /* delete the digit and ~@% */
! 134: }
! 135: else
! 136: Prenum = Prenum * 10 + (c - '0');
! 137: if (Prenum < 0) /* got too large! */
! 138: Prenum = 999999999;
! 139: c = vgetc();
! 140: #ifdef HAVE_LANGMAP
! 141: LANGMAP_ADJUST(c, TRUE);
! 142: #endif
! 143: (void)add_to_showcmd(c, FALSE);
! 144: }
! 145:
! 146: /*
! 147: * If we got CTRL-W there may be a/another count
! 148: */
! 149: if (c == Ctrl('W') && !ctrl_w && op_type == NOP)
! 150: {
! 151: ctrl_w = TRUE;
! 152: opnum = Prenum; /* remember first count */
! 153: Prenum = 0;
! 154: ++no_mapping;
! 155: ++allow_keys; /* no mapping for nchar, but keys */
! 156: c = vgetc(); /* get next character */
! 157: #ifdef HAVE_LANGMAP
! 158: LANGMAP_ADJUST(c, TRUE);
! 159: #endif
! 160: --no_mapping;
! 161: --allow_keys;
! 162: (void)add_to_showcmd(c, FALSE);
! 163: goto getcount; /* jump back */
! 164: }
! 165:
! 166: /*
! 167: * If we're in the middle of an operator (including after entering a yank
! 168: * buffer with ") AND we had a count before the
! 169: * operator, then that count overrides the current value of Prenum. What
! 170: * this means effectively, is that commands like "3dw" get turned into
! 171: * "d3w" which makes things fall into place pretty neatly.
! 172: * If you give a count before AND after the operator, they are multiplied.
! 173: */
! 174: if (opnum != 0)
! 175: {
! 176: if (Prenum)
! 177: Prenum *= opnum;
! 178: else
! 179: Prenum = opnum;
! 180: opnum = 0;
! 181: }
! 182:
! 183: Prenum1 = (Prenum == 0 ? 1 : Prenum); /* Prenum often defaults to 1 */
! 184:
! 185: /*
! 186: * Get an additional character if we need one.
! 187: * For CTRL-W we already got it when looking for a count.
! 188: */
! 189: if (ctrl_w)
! 190: {
! 191: nchar = c;
! 192: c = Ctrl('W');
! 193: }
! 194: else if ((op_type == NOP && vim_strchr((char_u *)"@zm\"", c) != NULL) ||
! 195: (op_type == NOP && !VIsual_active &&
! 196: vim_strchr((char_u *)"rZ", c) != NULL) ||
! 197: vim_strchr((char_u *)"tTfF[]g'`", c) != NULL ||
! 198: (c == 'q' && !Recording && !Exec_reg))
! 199: {
! 200: ++no_mapping;
! 201: ++allow_keys; /* no mapping for nchar, but allow key codes */
! 202: nchar = vgetc();
! 203: #ifdef HAVE_LANGMAP
! 204: /* adjust chars > 127: tTfFr should leave lang of nchar unchanged! */
! 205: LANGMAP_ADJUST(nchar, vim_strchr((char_u *)"tTfFr", c) == NULL);
! 206: #endif
! 207: #ifdef RIGHTLEFT
! 208: if (p_hkmap && strchr("tTfFr", c) && KeyTyped) /* Hebrew mapped char */
! 209: nchar = hkmap(nchar);
! 210: #endif
! 211: --no_mapping;
! 212: --allow_keys;
! 213: (void)add_to_showcmd(nchar, FALSE);
! 214: }
! 215: if (p_sc)
! 216: flushbuf(); /* flush the showcmd characters onto the
! 217: * screen so we can see them while the command
! 218: * is being executed
! 219: */
! 220:
! 221: State = NORMAL;
! 222: if (nchar == ESC)
! 223: {
! 224: clearop();
! 225: goto normal_end;
! 226: }
! 227: msg_didout = FALSE; /* don't scroll screen up for normal command */
! 228: msg_col = 0;
! 229:
! 230: #ifdef RIGHTLEFT
! 231: if (curwin->w_p_rl && KeyTyped) /* invert horizontal operations */
! 232: switch (c)
! 233: {
! 234: case 'l': c = 'h'; break;
! 235: case K_RIGHT: c = K_LEFT; break;
! 236: case 'h': c = 'l'; break;
! 237: case K_LEFT: c = K_RIGHT; break;
! 238: case '>': c = '<'; break;
! 239: case '<': c = '>'; break;
! 240: }
! 241: #endif
! 242: switch (c)
! 243: {
! 244:
! 245: /*
! 246: * 0: Macros
! 247: */
! 248: case 'q': /* (stop) recording into a named register */
! 249: if (checkclearop())
! 250: break;
! 251: /* command is ignored while executing a register */
! 252: if (!Exec_reg && do_record(nchar) == FAIL)
! 253: clearopbeep();
! 254: break;
! 255:
! 256: case '@': /* execute a named buffer */
! 257: if (checkclearop())
! 258: break;
! 259: while (Prenum1--)
! 260: {
! 261: if (do_execbuf(nchar, FALSE, FALSE) == FAIL)
! 262: {
! 263: clearopbeep();
! 264: break;
! 265: }
! 266: }
! 267: break;
! 268:
! 269: /*
! 270: * 1: Screen positioning commands
! 271: */
! 272: case Ctrl('D'):
! 273: flag = TRUE;
! 274:
! 275: case Ctrl('U'):
! 276: if ((c == Ctrl('U') && curwin->w_cursor.lnum == 1) ||
! 277: (c == Ctrl('D') && curwin->w_cursor.lnum ==
! 278: curbuf->b_ml.ml_line_count))
! 279: clearopbeep();
! 280: else
! 281: {
! 282: if (checkclearop())
! 283: break;
! 284: halfpage(flag, Prenum);
! 285: }
! 286: break;
! 287:
! 288: case Ctrl('B'):
! 289: case K_S_UP:
! 290: case K_PAGEUP:
! 291: dir = BACKWARD;
! 292:
! 293: case Ctrl('F'):
! 294: case K_S_DOWN:
! 295: case K_PAGEDOWN:
! 296: if (checkclearop())
! 297: break;
! 298: (void)onepage(dir, Prenum1);
! 299: break;
! 300:
! 301: case Ctrl('E'):
! 302: if (checkclearop())
! 303: break;
! 304: scrollup(Prenum1);
! 305: if (p_so)
! 306: cursor_correct();
! 307: /* We may have moved to another line -- webb */
! 308: coladvance(curwin->w_curswant);
! 309: cursupdate();
! 310: updateScreen(VALID);
! 311: break;
! 312:
! 313: case Ctrl('Y'):
! 314: if (checkclearop())
! 315: break;
! 316: scrolldown(Prenum1);
! 317: if (p_so)
! 318: cursor_correct();
! 319: /* We may have moved to another line -- webb */
! 320: coladvance(curwin->w_curswant);
! 321: updateScreen(VALID);
! 322: break;
! 323:
! 324: case 'z':
! 325: if (checkclearop())
! 326: break;
! 327: if (nchar < 0x100 && isdigit(nchar))
! 328: {
! 329: Prenum = nchar - '0';
! 330: for (;;)
! 331: {
! 332: ++no_mapping;
! 333: ++allow_keys; /* no mapping for nchar, but allow key codes */
! 334: nchar = vgetc();
! 335: #ifdef HAVE_LANGMAP
! 336: LANGMAP_ADJUST(c, TRUE);
! 337: #endif
! 338: --no_mapping;
! 339: --allow_keys;
! 340: (void)add_to_showcmd(nchar, FALSE);
! 341: if (c == K_DEL)
! 342: Prenum /= 10;
! 343: else if (nchar < 0x100 && isdigit(nchar))
! 344: Prenum = Prenum * 10 + (nchar - '0');
! 345: else if (nchar == CR)
! 346: {
! 347: win_setheight((int)Prenum);
! 348: break;
! 349: }
! 350: else if (nchar == 'l' || nchar == 'h' ||
! 351: nchar == K_LEFT || nchar == K_RIGHT)
! 352: {
! 353: Prenum1 = Prenum ? Prenum : 1;
! 354: goto dozet;
! 355: }
! 356: else
! 357: {
! 358: clearopbeep();
! 359: break;
! 360: }
! 361: }
! 362: op_type = NOP;
! 363: break;
! 364: }
! 365: dozet:
! 366: /*
! 367: * If line number given, set cursor, except for "zh", "zl", "ze" and
! 368: * "zs"
! 369: */
! 370: if (vim_strchr((char_u *)"hles", nchar) == NULL &&
! 371: nchar != K_LEFT && nchar != K_RIGHT &&
! 372: Prenum && Prenum != curwin->w_cursor.lnum)
! 373: {
! 374: setpcmark();
! 375: if (Prenum > curbuf->b_ml.ml_line_count)
! 376: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 377: else
! 378: curwin->w_cursor.lnum = Prenum;
! 379: }
! 380: switch (nchar)
! 381: {
! 382: case NL: /* put curwin->w_cursor at top of screen */
! 383: case CR:
! 384: beginline(TRUE);
! 385: /* FALLTHROUGH */
! 386: case 't':
! 387: scroll_cursor_top(0, TRUE);
! 388: break;
! 389:
! 390: case '.': /* put curwin->w_cursor in middle of screen */
! 391: beginline(TRUE);
! 392: /* FALLTHROUGH */
! 393: case 'z':
! 394: scroll_cursor_halfway(TRUE);
! 395: break;
! 396:
! 397: case '-': /* put curwin->w_cursor at bottom of screen */
! 398: beginline(TRUE);
! 399: /* FALLTHROUGH */
! 400: case 'b':
! 401: scroll_cursor_bot(0, TRUE);
! 402: break;
! 403:
! 404: /* "zh" - scroll screen to the right */
! 405: case 'h':
! 406: case K_LEFT:
! 407: if (!curwin->w_p_wrap)
! 408: {
! 409: colnr_t s, e;
! 410:
! 411: if ((colnr_t)Prenum1 > curwin->w_leftcol)
! 412: curwin->w_leftcol = 0;
! 413: else
! 414: curwin->w_leftcol -= (colnr_t)Prenum1;
! 415: n = curwin->w_leftcol + Columns -
! 416: (curwin->w_p_nu ? 8 : 0) - 1;
! 417: if (curwin->w_virtcol > (colnr_t)n)
! 418: coladvance((colnr_t)n);
! 419:
! 420: getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
! 421: if (e > (colnr_t)n)
! 422: coladvance(s - 1);
! 423: redraw_later(NOT_VALID);
! 424: }
! 425: break;
! 426:
! 427: /* "zl" - scroll screen to the left */
! 428: case 'l':
! 429: case K_RIGHT:
! 430: if (!curwin->w_p_wrap)
! 431: {
! 432: colnr_t s, e;
! 433:
! 434: /* scroll the window left */
! 435: curwin->w_leftcol += (colnr_t)Prenum1;
! 436:
! 437: /* If the cursor has moved off the screen, put it at the
! 438: * first char on the screen */
! 439: if (curwin->w_leftcol > curwin->w_virtcol)
! 440: (void)coladvance(curwin->w_leftcol);
! 441:
! 442: /* If the start of the character under the cursor is not
! 443: * on the screen, advance the cursor one more char. If
! 444: * this fails (last char of the line) adjust the
! 445: * scrolling. */
! 446: getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
! 447: if (s < curwin->w_leftcol)
! 448: if (coladvance(e + 1) == FAIL)
! 449: curwin->w_leftcol = s;
! 450:
! 451: redraw_later(NOT_VALID);
! 452: }
! 453: break;
! 454:
! 455: /* "zs" - scroll screen, cursor at the start */
! 456: case 's':
! 457: if (!curwin->w_p_wrap)
! 458: {
! 459: colnr_t s;
! 460:
! 461: getvcol(curwin, &curwin->w_cursor, &s, NULL, NULL);
! 462: curwin->w_leftcol = s;
! 463: redraw_later(NOT_VALID);
! 464: }
! 465: break;
! 466:
! 467: /* "ze" - scroll screen, cursor at the end */
! 468: case 'e':
! 469: if (!curwin->w_p_wrap)
! 470: {
! 471: colnr_t e;
! 472:
! 473: getvcol(curwin, &curwin->w_cursor, NULL, NULL, &e);
! 474: if ((long)e < Columns)
! 475: curwin->w_leftcol = 0;
! 476: else
! 477: curwin->w_leftcol = e - Columns + 1;
! 478: redraw_later(NOT_VALID);
! 479: }
! 480: break;
! 481:
! 482: case Ctrl('S'): /* ignore CTRL-S and CTRL-Q to avoid problems */
! 483: case Ctrl('Q'): /* with terminals that use xon/xoff */
! 484: break;
! 485:
! 486: default:
! 487: clearopbeep();
! 488: }
! 489: updateScreen(VALID);
! 490: break;
! 491:
! 492: /*
! 493: * 2: Control commands
! 494: */
! 495: case ':':
! 496: if (VIsual_active)
! 497: goto dooperator;
! 498: if (checkclearop())
! 499: break;
! 500: /*
! 501: * translate "count:" into ":.,.+(count - 1)"
! 502: */
! 503: if (Prenum)
! 504: {
! 505: stuffReadbuff((char_u *)".");
! 506: if (Prenum > 1)
! 507: {
! 508: stuffReadbuff((char_u *)",.+");
! 509: stuffnumReadbuff((long)Prenum - 1L);
! 510: }
! 511: }
! 512: do_cmdline(NULL, FALSE, FALSE);
! 513: break;
! 514:
! 515: case K_HELP:
! 516: case K_F1:
! 517: if (checkclearopq())
! 518: break;
! 519: do_help((char_u *)"");
! 520: break;
! 521:
! 522: case Ctrl('L'):
! 523: if (checkclearop())
! 524: break;
! 525: updateScreen(CLEAR);
! 526: break;
! 527:
! 528: case Ctrl('G'):
! 529: if (checkclearop())
! 530: break;
! 531: /* print full name if count given or :cd used */
! 532: fileinfo(did_cd | (int)Prenum, FALSE, FALSE);
! 533:
! 534: /*
! 535: * In Visual mode and "^O^G" in Insert mode, the message will be
! 536: * overwritten by the mode message. Wait a bit, until a key is hit.
! 537: */
! 538: if ((VIsual_active || (restart_edit && p_smd)) && KeyTyped)
! 539: {
! 540: setcursor();
! 541: flushbuf();
! 542: mch_delay(10000L, FALSE);
! 543: }
! 544: break;
! 545:
! 546: case K_CCIRCM: /* CTRL-^, short for ":e #" */
! 547: if (checkclearopq())
! 548: break;
! 549: (void)buflist_getfile((int)Prenum, (linenr_t)0, GETF_SETMARK|GETF_ALT);
! 550: break;
! 551:
! 552: case 'Z': /* write, if changed, and exit */
! 553: if (checkclearopq())
! 554: break;
! 555: if (nchar != 'Z')
! 556: {
! 557: clearopbeep();
! 558: break;
! 559: }
! 560: stuffReadbuff((char_u *)":x\n");
! 561: break;
! 562:
! 563: case Ctrl(']'): /* :ta to current identifier */
! 564: case 'K': /* run program for current identifier */
! 565: if (VIsual_active) /* :ta to visual highlighted text */
! 566: {
! 567: if (VIsual.lnum != curwin->w_cursor.lnum)
! 568: {
! 569: clearopbeep();
! 570: break;
! 571: }
! 572: if (lt(curwin->w_cursor, VIsual))
! 573: {
! 574: ptr = ml_get_pos(&curwin->w_cursor);
! 575: n = VIsual.col - curwin->w_cursor.col + 1;
! 576: }
! 577: else
! 578: {
! 579: ptr = ml_get_pos(&VIsual);
! 580: n = curwin->w_cursor.col - VIsual.col + 1;
! 581: }
! 582: end_visual_mode();
! 583: ++RedrawingDisabled;
! 584: update_curbuf(NOT_VALID); /* update the inversion later */
! 585: --RedrawingDisabled;
! 586: }
! 587: if (checkclearopq())
! 588: break;
! 589: /*FALLTHROUGH*/
! 590:
! 591: case 163: /* the pound sign, '#' for English keyboards */
! 592: if (c == 163)
! 593: c = '#';
! 594: /*FALLTHROUGH*/
! 595:
! 596: case '*': /* / to current identifier or string */
! 597: case '#': /* ? to current identifier or string */
! 598: search_word:
! 599: if (c == 'g')
! 600: type = nchar; /* "g*" or "g#" */
! 601: else
! 602: type = c;
! 603: if (ptr == NULL && (n = find_ident_under_cursor(&ptr, (type == '*' ||
! 604: type == '#') ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0)
! 605: {
! 606: clearop();
! 607: break;
! 608: }
! 609:
! 610: if (Prenum)
! 611: stuffnumReadbuff(Prenum);
! 612: switch (type)
! 613: {
! 614: case '*':
! 615: stuffReadbuff((char_u *)"/");
! 616: /* FALLTHROUGH */
! 617:
! 618: case '#':
! 619: if (type == '#')
! 620: stuffReadbuff((char_u *)"?");
! 621:
! 622: /*
! 623: * put cursor at start of word, makes search skip the word
! 624: * under the cursor
! 625: */
! 626: curwin->w_cursor.col = ptr - ml_get_curline();
! 627:
! 628: if (c != 'g' && iswordchar(*ptr))
! 629: stuffReadbuff((char_u *)"\\<");
! 630: no_smartcase = TRUE; /* don't use 'smartcase' now */
! 631: break;
! 632:
! 633: case 'K':
! 634: if (*p_kp == NUL)
! 635: stuffReadbuff((char_u *)":he ");
! 636: else
! 637: {
! 638: stuffReadbuff((char_u *)":! ");
! 639: stuffReadbuff(p_kp);
! 640: stuffReadbuff((char_u *)" ");
! 641: }
! 642: break;
! 643: default:
! 644: if (curbuf->b_help)
! 645: stuffReadbuff((char_u *)":he ");
! 646: else
! 647: stuffReadbuff((char_u *)":ta ");
! 648: }
! 649:
! 650: /*
! 651: * Now grab the chars in the identifier
! 652: */
! 653: while (n--)
! 654: {
! 655: /* put a backslash before \ and some others */
! 656: if (*ptr == '\\' || (!(type == '*' || type == '#') &&
! 657: vim_strchr(escape_chars, *ptr) != NULL))
! 658: stuffcharReadbuff('\\');
! 659: /* don't interpret the characters as edit commands */
! 660: if (*ptr < ' ' || *ptr > '~')
! 661: stuffcharReadbuff(Ctrl('V'));
! 662: stuffcharReadbuff(*ptr++);
! 663: }
! 664:
! 665: if (c != 'g' && (type == '*' || type == '#') && iswordchar(ptr[-1]))
! 666: stuffReadbuff((char_u *)"\\>");
! 667: stuffReadbuff((char_u *)"\n");
! 668: break;
! 669:
! 670: case Ctrl('T'): /* backwards in tag stack */
! 671: if (checkclearopq())
! 672: break;
! 673: do_tag((char_u *)"", 2, (int)Prenum1);
! 674: break;
! 675:
! 676: /*
! 677: * Cursor motions
! 678: */
! 679: case 'G':
! 680: goto_line:
! 681: op_motion_type = MLINE;
! 682: setpcmark();
! 683: if (Prenum == 0 || Prenum > curbuf->b_ml.ml_line_count)
! 684: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 685: else
! 686: curwin->w_cursor.lnum = Prenum;
! 687: beginline(MAYBE);
! 688: break;
! 689:
! 690: case 'H':
! 691: case 'M':
! 692: if (c == 'M')
! 693: {
! 694: int used = 0;
! 695:
! 696: for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n)
! 697: if ((used += plines(curwin->w_topline + n)) >=
! 698: (curwin->w_height - curwin->w_empty_rows + 1) / 2)
! 699: break;
! 700: if (n && used > curwin->w_height)
! 701: --n;
! 702: }
! 703: else
! 704: n = Prenum;
! 705: op_motion_type = MLINE;
! 706: setpcmark();
! 707: curwin->w_cursor.lnum = curwin->w_topline + n;
! 708: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
! 709: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 710: cursor_correct(); /* correct for 'so' */
! 711: beginline(MAYBE);
! 712: break;
! 713:
! 714: case 'L':
! 715: op_motion_type = MLINE;
! 716: setpcmark();
! 717: curwin->w_cursor.lnum = curwin->w_botline - 1;
! 718: if (Prenum >= curwin->w_cursor.lnum)
! 719: curwin->w_cursor.lnum = 1;
! 720: else
! 721: curwin->w_cursor.lnum -= Prenum;
! 722: cursor_correct(); /* correct for 'so' */
! 723: beginline(MAYBE);
! 724: break;
! 725:
! 726: case 'l':
! 727: case K_RIGHT:
! 728: case ' ':
! 729: op_motion_type = MCHAR;
! 730: op_inclusive = FALSE;
! 731: n = Prenum1;
! 732: while (n--)
! 733: {
! 734: if (oneright() == FAIL)
! 735: {
! 736: /* space wraps to next line if 'whichwrap' bit 1 set */
! 737: /* 'l' wraps to next line if 'whichwrap' bit 2 set */
! 738: /* CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set */
! 739: if (((c == ' ' && vim_strchr(p_ww, 's') != NULL) ||
! 740: (c == 'l' && vim_strchr(p_ww, 'l') != NULL) ||
! 741: (c == K_RIGHT && vim_strchr(p_ww, '>') != NULL)) &&
! 742: curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
! 743: {
! 744: /* When deleting we also count the NL as a character.
! 745: * Set op_inclusive when last char in the line is
! 746: * included, move to next line after that */
! 747: if ((op_type == DELETE || op_type == CHANGE) &&
! 748: !op_inclusive && !lineempty(curwin->w_cursor.lnum))
! 749: op_inclusive = TRUE;
! 750: else
! 751: {
! 752: ++curwin->w_cursor.lnum;
! 753: curwin->w_cursor.col = 0;
! 754: curwin->w_set_curswant = TRUE;
! 755: op_inclusive = FALSE;
! 756: }
! 757: continue;
! 758: }
! 759: if (op_type == NOP)
! 760: beep_flush();
! 761: else
! 762: {
! 763: if (lineempty(curwin->w_cursor.lnum))
! 764: clearopbeep();
! 765: else
! 766: {
! 767: op_inclusive = TRUE;
! 768: if (n)
! 769: beep_flush();
! 770: }
! 771: }
! 772: break;
! 773: }
! 774: }
! 775: break;
! 776:
! 777: case 'h':
! 778: case K_LEFT:
! 779: case K_BS:
! 780: case Ctrl('H'):
! 781: op_motion_type = MCHAR;
! 782: op_inclusive = FALSE;
! 783: n = Prenum1;
! 784: while (n--)
! 785: {
! 786: if (oneleft() == FAIL)
! 787: {
! 788: /* backspace and del wrap to previous line if 'whichwrap'
! 789: * bit 0 set.
! 790: * 'h' wraps to previous line if 'whichwrap' bit 2 set.
! 791: * CURS_LEFT wraps to previous line if 'whichwrap' bit 3
! 792: * set. */
! 793: if ( (((c == K_BS || c == Ctrl('H'))
! 794: && vim_strchr(p_ww, 'b') != NULL) ||
! 795: (c == 'h' && vim_strchr(p_ww, 'h') != NULL) ||
! 796: (c == K_LEFT && vim_strchr(p_ww, '<') != NULL)) &&
! 797: curwin->w_cursor.lnum > 1)
! 798: {
! 799: --(curwin->w_cursor.lnum);
! 800: coladvance(MAXCOL);
! 801: curwin->w_set_curswant = TRUE;
! 802:
! 803: /* When the NL before the first char has to be deleted we
! 804: * put the cursor on the NUL after the previous line.
! 805: * This is a very special case, be careful!
! 806: * don't adjust op_end now, otherwise it won't work */
! 807: if ((op_type == DELETE || op_type == CHANGE) &&
! 808: !lineempty(curwin->w_cursor.lnum))
! 809: {
! 810: ++curwin->w_cursor.col;
! 811: dont_adjust_op_end = TRUE;
! 812: }
! 813: continue;
! 814: }
! 815: else if (op_type != DELETE && op_type != CHANGE)
! 816: beep_flush();
! 817: else if (Prenum1 == 1)
! 818: clearopbeep();
! 819: break;
! 820: }
! 821: }
! 822: break;
! 823:
! 824: case '-':
! 825: flag = TRUE;
! 826: /* FALLTHROUGH */
! 827:
! 828: case 'k':
! 829: case K_UP:
! 830: case Ctrl('P'):
! 831: normal_k:
! 832: op_motion_type = MLINE;
! 833: if (cursor_up(Prenum1) == FAIL)
! 834: clearopbeep();
! 835: else if (flag)
! 836: beginline(TRUE);
! 837: break;
! 838:
! 839: case '+':
! 840: case CR:
! 841: flag = TRUE;
! 842: /* FALLTHROUGH */
! 843:
! 844: case 'j':
! 845: case K_DOWN:
! 846: case Ctrl('N'):
! 847: case NL:
! 848: normal_j:
! 849: op_motion_type = MLINE;
! 850: if (cursor_down(Prenum1) == FAIL)
! 851: clearopbeep();
! 852: else if (flag)
! 853: beginline(TRUE);
! 854: break;
! 855:
! 856: /*
! 857: * This is a strange motion command that helps make operators more
! 858: * logical. It is actually implemented, but not documented in the
! 859: * real 'vi'. This motion command actually refers to "the current
! 860: * line". Commands like "dd" and "yy" are really an alternate form of
! 861: * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
! 862: * lines.
! 863: */
! 864: case '_':
! 865: lineop:
! 866: old_col = curwin->w_curswant;
! 867: op_motion_type = MLINE;
! 868: if (cursor_down((long)(Prenum1 - 1)) == FAIL)
! 869: clearopbeep();
! 870: if (op_type == DELETE || op_type == LSHIFT || op_type == RSHIFT)
! 871: beginline(MAYBE);
! 872: else if (op_type != YANK) /* 'Y' does not move cursor */
! 873: beginline(TRUE);
! 874: break;
! 875:
! 876: case K_HOME:
! 877: if ((mod_mask & MOD_MASK_CTRL))
! 878: goto goto_line_one;
! 879: Prenum = 1;
! 880: /* FALLTHROUGH */
! 881:
! 882: case '|':
! 883: op_motion_type = MCHAR;
! 884: op_inclusive = FALSE;
! 885: beginline(FALSE);
! 886: if (Prenum > 0)
! 887: {
! 888: coladvance((colnr_t)(Prenum - 1));
! 889: curwin->w_curswant = (colnr_t)(Prenum - 1);
! 890: }
! 891: else
! 892: curwin->w_curswant = 0;
! 893: /* keep curswant at the column where we wanted to go, not where
! 894: we ended; differs is line is too short */
! 895: curwin->w_set_curswant = FALSE;
! 896: break;
! 897:
! 898: /*
! 899: * Word Motions
! 900: */
! 901:
! 902: case 'B':
! 903: type = 1;
! 904: /* FALLTHROUGH */
! 905:
! 906: case 'b':
! 907: case K_S_LEFT:
! 908: op_motion_type = MCHAR;
! 909: op_inclusive = FALSE;
! 910: curwin->w_set_curswant = TRUE;
! 911: if (bck_word(Prenum1, type, FALSE) == FAIL)
! 912: clearopbeep();
! 913: break;
! 914:
! 915: case 'E':
! 916: type = 1;
! 917: /* FALLTHROUGH */
! 918:
! 919: case 'e':
! 920: op_inclusive = TRUE;
! 921: goto dowrdcmd;
! 922:
! 923: case 'W':
! 924: type = 1;
! 925: /* FALLTHROUGH */
! 926:
! 927: case 'w':
! 928: case K_S_RIGHT:
! 929: op_inclusive = FALSE;
! 930: flag = TRUE;
! 931: /*
! 932: * This is a little strange. To match what the real vi does, we
! 933: * effectively map 'cw' to 'ce', and 'cW' to 'cE', provided that we
! 934: * are not on a space or a TAB. This seems impolite at first, but it's
! 935: * really more what we mean when we say 'cw'.
! 936: * Another strangeness: When standing on the end of a word "ce" will
! 937: * change until the end of the next wordt, but "cw" will change only
! 938: * one character! This is done by setting type to 2.
! 939: */
! 940: if (op_type == CHANGE && (n = gchar_cursor()) != ' ' && n != TAB &&
! 941: n != NUL)
! 942: {
! 943: op_inclusive = TRUE;
! 944: flag = FALSE;
! 945: flag2 = TRUE;
! 946: }
! 947:
! 948: dowrdcmd:
! 949: op_motion_type = MCHAR;
! 950: curwin->w_set_curswant = TRUE;
! 951: if (flag)
! 952: n = fwd_word(Prenum1, type, op_type != NOP);
! 953: else
! 954: n = end_word(Prenum1, type, flag2, FALSE);
! 955: if (n == FAIL)
! 956: clearopbeep();
! 957: break;
! 958:
! 959: case K_END:
! 960: if ((mod_mask & MOD_MASK_CTRL))
! 961: goto goto_line;
! 962: /* FALLTHROUGH */
! 963:
! 964: case '$':
! 965: op_motion_type = MCHAR;
! 966: op_inclusive = TRUE;
! 967: curwin->w_curswant = MAXCOL; /* so we stay at the end */
! 968: if (cursor_down((long)(Prenum1 - 1)) == FAIL)
! 969: {
! 970: clearopbeep();
! 971: break;
! 972: }
! 973: break;
! 974:
! 975: case '^':
! 976: flag = TRUE;
! 977: /* FALLTHROUGH */
! 978:
! 979: case '0':
! 980: op_motion_type = MCHAR;
! 981: op_inclusive = FALSE;
! 982: beginline(flag);
! 983: break;
! 984:
! 985: /*
! 986: * 4: Searches
! 987: */
! 988: case '?':
! 989: case '/':
! 990: if ((searchbuff = getcmdline(c, Prenum1)) == NULL)
! 991: {
! 992: clearop();
! 993: break;
! 994: }
! 995: op_motion_type = MCHAR;
! 996: op_inclusive = FALSE;
! 997: curwin->w_set_curswant = TRUE;
! 998:
! 999: n = do_search(c, searchbuff, Prenum1,
! 1000: SEARCH_MARK | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG);
! 1001: if (n == 0)
! 1002: clearop();
! 1003: else if (n == 2)
! 1004: op_motion_type = MLINE;
! 1005: break;
! 1006:
! 1007: case 'N':
! 1008: flag = SEARCH_REV;
! 1009:
! 1010: case 'n':
! 1011: op_motion_type = MCHAR;
! 1012: op_inclusive = FALSE;
! 1013: curwin->w_set_curswant = TRUE;
! 1014: if (!do_search(0, NULL, Prenum1,
! 1015: SEARCH_MARK | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG | flag))
! 1016: clearop();
! 1017: break;
! 1018:
! 1019: /*
! 1020: * Character searches
! 1021: */
! 1022: case 'T':
! 1023: dir = BACKWARD;
! 1024: /* FALLTHROUGH */
! 1025:
! 1026: case 't':
! 1027: type = 1;
! 1028: goto docsearch;
! 1029:
! 1030: case 'F':
! 1031: dir = BACKWARD;
! 1032: /* FALLTHROUGH */
! 1033:
! 1034: case 'f':
! 1035: docsearch:
! 1036: op_motion_type = MCHAR;
! 1037: if (dir == BACKWARD)
! 1038: op_inclusive = FALSE;
! 1039: else
! 1040: op_inclusive = TRUE;
! 1041: curwin->w_set_curswant = TRUE;
! 1042: if (nchar >= 0x100 || !searchc(nchar, dir, type, Prenum1))
! 1043: clearopbeep();
! 1044: break;
! 1045:
! 1046: case ',':
! 1047: flag = 1;
! 1048: /* FALLTHROUGH */
! 1049:
! 1050: case ';':
! 1051: dir = flag;
! 1052: goto docsearch; /* nchar == NUL, thus repeat previous search */
! 1053:
! 1054: /*
! 1055: * section or C function searches
! 1056: */
! 1057: case '[':
! 1058: dir = BACKWARD;
! 1059: /* FALLTHROUGH */
! 1060:
! 1061: case ']':
! 1062: op_motion_type = MCHAR;
! 1063: op_inclusive = FALSE;
! 1064:
! 1065: /*
! 1066: * "[f" or "]f" : Edit file under the cursor (same as "gf")
! 1067: */
! 1068: if (nchar == 'f')
! 1069: goto gotofile;
! 1070:
! 1071: /*
! 1072: * Find the occurence(s) of the identifier or define under cursor
! 1073: * in current and included files or jump to the first occurence.
! 1074: *
! 1075: * search list jump
! 1076: * fwd bwd fwd bwd fwd bwd
! 1077: * identifier "]i" "[i" "]I" "[I" "]^I" "[^I"
! 1078: * define "]d" "[d" "]D" "[D" "]^D" "[^D"
! 1079: */
! 1080: if (nchar == 'i' || nchar == 'I' || nchar == Ctrl('I') ||
! 1081: nchar == 'd' || nchar == 'D' || nchar == Ctrl('D'))
! 1082: {
! 1083: int len;
! 1084:
! 1085: if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
! 1086: {
! 1087: clearop();
! 1088: break;
! 1089: }
! 1090: find_pattern_in_path(ptr, len, TRUE,
! 1091: Prenum == 0 ? !isupper(nchar) : FALSE,
! 1092: ((nchar & 0xf) == ('d' & 0xf)) ? FIND_DEFINE : FIND_ANY,
! 1093: Prenum1,
! 1094: isupper(nchar) ? ACTION_SHOW_ALL :
! 1095: islower(nchar) ? ACTION_SHOW : ACTION_GOTO,
! 1096: c == ']' ? curwin->w_cursor.lnum : (linenr_t)1,
! 1097: (linenr_t)MAXLNUM);
! 1098: curwin->w_set_curswant = TRUE;
! 1099: break;
! 1100: }
! 1101:
! 1102: /*
! 1103: * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
! 1104: * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
! 1105: * "[/", "[*", "]/", "]*": go to Nth comment start/end.
! 1106: */
! 1107: if ((c == '[' && vim_strchr((char_u *)"{(*/#", nchar) != NULL) ||
! 1108: (c == ']' && vim_strchr((char_u *)"})*/#", nchar) != NULL))
! 1109: {
! 1110: FPOS old_pos;
! 1111: FPOS new_pos;
! 1112:
! 1113: if (nchar == '*')
! 1114: nchar = '/';
! 1115: old_pos = curwin->w_cursor;
! 1116: new_pos.lnum = 0;
! 1117: while (Prenum1--)
! 1118: {
! 1119: if ((pos = findmatchlimit(nchar,
! 1120: (c == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
! 1121: {
! 1122: if (new_pos.lnum == 0) /* nothing found */
! 1123: clearopbeep();
! 1124: else
! 1125: pos = &new_pos; /* use last one found */
! 1126: break;
! 1127: }
! 1128: curwin->w_cursor = *pos;
! 1129: new_pos= *pos;
! 1130: }
! 1131: curwin->w_cursor = old_pos;
! 1132: if (pos != NULL)
! 1133: {
! 1134: setpcmark();
! 1135: curwin->w_cursor = *pos;
! 1136: curwin->w_set_curswant = TRUE;
! 1137: }
! 1138: break;
! 1139: }
! 1140:
! 1141: /*
! 1142: * "[[", "[]", "]]" and "][": move to start or end of function
! 1143: */
! 1144: if (nchar == '[' || nchar == ']')
! 1145: {
! 1146: if (nchar == c) /* "]]" or "[[" */
! 1147: flag = '{';
! 1148: else
! 1149: flag = '}'; /* "][" or "[]" */
! 1150:
! 1151: curwin->w_set_curswant = TRUE;
! 1152: /*
! 1153: * Imitate strange vi behaviour: When using "]]" with an operator
! 1154: * we also stop at '}'.
! 1155: */
! 1156: if (!findpar(dir, Prenum1, flag,
! 1157: (op_type != NOP && dir == FORWARD && flag == '{')))
! 1158: clearopbeep();
! 1159: else if (op_type == NOP)
! 1160: beginline(TRUE);
! 1161: break;
! 1162: }
! 1163:
! 1164: /*
! 1165: * "[p", "[P", "]P" and "]p": put with indent adjustment
! 1166: */
! 1167: if (nchar == 'p' || nchar == 'P')
! 1168: {
! 1169: if (checkclearopq())
! 1170: break;
! 1171: prep_redo(Prenum, NUL, c, nchar, NUL);
! 1172: do_put((c == ']' && nchar == 'p') ? FORWARD : BACKWARD,
! 1173: Prenum1, TRUE);
! 1174: break;
! 1175: }
! 1176:
! 1177: #ifdef USE_MOUSE
! 1178: /*
! 1179: * [ or ] followed by a middle mouse click: put selected text with
! 1180: * indent adjustment. Any other button just does as usual.
! 1181: */
! 1182: if (nchar >= K_LEFTMOUSE && nchar <= K_RIGHTRELEASE)
! 1183: {
! 1184: (void)do_mouse(nchar, (c == ']') ? FORWARD : BACKWARD,
! 1185: Prenum1, TRUE);
! 1186: break;
! 1187: }
! 1188: #endif /* USE_MOUSE */
! 1189:
! 1190: /*
! 1191: * end of '[' and ']': not a valid nchar
! 1192: */
! 1193: clearopbeep();
! 1194: break;
! 1195:
! 1196: case '%':
! 1197: op_inclusive = TRUE;
! 1198: if (Prenum) /* {cnt}% : goto {cnt} percentage in file */
! 1199: {
! 1200: if (Prenum > 100)
! 1201: clearopbeep();
! 1202: else
! 1203: {
! 1204: op_motion_type = MLINE;
! 1205: setpcmark();
! 1206: /* round up, so CTRL-G will give same value */
! 1207: curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
! 1208: Prenum + 99) / 100;
! 1209: beginline(MAYBE);
! 1210: }
! 1211: }
! 1212: else /* % : go to matching paren */
! 1213: {
! 1214: op_motion_type = MCHAR;
! 1215: if ((pos = findmatch(NUL)) == NULL)
! 1216: clearopbeep();
! 1217: else
! 1218: {
! 1219: setpcmark();
! 1220: curwin->w_cursor = *pos;
! 1221: curwin->w_set_curswant = TRUE;
! 1222: }
! 1223: }
! 1224: break;
! 1225:
! 1226: case '(':
! 1227: dir = BACKWARD;
! 1228: /* FALLTHROUGH */
! 1229:
! 1230: case ')':
! 1231: op_motion_type = MCHAR;
! 1232: if (c == ')')
! 1233: op_inclusive = FALSE;
! 1234: else
! 1235: op_inclusive = TRUE;
! 1236: curwin->w_set_curswant = TRUE;
! 1237:
! 1238: if (findsent(dir, Prenum1) == FAIL)
! 1239: clearopbeep();
! 1240: break;
! 1241:
! 1242: case '{':
! 1243: dir = BACKWARD;
! 1244: /* FALLTHROUGH */
! 1245:
! 1246: case '}':
! 1247: op_motion_type = MCHAR;
! 1248: op_inclusive = FALSE;
! 1249: curwin->w_set_curswant = TRUE;
! 1250: if (!findpar(dir, Prenum1, NUL, FALSE))
! 1251: clearopbeep();
! 1252: break;
! 1253:
! 1254: /*
! 1255: * 5: Edits
! 1256: */
! 1257: case '.': /* redo command */
! 1258: if (checkclearopq())
! 1259: break;
! 1260: /*
! 1261: * if restart_edit is TRUE, the last but one command is repeated
! 1262: * instead of the last command (inserting text). This is used for
! 1263: * CTRL-O <.> in insert mode
! 1264: */
! 1265: if (start_redo(Prenum, restart_edit && !arrow_used) == FAIL)
! 1266: clearopbeep();
! 1267: break;
! 1268:
! 1269: case 'u': /* undo */
! 1270: if (VIsual_active || op_type == vim_strchr(opchars, 'u') - opchars + 1)
! 1271: goto dooperator;
! 1272: case K_UNDO:
! 1273: if (checkclearopq())
! 1274: break;
! 1275: u_undo((int)Prenum1);
! 1276: curwin->w_set_curswant = TRUE;
! 1277: break;
! 1278:
! 1279: case Ctrl('R'): /* undo undo */
! 1280: if (checkclearopq())
! 1281: break;
! 1282: u_redo((int)Prenum1);
! 1283: curwin->w_set_curswant = TRUE;
! 1284: break;
! 1285:
! 1286: case 'U': /* Undo line */
! 1287: if (VIsual_active || op_type == vim_strchr(opchars, 'U') - opchars + 1)
! 1288: goto dooperator;
! 1289: if (checkclearopq())
! 1290: break;
! 1291: u_undoline();
! 1292: curwin->w_set_curswant = TRUE;
! 1293: break;
! 1294:
! 1295: case 'r':
! 1296: if (VIsual_active)
! 1297: {
! 1298: c = 'c';
! 1299: goto dooperator;
! 1300: }
! 1301: if (checkclearop())
! 1302: break;
! 1303: ptr = ml_get_cursor();
! 1304: /* special key or not enough characters to replace */
! 1305: if (nchar >= 0x100 || STRLEN(ptr) < (unsigned)Prenum1)
! 1306: {
! 1307: clearopbeep();
! 1308: break;
! 1309: }
! 1310: /*
! 1311: * Replacing with a TAB is done by edit(), because it is complicated
! 1312: * when 'expandtab' is set.
! 1313: * Other characters are done below to avoid problems with things like
! 1314: * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
! 1315: */
! 1316: if (nchar == '\t' && curbuf->b_p_et)
! 1317: {
! 1318: prep_redo(Prenum1, NUL, 'r', '\t', NUL);
! 1319: stuffnumReadbuff(Prenum1);
! 1320: stuffcharReadbuff('R');
! 1321: stuffcharReadbuff('\t');
! 1322: stuffcharReadbuff(ESC);
! 1323: break;
! 1324: }
! 1325:
! 1326: if (nchar == Ctrl('V')) /* get another character */
! 1327: {
! 1328: c = Ctrl('V');
! 1329: nchar = get_literal();
! 1330: }
! 1331: else
! 1332: c = NUL;
! 1333: prep_redo(Prenum1, NUL, 'r', c, nchar);
! 1334: if (u_save_cursor() == FAIL) /* save line for undo */
! 1335: break;
! 1336: /*
! 1337: * Replace characters by a newline.
! 1338: * Strange vi behaviour: Only one newline is inserted.
! 1339: * Delete the characters here.
! 1340: * Insert the newline with an insert command, takes care of
! 1341: * autoindent.
! 1342: */
! 1343: if (c != Ctrl('V') && (nchar == '\r' || nchar == '\n'))
! 1344: {
! 1345: while (Prenum1--) /* delete the characters */
! 1346: delchar(FALSE);
! 1347: /* replacing the last character of a line is different */
! 1348: if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
! 1349: {
! 1350: --curwin->w_cursor.col;
! 1351: stuffcharReadbuff('a');
! 1352: }
! 1353: else
! 1354: stuffcharReadbuff('i');
! 1355: stuffcharReadbuff('\r');
! 1356: stuffcharReadbuff(ESC);
! 1357: }
! 1358: else
! 1359: {
! 1360: while (Prenum1--) /* replace the characters */
! 1361: {
! 1362: /*
! 1363: * Replace a 'normal' character.
! 1364: * Get ptr again, because u_save and/or showmatch() will have
! 1365: * released the line. At the same time we let know that the
! 1366: * line will be changed.
! 1367: */
! 1368: ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
! 1369: ptr[curwin->w_cursor.col] = nchar;
! 1370: if (p_sm && (nchar == ')' || nchar == '}' || nchar == ']'))
! 1371: showmatch();
! 1372: ++curwin->w_cursor.col;
! 1373: }
! 1374: --curwin->w_cursor.col; /* cursor on the last replaced char */
! 1375: }
! 1376: curwin->w_set_curswant = TRUE;
! 1377: CHANGED;
! 1378: updateline();
! 1379: set_last_insert(nchar);
! 1380: break;
! 1381:
! 1382: case 'J':
! 1383: if (VIsual_active) /* join the visual lines */
! 1384: goto dooperator;
! 1385: if (checkclearop())
! 1386: break;
! 1387: if (Prenum <= 1)
! 1388: Prenum = 2; /* default for join is two lines! */
! 1389: if (curwin->w_cursor.lnum + Prenum - 1 > curbuf->b_ml.ml_line_count)
! 1390: {
! 1391: clearopbeep(); /* beyond last line */
! 1392: break;
! 1393: }
! 1394:
! 1395: prep_redo(Prenum, NUL, 'J', NUL, NUL);
! 1396: do_do_join(Prenum, TRUE, TRUE);
! 1397: break;
! 1398:
! 1399: case 'P':
! 1400: dir = BACKWARD;
! 1401: /* FALLTHROUGH */
! 1402:
! 1403: case 'p':
! 1404: /*
! 1405: * 'P' after an operator or with Visual: Set current block.
! 1406: * 'p' after an operator or with Visual: Set current paragraph.
! 1407: */
! 1408: if (op_type != NOP || VIsual_active)
! 1409: {
! 1410: if (c == 'P')
! 1411: {
! 1412: if (current_block('{', Prenum1) == FAIL)
! 1413: clearopbeep();
! 1414: }
! 1415: else
! 1416: {
! 1417: if (current_par(c, Prenum1) == FAIL)
! 1418: clearopbeep();
! 1419: }
! 1420: curwin->w_set_curswant = TRUE;
! 1421: }
! 1422: else
! 1423: {
! 1424: prep_redo(Prenum, NUL, c, NUL, NUL);
! 1425: do_put(dir, Prenum1, FALSE);
! 1426: }
! 1427: break;
! 1428:
! 1429: case Ctrl('A'): /* add to number */
! 1430: case Ctrl('X'): /* subtract from number */
! 1431: if (checkclearopq())
! 1432: break;
! 1433: if (do_addsub((int)c, Prenum1) == OK)
! 1434: prep_redo(Prenum1, NUL, c, NUL, NUL);
! 1435: break;
! 1436:
! 1437: /*
! 1438: * 6: Inserts
! 1439: */
! 1440: case 'A':
! 1441: type = 1;
! 1442: /* FALLTHROUGH */
! 1443:
! 1444: case 'a':
! 1445: if (op_type != NOP || VIsual_active)
! 1446: {
! 1447: if (current_word(Prenum1, type) == FAIL)
! 1448: clearopbeep();
! 1449: curwin->w_set_curswant = TRUE;
! 1450: }
! 1451: else
! 1452: {
! 1453: if (c == 'A')
! 1454: {
! 1455: curwin->w_set_curswant = TRUE;
! 1456: while (oneright() == OK)
! 1457: ;
! 1458: }
! 1459:
! 1460: /* Works just like an 'i'nsert on the next character. */
! 1461: if (u_save_cursor() == OK)
! 1462: {
! 1463: if (!lineempty(curwin->w_cursor.lnum))
! 1464: inc_cursor();
! 1465: command_busy = edit(c, FALSE, Prenum1);
! 1466: }
! 1467: }
! 1468: break;
! 1469:
! 1470: case 'I':
! 1471: if (checkclearopq())
! 1472: break;
! 1473: beginline(TRUE);
! 1474: /* FALLTHROUGH */
! 1475:
! 1476: case 'i':
! 1477: case K_INS:
! 1478: insert_command:
! 1479: if (checkclearopq())
! 1480: break;
! 1481: if (u_save_cursor() == OK)
! 1482: command_busy = edit(c, FALSE, Prenum1);
! 1483: break;
! 1484:
! 1485: case 'o':
! 1486: if (VIsual_active) /* switch start and end of visual */
! 1487: {
! 1488: Prenum = VIsual.lnum;
! 1489: VIsual.lnum = curwin->w_cursor.lnum;
! 1490: curwin->w_cursor.lnum = Prenum;
! 1491: n = VIsual.col;
! 1492: VIsual.col = curwin->w_cursor.col;
! 1493: curwin->w_cursor.col = (int)n;
! 1494: curwin->w_set_curswant = TRUE;
! 1495: break;
! 1496: }
! 1497: if (checkclearop())
! 1498: break;
! 1499: if (has_format_option(FO_OPEN_COMS))
! 1500: fo_do_comments = TRUE;
! 1501: if (u_save(curwin->w_cursor.lnum,
! 1502: (linenr_t)(curwin->w_cursor.lnum + 1)) == OK &&
! 1503: Opencmd(FORWARD, TRUE, FALSE))
! 1504: command_busy = edit('o', TRUE, Prenum1);
! 1505: fo_do_comments = FALSE;
! 1506: break;
! 1507:
! 1508: case 'O':
! 1509: if (checkclearopq())
! 1510: break;
! 1511: if (has_format_option(FO_OPEN_COMS))
! 1512: fo_do_comments = TRUE;
! 1513: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
! 1514: curwin->w_cursor.lnum) == OK && Opencmd(BACKWARD, TRUE, FALSE))
! 1515: command_busy = edit('O', TRUE, Prenum1);
! 1516: fo_do_comments = FALSE;
! 1517: break;
! 1518:
! 1519: case 'R':
! 1520: if (VIsual_active)
! 1521: {
! 1522: c = 'c';
! 1523: VIsual_mode = 'V';
! 1524: goto dooperator;
! 1525: }
! 1526: if (checkclearopq())
! 1527: break;
! 1528: if (u_save_cursor() == OK)
! 1529: command_busy = edit('R', FALSE, Prenum1);
! 1530: break;
! 1531:
! 1532: /*
! 1533: * 7: Operators
! 1534: */
! 1535: case '~': /* swap case */
! 1536: /*
! 1537: * if tilde is not an operator and Visual is off: swap case
! 1538: * of a single character
! 1539: */
! 1540: if (!p_to && !VIsual_active &&
! 1541: op_type != vim_strchr(opchars, '~') - opchars + 1)
! 1542: {
! 1543: if (checkclearopq())
! 1544: break;
! 1545: if (lineempty(curwin->w_cursor.lnum))
! 1546: {
! 1547: clearopbeep();
! 1548: break;
! 1549: }
! 1550: prep_redo(Prenum, NUL, '~', NUL, NUL);
! 1551:
! 1552: if (u_save_cursor() == FAIL)
! 1553: break;
! 1554:
! 1555: for (; Prenum1 > 0; --Prenum1)
! 1556: {
! 1557: if (gchar_cursor() == NUL)
! 1558: break;
! 1559: swapchar(&curwin->w_cursor);
! 1560: inc_cursor();
! 1561: }
! 1562:
! 1563: curwin->w_set_curswant = TRUE;
! 1564: CHANGED;
! 1565: updateline();
! 1566: break;
! 1567: }
! 1568: /*FALLTHROUGH*/
! 1569:
! 1570: case 'd':
! 1571: case 'c':
! 1572: case 'y':
! 1573: case '>':
! 1574: case '<':
! 1575: case '!':
! 1576: case '=':
! 1577: case 'Q': /* should start Ex mode */
! 1578: dooperator:
! 1579: n = vim_strchr(opchars, c) - opchars + 1;
! 1580: if (n == op_type) /* double operator works on lines */
! 1581: goto lineop;
! 1582: if (checkclearop())
! 1583: break;
! 1584: if (Prenum != 0)
! 1585: opnum = Prenum;
! 1586: curbuf->b_op_start = curwin->w_cursor;
! 1587: op_type = (int)n;
! 1588: break;
! 1589:
! 1590: /*
! 1591: * 8: Abbreviations
! 1592: */
! 1593:
! 1594: /* when Visual the next commands are operators */
! 1595: case K_DEL:
! 1596: c = 'x'; /* DEL key behaves like 'x' */
! 1597: case 'S':
! 1598: case 'Y':
! 1599: case 'D':
! 1600: case 'C':
! 1601: case 'x':
! 1602: case 'X':
! 1603: case 's':
! 1604: /*
! 1605: * 's' or 'S' with an operator: Operate on sentence or section.
! 1606: */
! 1607: if (op_type != NOP || VIsual_active)
! 1608: {
! 1609: if (c == 's') /* sentence */
! 1610: {
! 1611: if (current_sent(Prenum1) == FAIL)
! 1612: clearopbeep();
! 1613: curwin->w_set_curswant = TRUE;
! 1614: break;
! 1615: }
! 1616: if (c == 'S') /* block with () */
! 1617: {
! 1618: if (current_block('(', Prenum1) == FAIL)
! 1619: clearopbeep();
! 1620: curwin->w_set_curswant = TRUE;
! 1621: break;
! 1622: }
! 1623: }
! 1624: if (VIsual_active)
! 1625: {
! 1626: static char_u trans[] = "YyDdCcxdXd";
! 1627:
! 1628: /* uppercase means linewise */
! 1629: if (isupper(c) && VIsual_mode != Ctrl('V'))
! 1630: VIsual_mode = 'V';
! 1631: c = *(vim_strchr(trans, c) + 1);
! 1632: goto dooperator;
! 1633: }
! 1634:
! 1635: case '&':
! 1636: if (checkclearopq())
! 1637: break;
! 1638: if (Prenum)
! 1639: stuffnumReadbuff(Prenum);
! 1640:
! 1641: {
! 1642: static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
! 1643: (char_u *)"d$", (char_u *)"c$",
! 1644: (char_u *)"cl", (char_u *)"cc",
! 1645: (char_u *)"yy", (char_u *)":s\r"};
! 1646: static char_u *str = (char_u *)"xXDCsSY&";
! 1647:
! 1648: stuffReadbuff(ar[(int)(vim_strchr(str, c) - str)]);
! 1649: }
! 1650: break;
! 1651:
! 1652: /*
! 1653: * 9: Marks
! 1654: */
! 1655:
! 1656: case 'm':
! 1657: if (checkclearop())
! 1658: break;
! 1659: if (setmark(nchar) == FAIL)
! 1660: clearopbeep();
! 1661: break;
! 1662:
! 1663: case '\'':
! 1664: flag = TRUE;
! 1665: /* FALLTHROUGH */
! 1666:
! 1667: case '`':
! 1668: pos = getmark(nchar, (op_type == NOP));
! 1669: if (pos == (FPOS *)-1) /* jumped to other file */
! 1670: {
! 1671: if (flag)
! 1672: beginline(TRUE);
! 1673: break;
! 1674: }
! 1675:
! 1676: cursormark:
! 1677: if (check_mark(pos) == FAIL)
! 1678: clearop();
! 1679: else
! 1680: {
! 1681: if (c == '\'' || c == '`')
! 1682: setpcmark();
! 1683: curwin->w_cursor = *pos;
! 1684: if (flag)
! 1685: beginline(TRUE);
! 1686: }
! 1687: op_motion_type = flag ? MLINE : MCHAR;
! 1688: op_inclusive = FALSE; /* ignored if not MCHAR */
! 1689: curwin->w_set_curswant = TRUE;
! 1690: break;
! 1691:
! 1692: case Ctrl('O'): /* goto older pcmark */
! 1693: Prenum1 = -Prenum1;
! 1694: /* FALLTHROUGH */
! 1695:
! 1696: case Ctrl('I'): /* goto newer pcmark */
! 1697: if (checkclearopq())
! 1698: break;
! 1699: pos = movemark((int)Prenum1);
! 1700: if (pos == (FPOS *)-1) /* jump to other file */
! 1701: {
! 1702: curwin->w_set_curswant = TRUE;
! 1703: break;
! 1704: }
! 1705: if (pos != NULL) /* can jump */
! 1706: goto cursormark;
! 1707: clearopbeep();
! 1708: break;
! 1709:
! 1710: /*
! 1711: * 10. Buffer setting
! 1712: */
! 1713: case '"':
! 1714: if (checkclearop())
! 1715: break;
! 1716: if (nchar != NUL && is_yank_buffer(nchar, FALSE))
! 1717: {
! 1718: yankbuffer = nchar;
! 1719: opnum = Prenum; /* remember count before '"' */
! 1720: }
! 1721: else
! 1722: clearopbeep();
! 1723: break;
! 1724:
! 1725: /*
! 1726: * 11. Visual
! 1727: */
! 1728: case 'v':
! 1729: case 'V':
! 1730: case Ctrl('V'):
! 1731: if (checkclearop())
! 1732: break;
! 1733:
! 1734: /* change Visual mode */
! 1735: if (VIsual_active)
! 1736: {
! 1737: if (VIsual_mode == c) /* stop visual mode */
! 1738: {
! 1739: end_visual_mode();
! 1740: }
! 1741: else /* toggle char/block mode */
! 1742: { /* or char/line mode */
! 1743: VIsual_mode = c;
! 1744: showmode();
! 1745: }
! 1746: update_curbuf(NOT_VALID); /* update the inversion */
! 1747: }
! 1748: /* start Visual mode */
! 1749: else
! 1750: {
! 1751: VIsual_save = VIsual; /* keep for "gv" */
! 1752: VIsual_mode_save = VIsual_mode;
! 1753: start_visual_highlight();
! 1754: if (Prenum) /* use previously selected part */
! 1755: {
! 1756: if (resel_VIsual_mode == NUL) /* there is none */
! 1757: {
! 1758: beep_flush();
! 1759: break;
! 1760: }
! 1761: VIsual = curwin->w_cursor;
! 1762: VIsual_active = TRUE;
! 1763: #ifdef USE_MOUSE
! 1764: setmouse();
! 1765: #endif
! 1766: if (p_smd)
! 1767: redraw_cmdline = TRUE; /* show visual mode later */
! 1768: /*
! 1769: * For V and ^V, we multiply the number of lines even if there
! 1770: * was only one -- webb
! 1771: */
! 1772: if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
! 1773: {
! 1774: curwin->w_cursor.lnum += resel_VIsual_line_count * Prenum - 1;
! 1775: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
! 1776: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 1777: }
! 1778: VIsual_mode = resel_VIsual_mode;
! 1779: if (VIsual_mode == 'v')
! 1780: {
! 1781: if (resel_VIsual_line_count <= 1)
! 1782: curwin->w_cursor.col += resel_VIsual_col * Prenum - 1;
! 1783: else
! 1784: curwin->w_cursor.col = resel_VIsual_col;
! 1785: }
! 1786: if (resel_VIsual_col == MAXCOL)
! 1787: {
! 1788: curwin->w_curswant = MAXCOL;
! 1789: coladvance(MAXCOL);
! 1790: }
! 1791: else if (VIsual_mode == Ctrl('V'))
! 1792: {
! 1793: curwin->w_curswant = curwin->w_virtcol +
! 1794: resel_VIsual_col * Prenum - 1;
! 1795: coladvance((colnr_t)curwin->w_curswant);
! 1796: }
! 1797: else
! 1798: curwin->w_set_curswant = TRUE;
! 1799: curs_columns(TRUE); /* recompute w_virtcol */
! 1800: update_curbuf(NOT_VALID); /* show the inversion */
! 1801: }
! 1802: else
! 1803: {
! 1804: VIsual = curwin->w_cursor;
! 1805: VIsual_mode = c;
! 1806: VIsual_active = TRUE;
! 1807: #ifdef USE_MOUSE
! 1808: setmouse();
! 1809: #endif
! 1810: if (p_smd)
! 1811: redraw_cmdline = TRUE; /* show visual mode later */
! 1812: updateline(); /* start the inversion */
! 1813: }
! 1814: }
! 1815: break;
! 1816:
! 1817: /*
! 1818: * 12. Suspend
! 1819: */
! 1820:
! 1821: case Ctrl('Z'):
! 1822: clearop();
! 1823: if (VIsual_active)
! 1824: end_visual_mode(); /* stop Visual */
! 1825: stuffReadbuff((char_u *)":st\r"); /* with autowrite */
! 1826: break;
! 1827:
! 1828: /*
! 1829: * 13. Window commands
! 1830: */
! 1831:
! 1832: case Ctrl('W'):
! 1833: if (checkclearop())
! 1834: break;
! 1835: do_window(nchar, Prenum); /* everything is in window.c */
! 1836: break;
! 1837:
! 1838: /*
! 1839: * 14. extended commands (starting with 'g')
! 1840: */
! 1841: case 'g':
! 1842: switch (nchar)
! 1843: {
! 1844: /*
! 1845: * "gv": reselect the previous visual area
! 1846: */
! 1847: case 'v':
! 1848: if (checkclearop())
! 1849: break;
! 1850: if (VIsual_active)
! 1851: pos = &VIsual_save;
! 1852: else
! 1853: pos = &VIsual;
! 1854: if (pos->lnum == 0 || pos->lnum > curbuf->b_ml.ml_line_count ||
! 1855: VIsual_end.lnum == 0)
! 1856: beep_flush();
! 1857: else
! 1858: {
! 1859: FPOS tt;
! 1860: int t;
! 1861:
! 1862: /* exchange previous and current visual area */
! 1863: if (VIsual_active)
! 1864: {
! 1865: tt = VIsual;
! 1866: VIsual = VIsual_save;
! 1867: VIsual_save = tt;
! 1868: t = VIsual_mode;
! 1869: VIsual_mode = VIsual_mode_save;
! 1870: VIsual_mode_save = t;
! 1871: tt = curwin->w_cursor;
! 1872: }
! 1873: curwin->w_cursor = VIsual_end;
! 1874: if (VIsual_active)
! 1875: VIsual_end = tt;
! 1876: check_cursor();
! 1877: VIsual_active = TRUE;
! 1878: #ifdef USE_MOUSE
! 1879: setmouse();
! 1880: #endif
! 1881: update_curbuf(NOT_VALID);
! 1882: showmode();
! 1883: }
! 1884: break;
! 1885:
! 1886: /*
! 1887: * "gj" and "gk" two new funny movement keys -- up and down
! 1888: * movement based on *screen* line rather than *file* line.
! 1889: */
! 1890: case 'j':
! 1891: case K_DOWN:
! 1892: if (!curwin->w_p_wrap)
! 1893: goto normal_j;
! 1894: if (screengo(FORWARD, Prenum1) == FAIL)
! 1895: clearopbeep();
! 1896: break;
! 1897:
! 1898: case 'k':
! 1899: case K_UP:
! 1900: if (!curwin->w_p_wrap)
! 1901: goto normal_k;
! 1902: if (screengo(BACKWARD, Prenum1) == FAIL)
! 1903: clearopbeep();
! 1904: break;
! 1905:
! 1906: /*
! 1907: * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines.
! 1908: */
! 1909: case '^':
! 1910: flag = TRUE;
! 1911: /* FALLTHROUGH */
! 1912:
! 1913: case '0':
! 1914: case K_HOME:
! 1915: op_motion_type = MCHAR;
! 1916: op_inclusive = FALSE;
! 1917: if (curwin->w_p_wrap)
! 1918: {
! 1919: n = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
! 1920: Columns) * Columns;
! 1921: if (curwin->w_p_nu && n > 8)
! 1922: n -= 8;
! 1923: }
! 1924: else
! 1925: n = curwin->w_leftcol;
! 1926: coladvance((colnr_t)n);
! 1927: if (flag)
! 1928: while (vim_iswhite(gchar_cursor()) && oneright() == OK)
! 1929: ;
! 1930: curwin->w_set_curswant = TRUE;
! 1931: break;
! 1932:
! 1933: case '$':
! 1934: case K_END:
! 1935: op_motion_type = MCHAR;
! 1936: op_inclusive = TRUE;
! 1937: if (curwin->w_p_wrap)
! 1938: {
! 1939: curwin->w_curswant = MAXCOL; /* so we stay at the end */
! 1940: if (Prenum1 == 1)
! 1941: {
! 1942: n = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
! 1943: Columns + 1) * Columns - 1;
! 1944: if (curwin->w_p_nu && n > 8)
! 1945: n -= 8;
! 1946: coladvance((colnr_t)n);
! 1947: }
! 1948: else if (screengo(FORWARD, Prenum1 - 1) == FAIL)
! 1949: clearopbeep();
! 1950: }
! 1951: else
! 1952: {
! 1953: n = curwin->w_leftcol + Columns - 1;
! 1954: if (curwin->w_p_nu)
! 1955: n -= 8;
! 1956: coladvance((colnr_t)n);
! 1957: curwin->w_set_curswant = TRUE;
! 1958: }
! 1959: break;
! 1960:
! 1961: /*
! 1962: * "g*" and "g#", like "*" and "#" but without using "\<" and "\>"
! 1963: */
! 1964: case '*':
! 1965: case '#':
! 1966: goto search_word;
! 1967:
! 1968: /*
! 1969: * ge and gE: go back to end of word
! 1970: */
! 1971: case 'e':
! 1972: case 'E':
! 1973: op_motion_type = MCHAR;
! 1974: curwin->w_set_curswant = TRUE;
! 1975: op_inclusive = TRUE;
! 1976: if (bckend_word(Prenum1, nchar == 'E', FALSE) == FAIL)
! 1977: clearopbeep();
! 1978: break;
! 1979:
! 1980: /*
! 1981: * g CTRL-G: display info about cursor position
! 1982: */
! 1983: case Ctrl('G'):
! 1984: cursor_pos_info();
! 1985: break;
! 1986:
! 1987: /*
! 1988: * "gI": Start insert in column 1.
! 1989: */
! 1990: case 'I':
! 1991: beginline(FALSE);
! 1992: goto insert_command;
! 1993:
! 1994: /*
! 1995: * "gf": goto file, edit file under cursor
! 1996: * "]f" and "[f": can also be used.
! 1997: */
! 1998: case 'f':
! 1999: gotofile:
! 2000: ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP);
! 2001: if (ptr != NULL)
! 2002: {
! 2003: /* do autowrite if necessary */
! 2004: if (curbuf->b_changed && curbuf->b_nwindows <= 1 && !p_hid)
! 2005: autowrite(curbuf);
! 2006: setpcmark();
! 2007: (void)do_ecmd(0, ptr, NULL, NULL, p_hid, (linenr_t)0,
! 2008: FALSE);
! 2009: vim_free(ptr);
! 2010: }
! 2011: else
! 2012: clearop();
! 2013: break;
! 2014:
! 2015: /*
! 2016: * "gs": Goto sleep, but keep on checking for CTRL-C
! 2017: */
! 2018: case 's':
! 2019: while (Prenum1-- && !got_int)
! 2020: {
! 2021: mch_delay(1000L, TRUE);
! 2022: mch_breakcheck();
! 2023: }
! 2024: break;
! 2025:
! 2026: /*
! 2027: * "ga": Display the ascii value of the character under the
! 2028: * cursor. It is displayed in decimal, hex, and octal. -- webb
! 2029: */
! 2030: case 'a':
! 2031: do_ascii();
! 2032: break;
! 2033:
! 2034: /*
! 2035: * "gg": Goto the first line in file. With a count it goes to
! 2036: * that line number like for G. -- webb
! 2037: */
! 2038: case 'g':
! 2039: goto_line_one:
! 2040: if (Prenum == 0)
! 2041: Prenum = 1;
! 2042: goto goto_line;
! 2043:
! 2044: /*
! 2045: * Operater to format text:
! 2046: * gq same as 'Q' operator.
! 2047: * Operators to change the case of text:
! 2048: * g~ Toggle the case of the text.
! 2049: * gu Change text to lower case.
! 2050: * gU Change text to upper case.
! 2051: * --webb
! 2052: */
! 2053: case 'q':
! 2054: case '~':
! 2055: case 'u':
! 2056: case 'U':
! 2057: prechar = c;
! 2058: c = nchar;
! 2059: goto dooperator;
! 2060:
! 2061: /*
! 2062: * "gd": Find first occurence of pattern under the cursor in the
! 2063: * current function
! 2064: * "gD": idem, but in the current file.
! 2065: */
! 2066: case 'd':
! 2067: case 'D':
! 2068: do_gd(nchar);
! 2069: break;
! 2070:
! 2071: #ifdef USE_MOUSE
! 2072: /*
! 2073: * g<*Mouse> : <C-*mouse>
! 2074: */
! 2075: case K_MIDDLEMOUSE:
! 2076: case K_MIDDLEDRAG:
! 2077: case K_MIDDLERELEASE:
! 2078: case K_LEFTMOUSE:
! 2079: case K_LEFTDRAG:
! 2080: case K_LEFTRELEASE:
! 2081: case K_RIGHTMOUSE:
! 2082: case K_RIGHTDRAG:
! 2083: case K_RIGHTRELEASE:
! 2084: mod_mask = MOD_MASK_CTRL;
! 2085: (void)do_mouse(nchar, BACKWARD, Prenum1, FALSE);
! 2086: break;
! 2087:
! 2088: case K_IGNORE:
! 2089: break;
! 2090: #endif
! 2091:
! 2092: default:
! 2093: clearopbeep();
! 2094: break;
! 2095: }
! 2096: break;
! 2097:
! 2098: /*
! 2099: * 15. mouse click
! 2100: */
! 2101: #ifdef USE_MOUSE
! 2102: case K_MIDDLEMOUSE:
! 2103: case K_MIDDLEDRAG:
! 2104: case K_MIDDLERELEASE:
! 2105: case K_LEFTMOUSE:
! 2106: case K_LEFTDRAG:
! 2107: case K_LEFTRELEASE:
! 2108: case K_RIGHTMOUSE:
! 2109: case K_RIGHTDRAG:
! 2110: case K_RIGHTRELEASE:
! 2111: (void)do_mouse(c, BACKWARD, Prenum1, FALSE);
! 2112: break;
! 2113:
! 2114: case K_IGNORE:
! 2115: break;
! 2116: #endif
! 2117:
! 2118: #ifdef USE_GUI
! 2119: /*
! 2120: * 16. scrollbar movement
! 2121: */
! 2122: case K_SCROLLBAR:
! 2123: if (op_type != NOP)
! 2124: clearopbeep();
! 2125:
! 2126: /* Even if an operator was pending, we still want to scroll */
! 2127: gui_do_scroll();
! 2128: break;
! 2129:
! 2130: case K_HORIZ_SCROLLBAR:
! 2131: if (op_type != NOP)
! 2132: clearopbeep();
! 2133:
! 2134: /* Even if an operator was pending, we still want to scroll */
! 2135: gui_do_horiz_scroll();
! 2136: break;
! 2137: #endif
! 2138:
! 2139: /*
! 2140: * 17. The end
! 2141: */
! 2142: case ESC:
! 2143: /* Don't drop through and beep if we are canceling a command: */
! 2144: if (!VIsual_active && (op_type != NOP ||
! 2145: opnum || Prenum || yankbuffer))
! 2146: {
! 2147: clearop(); /* don't beep */
! 2148: break;
! 2149: }
! 2150: if (VIsual_active)
! 2151: {
! 2152: end_visual_mode(); /* stop Visual */
! 2153: update_curbuf(NOT_VALID);
! 2154: clearop(); /* don't beep */
! 2155: break;
! 2156: }
! 2157: /* ESC in normal mode: beep, but don't flush buffers */
! 2158: clearop();
! 2159: vim_beep();
! 2160: break;
! 2161:
! 2162: default: /* not a known command */
! 2163: clearopbeep();
! 2164: break;
! 2165:
! 2166: } /* end of switch on command character */
! 2167:
! 2168: /*
! 2169: * if we didn't start or finish an operator, reset yankbuffer, unless we
! 2170: * need it later.
! 2171: */
! 2172: if (!finish_op && !op_type && vim_strchr((char_u *)"\"DCYSsXx.", c) == NULL)
! 2173: yankbuffer = 0;
! 2174:
! 2175: /*
! 2176: * If an operation is pending, handle it...
! 2177: */
! 2178: do_pending_operator(c, nchar, finish_op, searchbuff,
! 2179: &command_busy, old_col, FALSE, dont_adjust_op_end);
! 2180:
! 2181: normal_end:
! 2182: if (op_type == NOP && yankbuffer == 0)
! 2183: clear_showcmd();
! 2184:
! 2185: if (restart_edit && op_type == NOP && !VIsual_active
! 2186: && !command_busy && stuff_empty() && yankbuffer == 0)
! 2187: (void)edit(restart_edit, FALSE, 1L);
! 2188:
! 2189: checkpcmark(); /* check if we moved since setting pcmark */
! 2190: vim_free(searchbuff);
! 2191:
! 2192: /*
! 2193: * Update the other windows for the current buffer if modified has been set in
! 2194: * set_Changed() (This should be done more efficiently)
! 2195: */
! 2196: if (modified)
! 2197: {
! 2198: WIN *wp;
! 2199:
! 2200: for (wp = firstwin; wp; wp = wp->w_next)
! 2201: if (wp != curwin && wp->w_buffer == curbuf)
! 2202: {
! 2203: cursor_off();
! 2204: wp->w_redr_type = NOT_VALID;
! 2205: /*
! 2206: * don't do the actual redraw if wait_return() has just been
! 2207: * called and the user typed a ":"
! 2208: */
! 2209: if (!skip_redraw)
! 2210: win_update(wp);
! 2211: }
! 2212: modified = FALSE;
! 2213: }
! 2214: }
! 2215:
! 2216: /*
! 2217: * Handle an operator after visual mode or when the movement is finished
! 2218: */
! 2219: void
! 2220: do_pending_operator(c, nchar, finish_op, searchbuff, command_busy,
! 2221: old_col, gui_yank, dont_adjust_op_end)
! 2222: register int c;
! 2223: int nchar;
! 2224: int finish_op;
! 2225: char_u *searchbuff;
! 2226: int *command_busy;
! 2227: int old_col;
! 2228: int gui_yank; /* yanking visual area for GUI */
! 2229: int dont_adjust_op_end;
! 2230: {
! 2231: /* The visual area is remembered for redo */
! 2232: static int redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
! 2233: static linenr_t redo_VIsual_line_count; /* number of lines */
! 2234: static colnr_t redo_VIsual_col; /* number of cols or end column */
! 2235: static long redo_VIsual_Prenum; /* Prenum for operator */
! 2236:
! 2237: linenr_t Prenum1 = 1L;
! 2238: FPOS old_cursor;
! 2239: int VIsual_was_active = VIsual_active;
! 2240: int redraw;
! 2241:
! 2242: #ifdef USE_GUI
! 2243: /*
! 2244: * Yank the visual area into the GUI selection register before we operate
! 2245: * on it and lose it forever. This could call do_pending_operator()
! 2246: * recursively, but that's OK because gui_yank will be TRUE for the
! 2247: * nested call. Note also that we call gui_copy_selection() and not
! 2248: * gui_auto_select(). This is because even when 'autoselect' is not set,
! 2249: * if we operate on the text, eg by deleting it, then this is considered to
! 2250: * be an explicit request for it to be put in the global cut buffer, so we
! 2251: * always want to do it here. -- webb
! 2252: */
! 2253: if (gui.in_use && op_type != NOP && !gui_yank && VIsual_active
! 2254: && !redo_VIsual_busy)
! 2255: gui_copy_selection();
! 2256: #endif
! 2257: old_cursor = curwin->w_cursor;
! 2258:
! 2259: /*
! 2260: * If an operation is pending, handle it...
! 2261: */
! 2262: if ((VIsual_active || finish_op) && op_type != NOP)
! 2263: {
! 2264: op_is_VIsual = VIsual_active;
! 2265: if (op_type != YANK && !VIsual_active) /* can't redo yank */
! 2266: {
! 2267: prep_redo(Prenum, prechar, opchars[op_type - 1], c, nchar);
! 2268: if (c == '/' || c == '?') /* was a search */
! 2269: {
! 2270: /*
! 2271: * If 'cpoptions' does not contain 'r', insert the search
! 2272: * pattern to really repeat the same command.
! 2273: */
! 2274: if (vim_strchr(p_cpo, CPO_REDO) == NULL)
! 2275: AppendToRedobuff(searchbuff);
! 2276: AppendToRedobuff(NL_STR);
! 2277: }
! 2278: }
! 2279:
! 2280: if (redo_VIsual_busy)
! 2281: {
! 2282: curbuf->b_op_start = curwin->w_cursor;
! 2283: curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
! 2284: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
! 2285: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 2286: VIsual_mode = redo_VIsual_mode;
! 2287: if (VIsual_mode == 'v')
! 2288: {
! 2289: if (redo_VIsual_line_count <= 1)
! 2290: curwin->w_cursor.col += redo_VIsual_col - 1;
! 2291: else
! 2292: curwin->w_cursor.col = redo_VIsual_col;
! 2293: }
! 2294: if (redo_VIsual_col == MAXCOL)
! 2295: {
! 2296: curwin->w_curswant = MAXCOL;
! 2297: coladvance(MAXCOL);
! 2298: }
! 2299: Prenum = redo_VIsual_Prenum;
! 2300: }
! 2301: else if (VIsual_active)
! 2302: {
! 2303: curbuf->b_op_start = VIsual;
! 2304: VIsual_end = curwin->w_cursor;
! 2305: if (VIsual_mode == 'V')
! 2306: curbuf->b_op_start.col = 0;
! 2307: }
! 2308:
! 2309: if (lt(curbuf->b_op_start, curwin->w_cursor))
! 2310: {
! 2311: curbuf->b_op_end = curwin->w_cursor;
! 2312: curwin->w_cursor = curbuf->b_op_start;
! 2313: }
! 2314: else
! 2315: {
! 2316: curbuf->b_op_end = curbuf->b_op_start;
! 2317: curbuf->b_op_start = curwin->w_cursor;
! 2318: }
! 2319: op_line_count = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
! 2320:
! 2321: if (VIsual_active || redo_VIsual_busy)
! 2322: {
! 2323: if (VIsual_mode == Ctrl('V')) /* block mode */
! 2324: {
! 2325: colnr_t start, end;
! 2326:
! 2327: op_block_mode = TRUE;
! 2328: getvcol(curwin, &(curbuf->b_op_start),
! 2329: &op_start_vcol, NULL, &op_end_vcol);
! 2330: if (!redo_VIsual_busy)
! 2331: {
! 2332: getvcol(curwin, &(curbuf->b_op_end), &start, NULL, &end);
! 2333: if (start < op_start_vcol)
! 2334: op_start_vcol = start;
! 2335: if (end > op_end_vcol)
! 2336: op_end_vcol = end;
! 2337: }
! 2338:
! 2339: /* if '$' was used, get op_end_vcol from longest line */
! 2340: if (curwin->w_curswant == MAXCOL)
! 2341: {
! 2342: curwin->w_cursor.col = MAXCOL;
! 2343: op_end_vcol = 0;
! 2344: for (curwin->w_cursor.lnum = curbuf->b_op_start.lnum;
! 2345: curwin->w_cursor.lnum <= curbuf->b_op_end.lnum;
! 2346: ++curwin->w_cursor.lnum)
! 2347: {
! 2348: getvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
! 2349: if (end > op_end_vcol)
! 2350: op_end_vcol = end;
! 2351: }
! 2352: curwin->w_cursor = curbuf->b_op_start;
! 2353: }
! 2354: else if (redo_VIsual_busy)
! 2355: op_end_vcol = op_start_vcol + redo_VIsual_col - 1;
! 2356: coladvance(op_start_vcol);
! 2357: }
! 2358:
! 2359: if (!redo_VIsual_busy)
! 2360: {
! 2361: /*
! 2362: * Prepare to reselect and redo Visual: this is based on the
! 2363: * size of the Visual text
! 2364: */
! 2365: resel_VIsual_mode = VIsual_mode;
! 2366: if (curwin->w_curswant == MAXCOL)
! 2367: resel_VIsual_col = MAXCOL;
! 2368: else if (VIsual_mode == Ctrl('V'))
! 2369: resel_VIsual_col = op_end_vcol - op_start_vcol + 1;
! 2370: else if (op_line_count > 1)
! 2371: resel_VIsual_col = curbuf->b_op_end.col;
! 2372: else
! 2373: resel_VIsual_col = curbuf->b_op_end.col -
! 2374: curbuf->b_op_start.col + 1;
! 2375: resel_VIsual_line_count = op_line_count;
! 2376: }
! 2377: /* can't redo yank and : */
! 2378: if (op_type != YANK && op_type != COLON)
! 2379: {
! 2380: prep_redo(0L, NUL, 'v', prechar, opchars[op_type - 1]);
! 2381: redo_VIsual_mode = resel_VIsual_mode;
! 2382: redo_VIsual_col = resel_VIsual_col;
! 2383: redo_VIsual_line_count = resel_VIsual_line_count;
! 2384: redo_VIsual_Prenum = Prenum;
! 2385: }
! 2386:
! 2387: /*
! 2388: * Mincl defaults to TRUE.
! 2389: * If op_end is on a NUL (empty line) op_inclusive becomes FALSE
! 2390: * This makes "d}P" and "v}dP" work the same.
! 2391: */
! 2392: op_inclusive = TRUE;
! 2393: if (VIsual_mode == 'V')
! 2394: op_motion_type = MLINE;
! 2395: else
! 2396: {
! 2397: op_motion_type = MCHAR;
! 2398: if (*ml_get_pos(&(curbuf->b_op_end)) == NUL)
! 2399: op_inclusive = FALSE;
! 2400: }
! 2401:
! 2402: redo_VIsual_busy = FALSE;
! 2403: /*
! 2404: * Switch Visual off now, so screen updating does
! 2405: * not show inverted text when the screen is redrawn.
! 2406: * With YANK and sometimes with COLON and FILTER there is no screen
! 2407: * redraw, so it is done here to remove the inverted part.
! 2408: */
! 2409: if (!gui_yank)
! 2410: {
! 2411: VIsual_active = FALSE;
! 2412: #ifdef USE_MOUSE
! 2413: setmouse();
! 2414: #endif
! 2415: if (p_smd)
! 2416: clear_cmdline = TRUE; /* unshow visual mode later */
! 2417: if (op_type == YANK || op_type == COLON || op_type == FILTER)
! 2418: update_curbuf(NOT_VALID);
! 2419: }
! 2420:
! 2421: /* set Prenum1 for LSHIFT and RSHIFT, e.g. "V3j2>" */
! 2422: if (Prenum == 0)
! 2423: Prenum1 = 1L;
! 2424: else
! 2425: Prenum1 = Prenum;
! 2426: }
! 2427:
! 2428: curwin->w_set_curswant = TRUE;
! 2429:
! 2430: /* op_empty is set when start and end are the same */
! 2431: op_empty = (op_motion_type == MCHAR && !op_inclusive &&
! 2432: equal(curbuf->b_op_start, curbuf->b_op_end));
! 2433:
! 2434: /*
! 2435: * If the end of an operator is in column one while op_motion_type is
! 2436: * MCHAR and op_inclusive is FALSE, we put op_end after the last character
! 2437: * in the previous line. If op_start is on or before the first non-blank
! 2438: * in the line, the operator becomes linewise (strange, but that's the way
! 2439: * vi does it).
! 2440: */
! 2441: if (op_motion_type == MCHAR && op_inclusive == FALSE &&
! 2442: !dont_adjust_op_end && curbuf->b_op_end.col == 0 &&
! 2443: op_line_count > 1)
! 2444: {
! 2445: op_end_adjusted = TRUE; /* remember that we did this */
! 2446: --op_line_count;
! 2447: --curbuf->b_op_end.lnum;
! 2448: if (inindent(0))
! 2449: op_motion_type = MLINE;
! 2450: else
! 2451: {
! 2452: curbuf->b_op_end.col = STRLEN(ml_get(curbuf->b_op_end.lnum));
! 2453: if (curbuf->b_op_end.col)
! 2454: {
! 2455: --curbuf->b_op_end.col;
! 2456: op_inclusive = TRUE;
! 2457: }
! 2458: }
! 2459: }
! 2460: else
! 2461: op_end_adjusted = FALSE;
! 2462: switch (op_type)
! 2463: {
! 2464: case LSHIFT:
! 2465: case RSHIFT:
! 2466: do_shift(op_type, TRUE, (int)Prenum1);
! 2467: break;
! 2468:
! 2469: case JOIN:
! 2470: if (op_line_count < 2)
! 2471: op_line_count = 2;
! 2472: if (curwin->w_cursor.lnum + op_line_count - 1 >
! 2473: curbuf->b_ml.ml_line_count)
! 2474: beep_flush();
! 2475: else
! 2476: {
! 2477: /*
! 2478: * If the cursor position has been changed, recompute the
! 2479: * current cursor position in the window. If it's not visible,
! 2480: * don't keep the window updated when joining the lines.
! 2481: */
! 2482: if (old_cursor.lnum != curwin->w_cursor.lnum ||
! 2483: old_cursor.col != curwin->w_cursor.col)
! 2484: redraw = (curs_rows() == OK);
! 2485: else
! 2486: redraw = TRUE;
! 2487: do_do_join(op_line_count, TRUE, redraw);
! 2488: }
! 2489: break;
! 2490:
! 2491: case DELETE:
! 2492: if (!op_empty)
! 2493: do_delete();
! 2494: break;
! 2495:
! 2496: case YANK:
! 2497: if (!op_empty)
! 2498: (void)do_yank(FALSE, !gui_yank);
! 2499: break;
! 2500:
! 2501: case CHANGE:
! 2502: *command_busy = do_change(); /* will set op_type to NOP */
! 2503: break;
! 2504:
! 2505: case FILTER:
! 2506: if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
! 2507: AppendToRedobuff((char_u *)"!\r"); /* use any last used !cmd */
! 2508: else
! 2509: bangredo = TRUE; /* do_bang() will put cmd in redo buffer */
! 2510:
! 2511: case INDENT:
! 2512: case COLON:
! 2513:
! 2514: #if defined(LISPINDENT) || defined(CINDENT)
! 2515: /*
! 2516: * If 'equalprg' is empty, do the indenting internally.
! 2517: */
! 2518: if (op_type == INDENT && *p_ep == NUL)
! 2519: {
! 2520: # ifdef LISPINDENT
! 2521: if (curbuf->b_p_lisp)
! 2522: {
! 2523: do_reindent(get_lisp_indent);
! 2524: break;
! 2525: }
! 2526: # endif
! 2527: # ifdef CINDENT
! 2528: do_reindent(get_c_indent);
! 2529: break;
! 2530: # endif
! 2531: }
! 2532: #endif /* defined(LISPINDENT) || defined(CINDENT) */
! 2533:
! 2534: dofilter:
! 2535: if (VIsual_was_active)
! 2536: sprintf((char *)IObuff, ":'<,'>");
! 2537: else
! 2538: sprintf((char *)IObuff, ":%ld,%ld",
! 2539: (long)curbuf->b_op_start.lnum,
! 2540: (long)curbuf->b_op_end.lnum);
! 2541: stuffReadbuff(IObuff);
! 2542: if (op_type != COLON)
! 2543: stuffReadbuff((char_u *)"!");
! 2544: if (op_type == INDENT)
! 2545: {
! 2546: #ifndef CINDENT
! 2547: if (*p_ep == NUL)
! 2548: stuffReadbuff((char_u *)"indent");
! 2549: else
! 2550: #endif
! 2551: stuffReadbuff(p_ep);
! 2552: stuffReadbuff((char_u *)"\n");
! 2553: }
! 2554: else if (op_type == FORMAT || op_type == GFORMAT)
! 2555: {
! 2556: if (*p_fp == NUL)
! 2557: stuffReadbuff((char_u *)"fmt");
! 2558: else
! 2559: stuffReadbuff(p_fp);
! 2560: stuffReadbuff((char_u *)"\n");
! 2561: }
! 2562: /* do_cmdline() does the rest */
! 2563: break;
! 2564:
! 2565: case TILDE:
! 2566: case UPPER:
! 2567: case LOWER:
! 2568: if (!op_empty)
! 2569: do_tilde();
! 2570: break;
! 2571:
! 2572: case FORMAT:
! 2573: case GFORMAT:
! 2574: if (*p_fp != NUL)
! 2575: goto dofilter; /* use external command */
! 2576: do_format(); /* use internal function */
! 2577: break;
! 2578:
! 2579: default:
! 2580: clearopbeep();
! 2581: }
! 2582: prechar = NUL;
! 2583: if (!gui_yank)
! 2584: {
! 2585: /*
! 2586: * if 'sol' not set, go back to old column for some commands
! 2587: */
! 2588: if (!p_sol && op_motion_type == MLINE && (op_type == LSHIFT ||
! 2589: op_type == RSHIFT || op_type == DELETE))
! 2590: coladvance(curwin->w_curswant = old_col);
! 2591: op_type = NOP;
! 2592: }
! 2593: else
! 2594: curwin->w_cursor = old_cursor;
! 2595: op_block_mode = FALSE;
! 2596: yankbuffer = 0;
! 2597: }
! 2598: }
! 2599:
! 2600: #ifdef USE_MOUSE
! 2601: /*
! 2602: * Do the appropriate action for the current mouse click in the current mode.
! 2603: *
! 2604: * Normal Mode:
! 2605: * event modi- position visual change action
! 2606: * fier cursor window
! 2607: * left press - yes end yes
! 2608: * left press C yes end yes "^]" (2)
! 2609: * left press S yes end yes "*" (2)
! 2610: * left drag - yes start if moved no
! 2611: * left relse - yes start if moved no
! 2612: * middle press - yes if not active no put register
! 2613: * middle press - yes if active no yank and put
! 2614: * right press - yes start or extend yes
! 2615: * right press S yes no change yes "#" (2)
! 2616: * right drag - yes extend no
! 2617: * right relse - yes extend no
! 2618: *
! 2619: * Insert or Replace Mode:
! 2620: * event modi- position visual change action
! 2621: * fier cursor window
! 2622: * left press - yes (cannot be active) yes
! 2623: * left press C yes (cannot be active) yes "CTRL-O^]" (2)
! 2624: * left press S yes (cannot be active) yes "CTRL-O*" (2)
! 2625: * left drag - yes start or extend (1) no CTRL-O (1)
! 2626: * left relse - yes start or extend (1) no CTRL-O (1)
! 2627: * middle press - no (cannot be active) no put register
! 2628: * right press - yes start or extend yes CTRL-O
! 2629: * right press S yes (cannot be active) yes "CTRL-O#" (2)
! 2630: *
! 2631: * (1) only if mouse pointer moved since press
! 2632: * (2) only if click is in same buffer
! 2633: *
! 2634: * Return TRUE if start_arrow() should be called for edit mode.
! 2635: */
! 2636: int
! 2637: do_mouse(c, dir, count, fix_indent)
! 2638: int c; /* K_LEFTMOUSE, etc */
! 2639: int dir; /* Direction to 'put' if necessary */
! 2640: long count;
! 2641: int fix_indent; /* Do we fix indent for 'put' if necessary? */
! 2642: {
! 2643: static int ignore_drag_release = FALSE;
! 2644: static FPOS orig_cursor;
! 2645: static int do_always = FALSE; /* ignore 'mouse' setting next time */
! 2646: static int got_click = FALSE; /* got a click some time back */
! 2647:
! 2648: int which_button; /* MOUSE_LEFT, _MIDDLE or _RIGHT */
! 2649: int is_click; /* If FALSE it's a drag or release event */
! 2650: int is_drag; /* If TRUE it's a drag event */
! 2651: int jump_flags = 0; /* flags for jump_to_mouse() */
! 2652: FPOS start_visual;
! 2653: FPOS end_visual;
! 2654: BUF *save_buffer;
! 2655: int diff;
! 2656: int moved; /* Has cursor moved? */
! 2657: int c1, c2;
! 2658: int VIsual_was_active = VIsual_active;
! 2659:
! 2660: /*
! 2661: * When GUI is active, always recognize mouse events, otherwise:
! 2662: * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
! 2663: * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
! 2664: * - For command line and insert mode 'mouse' is checked before calling
! 2665: * do_mouse().
! 2666: */
! 2667: if (do_always)
! 2668: do_always = FALSE;
! 2669: else
! 2670: #ifdef USE_GUI
! 2671: if (!gui.in_use)
! 2672: #endif
! 2673: {
! 2674: if (VIsual_active)
! 2675: {
! 2676: if (!mouse_has(MOUSE_VISUAL))
! 2677: return FALSE;
! 2678: }
! 2679: else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
! 2680: return FALSE;
! 2681: }
! 2682:
! 2683: which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
! 2684:
! 2685: /*
! 2686: * Ignore drag and release events if we didn't get a click.
! 2687: */
! 2688: if (is_click)
! 2689: got_click = TRUE;
! 2690: else
! 2691: {
! 2692: if (!got_click) /* didn't get click, ignore */
! 2693: return FALSE;
! 2694: if (!is_drag) /* release, reset got_click */
! 2695: got_click = FALSE;
! 2696: }
! 2697:
! 2698: /*
! 2699: * ALT is currently ignored
! 2700: */
! 2701: if ((mod_mask & MOD_MASK_ALT))
! 2702: return FALSE;
! 2703:
! 2704: /*
! 2705: * CTRL right mouse button does CTRL-T
! 2706: */
! 2707: if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
! 2708: {
! 2709: if (State & INSERT)
! 2710: stuffcharReadbuff(Ctrl('O'));
! 2711: stuffcharReadbuff(Ctrl('T'));
! 2712: got_click = FALSE; /* ignore drag&release now */
! 2713: return FALSE;
! 2714: }
! 2715:
! 2716: /*
! 2717: * CTRL only works with left mouse button
! 2718: */
! 2719: if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
! 2720: return FALSE;
! 2721:
! 2722: /*
! 2723: * When a modifier is down, ignore drag and release events, as well as
! 2724: * multiple clicks and the middle mouse button.
! 2725: */
! 2726: if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) &&
! 2727: (!is_click || (mod_mask & MOD_MASK_MULTI_CLICK) ||
! 2728: which_button == MOUSE_MIDDLE))
! 2729: return FALSE;
! 2730:
! 2731: /*
! 2732: * If the button press was used as the movement command for an operator
! 2733: * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
! 2734: * drag/release events.
! 2735: */
! 2736: if (!is_click && (ignore_drag_release || which_button == MOUSE_MIDDLE))
! 2737: return FALSE;
! 2738:
! 2739: /*
! 2740: * Middle mouse button does a 'put' of the selected text
! 2741: */
! 2742: if (which_button == MOUSE_MIDDLE)
! 2743: {
! 2744: if (State == NORMAL)
! 2745: {
! 2746: /*
! 2747: * If an operator was pending, we don't know what the user wanted
! 2748: * to do. Go back to normal mode: Clear the operator and beep().
! 2749: */
! 2750: if (op_type != NOP)
! 2751: {
! 2752: clearopbeep();
! 2753: return FALSE;
! 2754: }
! 2755:
! 2756: /*
! 2757: * If visual was active, yank the highlighted text and put it
! 2758: * before the mouse pointer position.
! 2759: */
! 2760: if (VIsual_active)
! 2761: {
! 2762: stuffcharReadbuff('y');
! 2763: stuffcharReadbuff(K_MIDDLEMOUSE);
! 2764: do_always = TRUE; /* ignore 'mouse' setting next time */
! 2765: return FALSE;
! 2766: }
! 2767: /*
! 2768: * The rest is below jump_to_mouse()
! 2769: */
! 2770: }
! 2771:
! 2772: /*
! 2773: * Middle click in insert mode doesn't move the mouse, just insert the
! 2774: * contents of a register. '.' register is special, can't insert that
! 2775: * with do_put().
! 2776: */
! 2777: else if (State & INSERT)
! 2778: {
! 2779: if (yankbuffer == '.')
! 2780: insertbuf(yankbuffer);
! 2781: else
! 2782: {
! 2783: #ifdef USE_GUI
! 2784: if (gui.in_use && yankbuffer == 0)
! 2785: yankbuffer = '*';
! 2786: #endif
! 2787: do_put(BACKWARD, 1L, fix_indent);
! 2788:
! 2789: /* Put cursor after the end of the just pasted text. */
! 2790: curwin->w_cursor = curbuf->b_op_end;
! 2791: if (gchar_cursor() != NUL)
! 2792: ++curwin->w_cursor.col;
! 2793:
! 2794: /* Repeat it with CTRL-R x, not exactly the same, but mostly
! 2795: * works fine. */
! 2796: AppendCharToRedobuff(Ctrl('R'));
! 2797: if (yankbuffer == 0)
! 2798: AppendCharToRedobuff('"');
! 2799: else
! 2800: AppendCharToRedobuff(yankbuffer);
! 2801: }
! 2802: return FALSE;
! 2803: }
! 2804: else
! 2805: return FALSE;
! 2806: }
! 2807:
! 2808: if (!is_click)
! 2809: jump_flags |= MOUSE_FOCUS;
! 2810:
! 2811: start_visual.lnum = 0;
! 2812:
! 2813: if ((State & (NORMAL | INSERT)) &&
! 2814: !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
! 2815: {
! 2816: if (which_button == MOUSE_LEFT)
! 2817: {
! 2818: if (is_click)
! 2819: {
! 2820: if (VIsual_active)
! 2821: {
! 2822: end_visual_mode();
! 2823: update_curbuf(NOT_VALID);
! 2824: }
! 2825: }
! 2826: else
! 2827: jump_flags |= MOUSE_MAY_VIS;
! 2828: }
! 2829: else if (which_button == MOUSE_RIGHT)
! 2830: {
! 2831: if (is_click && VIsual_active)
! 2832: {
! 2833: /*
! 2834: * Remember the start and end of visual before moving the
! 2835: * cursor.
! 2836: */
! 2837: if (lt(curwin->w_cursor, VIsual))
! 2838: {
! 2839: start_visual = curwin->w_cursor;
! 2840: end_visual = VIsual;
! 2841: }
! 2842: else
! 2843: {
! 2844: start_visual = VIsual;
! 2845: end_visual = curwin->w_cursor;
! 2846: }
! 2847: }
! 2848: jump_flags |= MOUSE_MAY_VIS;
! 2849: }
! 2850: }
! 2851:
! 2852: if (!is_drag)
! 2853: {
! 2854: /*
! 2855: * If an operator is pending, ignore all drags and releases until the
! 2856: * next mouse click.
! 2857: */
! 2858: ignore_drag_release = (op_type != NOP);
! 2859: }
! 2860:
! 2861: /*
! 2862: * Jump!
! 2863: */
! 2864: if (!is_click)
! 2865: jump_flags |= MOUSE_DID_MOVE;
! 2866: save_buffer = curbuf;
! 2867: moved = (jump_to_mouse(jump_flags) & CURSOR_MOVED);
! 2868:
! 2869: /* When jumping to another buffer, stop visual mode */
! 2870: if (curbuf != save_buffer && VIsual_active)
! 2871: {
! 2872: end_visual_mode();
! 2873: update_curbuf(NOT_VALID); /* delete the inversion */
! 2874: }
! 2875: else if (start_visual.lnum) /* right click in visual mode */
! 2876: {
! 2877: /*
! 2878: * If the click is before the start of visual, change the start. If
! 2879: * the click is after the end of visual, change the end. If the click
! 2880: * is inside the visual, change the closest side.
! 2881: */
! 2882: if (lt(curwin->w_cursor, start_visual))
! 2883: VIsual = end_visual;
! 2884: else if (lt(end_visual, curwin->w_cursor))
! 2885: VIsual = start_visual;
! 2886: else
! 2887: {
! 2888: /* In the same line, compare column number */
! 2889: if (end_visual.lnum == start_visual.lnum)
! 2890: {
! 2891: if (curwin->w_cursor.col - start_visual.col >
! 2892: end_visual.col - curwin->w_cursor.col)
! 2893: VIsual = start_visual;
! 2894: else
! 2895: VIsual = end_visual;
! 2896: }
! 2897:
! 2898: /* In different lines, compare line number */
! 2899: else
! 2900: {
! 2901: diff = (curwin->w_cursor.lnum - start_visual.lnum) -
! 2902: (end_visual.lnum - curwin->w_cursor.lnum);
! 2903:
! 2904: if (diff > 0) /* closest to end */
! 2905: VIsual = start_visual;
! 2906: else if (diff < 0) /* closest to start */
! 2907: VIsual = end_visual;
! 2908: else /* in the middle line */
! 2909: {
! 2910: if (curwin->w_cursor.col <
! 2911: (start_visual.col + end_visual.col) / 2)
! 2912: VIsual = end_visual;
! 2913: else
! 2914: VIsual = start_visual;
! 2915: }
! 2916: }
! 2917: }
! 2918: }
! 2919: /*
! 2920: * If Visual mode started in insert mode, execute "CTRL-O"
! 2921: */
! 2922: else if ((State & INSERT) && VIsual_active)
! 2923: stuffcharReadbuff(Ctrl('O'));
! 2924: /*
! 2925: * If cursor has moved, need to update Cline_row
! 2926: */
! 2927: else if (moved)
! 2928: cursupdate();
! 2929:
! 2930: /*
! 2931: * Middle mouse click: Put text before cursor.
! 2932: */
! 2933: if (which_button == MOUSE_MIDDLE)
! 2934: {
! 2935: #ifdef USE_GUI
! 2936: if (gui.in_use && yankbuffer == 0)
! 2937: yankbuffer = '*';
! 2938: #endif
! 2939: if (yank_buffer_mline())
! 2940: {
! 2941: if (mouse_past_bottom)
! 2942: dir = FORWARD;
! 2943: }
! 2944: else if (mouse_past_eol)
! 2945: dir = FORWARD;
! 2946:
! 2947: if (fix_indent)
! 2948: {
! 2949: c1 = (dir == BACKWARD) ? '[' : ']';
! 2950: c2 = 'p';
! 2951: }
! 2952: else
! 2953: {
! 2954: c1 = (dir == FORWARD) ? 'p' : 'P';
! 2955: c2 = NUL;
! 2956: }
! 2957: prep_redo(Prenum, NUL, c1, c2, NUL);
! 2958: /*
! 2959: * Remember where the paste started, so in edit() Insstart can be set
! 2960: * to this position
! 2961: */
! 2962: if (restart_edit)
! 2963: where_paste_started = curwin->w_cursor;
! 2964: do_put(dir, count, fix_indent);
! 2965:
! 2966: /* Put cursor at the end of the just pasted text. */
! 2967: curwin->w_cursor = curbuf->b_op_end;
! 2968: if (restart_edit && gchar_cursor() != NUL)
! 2969: ++curwin->w_cursor.col; /* put cursor after the text */
! 2970: }
! 2971:
! 2972: /*
! 2973: * Ctrl-Mouse click jumps to the tag under the mouse pointer
! 2974: */
! 2975: else if ((mod_mask & MOD_MASK_CTRL))
! 2976: {
! 2977: if (State & INSERT)
! 2978: stuffcharReadbuff(Ctrl('O'));
! 2979: stuffcharReadbuff(Ctrl(']'));
! 2980: ignore_drag_release = TRUE; /* ignore drag and release now */
! 2981: }
! 2982:
! 2983: /*
! 2984: * Shift-Mouse click searches for the next occurrence of the word under
! 2985: * the mouse pointer
! 2986: */
! 2987: else if ((mod_mask & MOD_MASK_SHIFT))
! 2988: {
! 2989: if (State & INSERT)
! 2990: stuffcharReadbuff(Ctrl('O'));
! 2991: if (which_button == MOUSE_LEFT)
! 2992: stuffcharReadbuff('*');
! 2993: else /* MOUSE_RIGHT */
! 2994: stuffcharReadbuff('#');
! 2995: }
! 2996:
! 2997: /* Handle double clicks */
! 2998: else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT)))
! 2999: {
! 3000: if (is_click || !VIsual_active)
! 3001: {
! 3002: if (VIsual_active)
! 3003: orig_cursor = VIsual;
! 3004: else
! 3005: {
! 3006: start_visual_highlight();
! 3007: VIsual = curwin->w_cursor;
! 3008: orig_cursor = VIsual;
! 3009: VIsual_active = TRUE;
! 3010: #ifdef USE_MOUSE
! 3011: setmouse();
! 3012: #endif
! 3013: if (p_smd)
! 3014: redraw_cmdline = TRUE; /* show visual mode later */
! 3015: }
! 3016: if (mod_mask & MOD_MASK_2CLICK)
! 3017: VIsual_mode = 'v';
! 3018: else if (mod_mask & MOD_MASK_3CLICK)
! 3019: VIsual_mode = 'V';
! 3020: else if (mod_mask & MOD_MASK_4CLICK)
! 3021: VIsual_mode = Ctrl('V');
! 3022: }
! 3023: if (mod_mask & MOD_MASK_2CLICK)
! 3024: {
! 3025: if (lt(curwin->w_cursor, orig_cursor))
! 3026: {
! 3027: find_start_of_word(&curwin->w_cursor);
! 3028: find_end_of_word(&VIsual);
! 3029: }
! 3030: else
! 3031: {
! 3032: find_start_of_word(&VIsual);
! 3033: find_end_of_word(&curwin->w_cursor);
! 3034: }
! 3035: curwin->w_set_curswant = TRUE;
! 3036: }
! 3037: if (is_click)
! 3038: {
! 3039: curs_columns(TRUE); /* recompute w_virtcol */
! 3040: update_curbuf(NOT_VALID); /* update the inversion */
! 3041: }
! 3042: }
! 3043: else if (VIsual_active && VIsual_was_active != VIsual_active)
! 3044: VIsual_mode = 'v';
! 3045:
! 3046: return moved;
! 3047: }
! 3048:
! 3049: static void
! 3050: find_start_of_word(pos)
! 3051: FPOS *pos;
! 3052: {
! 3053: char_u *ptr;
! 3054: int cclass;
! 3055:
! 3056: ptr = ml_get(pos->lnum);
! 3057: cclass = get_mouse_class(ptr[pos->col]);
! 3058:
! 3059: /* Can't test pos->col >= 0 because pos->col is unsigned */
! 3060: while (pos->col > 0 && get_mouse_class(ptr[pos->col]) == cclass)
! 3061: pos->col--;
! 3062: if (pos->col != 0 || get_mouse_class(ptr[0]) != cclass)
! 3063: pos->col++;
! 3064: }
! 3065:
! 3066: static void
! 3067: find_end_of_word(pos)
! 3068: FPOS *pos;
! 3069: {
! 3070: char_u *ptr;
! 3071: int cclass;
! 3072:
! 3073: ptr = ml_get(pos->lnum);
! 3074: cclass = get_mouse_class(ptr[pos->col]);
! 3075: while (ptr[pos->col] && get_mouse_class(ptr[pos->col]) == cclass)
! 3076: pos->col++;
! 3077: pos->col--;
! 3078: }
! 3079:
! 3080: static int
! 3081: get_mouse_class(c)
! 3082: int c;
! 3083: {
! 3084: if (c == ' ' || c == '\t')
! 3085: return ' ';
! 3086:
! 3087: if (isidchar(c))
! 3088: return 'a';
! 3089:
! 3090: /*
! 3091: * There are a few special cases where we want certain combinations of
! 3092: * characters to be considered as a single word. These are things like
! 3093: * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc. Otherwise, each
! 3094: * character is in it's own class.
! 3095: */
! 3096: if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
! 3097: return '=';
! 3098: return c;
! 3099: }
! 3100: #endif /* USE_MOUSE */
! 3101:
! 3102: /*
! 3103: * start highlighting for visual mode
! 3104: */
! 3105: void
! 3106: start_visual_highlight()
! 3107: {
! 3108: static int didwarn = FALSE; /* warned for broken inversion */
! 3109:
! 3110: if (!didwarn && set_highlight('v') == FAIL)/* cannot highlight */
! 3111: {
! 3112: EMSG("Warning: terminal cannot highlight");
! 3113: didwarn = TRUE;
! 3114: }
! 3115: }
! 3116:
! 3117: /*
! 3118: * End visual mode. If we are using the GUI, and autoselect is set, then
! 3119: * remember what was selected in case we need to paste it somewhere while we
! 3120: * still own the selection. This function should ALWAYS be called to end
! 3121: * visual mode.
! 3122: */
! 3123: void
! 3124: end_visual_mode()
! 3125: {
! 3126: #ifdef USE_GUI
! 3127: if (gui.in_use)
! 3128: gui_auto_select();
! 3129: #endif
! 3130: VIsual_active = FALSE;
! 3131: #ifdef USE_MOUSE
! 3132: setmouse();
! 3133: #endif
! 3134: VIsual_end = curwin->w_cursor; /* remember for '> mark */
! 3135: if (p_smd)
! 3136: clear_cmdline = TRUE; /* unshow visual mode later */
! 3137: }
! 3138:
! 3139: /*
! 3140: * Find the identifier under or to the right of the cursor. If none is
! 3141: * found and find_type has FIND_STRING, then find any non-white string. The
! 3142: * length of the string is returned, or zero if no string is found. If a
! 3143: * string is found, a pointer to the string is put in *string, but note that
! 3144: * the caller must use the length returned as this string may not be NUL
! 3145: * terminated.
! 3146: */
! 3147: int
! 3148: find_ident_under_cursor(string, find_type)
! 3149: char_u **string;
! 3150: int find_type;
! 3151: {
! 3152: char_u *ptr;
! 3153: int col = 0; /* init to shut up GCC */
! 3154: int i;
! 3155:
! 3156: /*
! 3157: * if i == 0: try to find an identifier
! 3158: * if i == 1: try to find any string
! 3159: */
! 3160: ptr = ml_get_curline();
! 3161: for (i = (find_type & FIND_IDENT) ? 0 : 1; i < 2; ++i)
! 3162: {
! 3163: /*
! 3164: * skip to start of identifier/string
! 3165: */
! 3166: col = curwin->w_cursor.col;
! 3167: while (ptr[col] != NUL &&
! 3168: (i == 0 ? !iswordchar(ptr[col]) : vim_iswhite(ptr[col])))
! 3169: ++col;
! 3170:
! 3171: /*
! 3172: * Back up to start of identifier/string. This doesn't match the
! 3173: * real vi but I like it a little better and it shouldn't bother
! 3174: * anyone.
! 3175: * When FIND_IDENT isn't defined, we backup until a blank.
! 3176: */
! 3177: while (col > 0 && (i == 0 ? iswordchar(ptr[col - 1]) :
! 3178: (!vim_iswhite(ptr[col - 1]) &&
! 3179: (!(find_type & FIND_IDENT) || !iswordchar(ptr[col - 1])))))
! 3180: --col;
! 3181:
! 3182: /*
! 3183: * if we don't want just any old string, or we've found an identifier,
! 3184: * stop searching.
! 3185: */
! 3186: if (!(find_type & FIND_STRING) || iswordchar(ptr[col]))
! 3187: break;
! 3188: }
! 3189: /*
! 3190: * didn't find an identifier or string
! 3191: */
! 3192: if (ptr[col] == NUL || (!iswordchar(ptr[col]) && i == 0))
! 3193: {
! 3194: if (find_type & FIND_STRING)
! 3195: EMSG("No string under cursor");
! 3196: else
! 3197: EMSG("No identifier under cursor");
! 3198: return 0;
! 3199: }
! 3200: ptr += col;
! 3201: *string = ptr;
! 3202: col = 0;
! 3203: while (i == 0 ? iswordchar(*ptr) : (*ptr != NUL && !vim_iswhite(*ptr)))
! 3204: {
! 3205: ++ptr;
! 3206: ++col;
! 3207: }
! 3208: return col;
! 3209: }
! 3210:
! 3211: static void
! 3212: prep_redo(num, pre_char, cmd, c, nchar)
! 3213: long num;
! 3214: int pre_char;
! 3215: int cmd;
! 3216: int c;
! 3217: int nchar;
! 3218: {
! 3219: ResetRedobuff();
! 3220: if (yankbuffer != 0) /* yank from specified buffer */
! 3221: {
! 3222: AppendCharToRedobuff('\"');
! 3223: AppendCharToRedobuff(yankbuffer);
! 3224: }
! 3225: if (num)
! 3226: AppendNumberToRedobuff(num);
! 3227: if (pre_char != NUL)
! 3228: AppendCharToRedobuff(pre_char);
! 3229: AppendCharToRedobuff(cmd);
! 3230: if (c != NUL)
! 3231: AppendCharToRedobuff(c);
! 3232: if (nchar != NUL)
! 3233: AppendCharToRedobuff(nchar);
! 3234: }
! 3235:
! 3236: /*
! 3237: * check for operator active and clear it
! 3238: *
! 3239: * return TRUE if operator was active
! 3240: */
! 3241: static int
! 3242: checkclearop()
! 3243: {
! 3244: if (op_type == NOP)
! 3245: return (FALSE);
! 3246: clearopbeep();
! 3247: return (TRUE);
! 3248: }
! 3249:
! 3250: /*
! 3251: * check for operator or Visual active and clear it
! 3252: *
! 3253: * return TRUE if operator was active
! 3254: */
! 3255: static int
! 3256: checkclearopq()
! 3257: {
! 3258: if (op_type == NOP && !VIsual_active)
! 3259: return (FALSE);
! 3260: clearopbeep();
! 3261: return (TRUE);
! 3262: }
! 3263:
! 3264: static void
! 3265: clearop()
! 3266: {
! 3267: op_type = NOP;
! 3268: yankbuffer = 0;
! 3269: prechar = NUL;
! 3270: }
! 3271:
! 3272: static void
! 3273: clearopbeep()
! 3274: {
! 3275: clearop();
! 3276: beep_flush();
! 3277: }
! 3278:
! 3279: /*
! 3280: * Routines for displaying a partly typed command
! 3281: */
! 3282:
! 3283: static char_u showcmd_buf[SHOWCMD_COLS + 1];
! 3284: static char_u old_showcmd_buf[SHOWCMD_COLS + 1]; /* For push_showcmd() */
! 3285: static int is_showcmd_clear = TRUE;
! 3286:
! 3287: static void display_showcmd __ARGS((void));
! 3288:
! 3289: void
! 3290: clear_showcmd()
! 3291: {
! 3292: if (!p_sc)
! 3293: return;
! 3294:
! 3295: showcmd_buf[0] = NUL;
! 3296:
! 3297: /*
! 3298: * Don't actually display something if there is nothing to clear.
! 3299: */
! 3300: if (is_showcmd_clear)
! 3301: return;
! 3302:
! 3303: display_showcmd();
! 3304: }
! 3305:
! 3306: /*
! 3307: * Add 'c' to string of shown command chars.
! 3308: * Return TRUE if setcursor() has been called.
! 3309: */
! 3310: int
! 3311: add_to_showcmd(c, display_always)
! 3312: int c;
! 3313: int display_always;
! 3314: {
! 3315: char_u *p;
! 3316: int old_len;
! 3317: int extra_len;
! 3318: int overflow;
! 3319:
! 3320: if (!p_sc)
! 3321: return FALSE;
! 3322:
! 3323: p = transchar(c);
! 3324: old_len = STRLEN(showcmd_buf);
! 3325: extra_len = STRLEN(p);
! 3326: overflow = old_len + extra_len - SHOWCMD_COLS;
! 3327: if (overflow > 0)
! 3328: STRCPY(showcmd_buf, showcmd_buf + overflow);
! 3329: STRCAT(showcmd_buf, p);
! 3330:
! 3331: if (!display_always && char_avail())
! 3332: return FALSE;
! 3333:
! 3334: display_showcmd();
! 3335:
! 3336: return TRUE;
! 3337: }
! 3338:
! 3339: /*
! 3340: * Delete 'len' characters from the end of the shown command.
! 3341: */
! 3342: static void
! 3343: del_from_showcmd(len)
! 3344: int len;
! 3345: {
! 3346: int old_len;
! 3347:
! 3348: if (!p_sc)
! 3349: return;
! 3350:
! 3351: old_len = STRLEN(showcmd_buf);
! 3352: if (len > old_len)
! 3353: len = old_len;
! 3354: showcmd_buf[old_len - len] = NUL;
! 3355:
! 3356: if (!char_avail())
! 3357: display_showcmd();
! 3358: }
! 3359:
! 3360: void
! 3361: push_showcmd()
! 3362: {
! 3363: if (p_sc)
! 3364: STRCPY(old_showcmd_buf, showcmd_buf);
! 3365: }
! 3366:
! 3367: void
! 3368: pop_showcmd()
! 3369: {
! 3370: if (!p_sc)
! 3371: return;
! 3372:
! 3373: STRCPY(showcmd_buf, old_showcmd_buf);
! 3374:
! 3375: display_showcmd();
! 3376: }
! 3377:
! 3378: static void
! 3379: display_showcmd()
! 3380: {
! 3381: int len;
! 3382:
! 3383: cursor_off();
! 3384:
! 3385: len = STRLEN(showcmd_buf);
! 3386: if (len == 0)
! 3387: is_showcmd_clear = TRUE;
! 3388: else
! 3389: {
! 3390: screen_msg(showcmd_buf, (int)Rows - 1, sc_col);
! 3391: is_showcmd_clear = FALSE;
! 3392: }
! 3393:
! 3394: /*
! 3395: * clear the rest of an old message by outputing up to SHOWCMD_COLS spaces
! 3396: */
! 3397: screen_msg((char_u *)" " + len, (int)Rows - 1, sc_col + len);
! 3398:
! 3399: setcursor(); /* put cursor back where it belongs */
! 3400: }
! 3401:
! 3402: /*
! 3403: * Implementation of "gd" and "gD" command.
! 3404: */
! 3405: static void
! 3406: do_gd(nchar)
! 3407: int nchar;
! 3408: {
! 3409: int len;
! 3410: char_u *pat;
! 3411: FPOS old_pos;
! 3412: int t;
! 3413: int save_p_ws;
! 3414: int save_p_scs;
! 3415: char_u *ptr;
! 3416:
! 3417: if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 ||
! 3418: (pat = alloc(len + 5)) == NULL)
! 3419: {
! 3420: clearopbeep();
! 3421: return;
! 3422: }
! 3423: sprintf((char *)pat, iswordchar(*ptr) ? "\\<%.*s\\>" :
! 3424: "%.*s", len, ptr);
! 3425: old_pos = curwin->w_cursor;
! 3426: save_p_ws = p_ws;
! 3427: save_p_scs = p_scs;
! 3428: p_ws = FALSE; /* don't wrap around end of file now */
! 3429: p_scs = FALSE; /* don't switch ignorecase off now */
! 3430: fo_do_comments = TRUE;
! 3431:
! 3432: /*
! 3433: * Search back for the end of the previous function.
! 3434: * If this fails, and with "gD", go to line 1.
! 3435: * Search forward for the identifier, ignore comment lines.
! 3436: */
! 3437: if (nchar == 'D' || !findpar(BACKWARD, 1L, '}', FALSE))
! 3438: {
! 3439: setpcmark(); /* Set in findpar() otherwise */
! 3440: curwin->w_cursor.lnum = 1;
! 3441: }
! 3442:
! 3443: while ((t = searchit(&curwin->w_cursor, FORWARD, pat, 1L, 0, RE_LAST))
! 3444: == OK &&
! 3445: get_leader_len(ml_get_curline(), NULL) &&
! 3446: old_pos.lnum > curwin->w_cursor.lnum)
! 3447: ++curwin->w_cursor.lnum;
! 3448: if (t == FAIL || old_pos.lnum <= curwin->w_cursor.lnum)
! 3449: {
! 3450: clearopbeep();
! 3451: curwin->w_cursor = old_pos;
! 3452: }
! 3453: else
! 3454: curwin->w_set_curswant = TRUE;
! 3455:
! 3456: vim_free(pat);
! 3457: p_ws = save_p_ws;
! 3458: p_scs = save_p_scs;
! 3459: fo_do_comments = FALSE;
! 3460: }