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