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