Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 930 lines (854 sloc) 23.44 kb
6335386 @mbert Import Elvis 1.8 (written by Steve Kirkendall)
authored
1 /* vi.c */
2
3 /* Author:
4 * Steve Kirkendall
5 * Beaverton, OR 97005
6 * kirkenda@cs.pdx.edu
7 */
8
9
10 #include "config.h"
11 #include "ctype.h"
12 #include "vi.h"
13
14
15
16 /* This array describes what each key does */
17 #define NO_FUNC (MARK (*)())0
18
19 #define NO_ARGS 0
20 #define CURSOR 1
21 #define CURSOR_CNT_KEY 2
22 #define CURSOR_MOVED 3
23 #define CURSOR_EOL 4
24 #define ZERO 5
25 #define DIGIT 6
26 #define CURSOR_TEXT 7
27 #define KEYWORD 8
28 #define CURSOR_KEY 9
29 #define ARGSMASK 0x0f
30 #define C_C_K_REP1 (CURSOR_CNT_KEY | 0x10)
31 #define C_C_K_CUT (CURSOR_CNT_KEY | 0x20)
32 #define C_K_CUT (CURSOR_KEY | 0x20)
33 #define C_C_K_MARK (CURSOR_CNT_KEY | 0x30)
34 #define C_C_K_CHAR (CURSOR_CNT_KEY | 0x40)
35 #ifndef NO_SHOWMODE
36 static int keymodes[] = {0, WHEN_REP1, WHEN_CUT, WHEN_MARK, WHEN_CHAR};
37 # define KEYMODE(args) (keymodes[(args) >> 4])
38 #else
39 # define KEYMODE(args) 0
40 #endif
41
42 static struct keystru
43 {
44 MARK (*func)(); /* the function to run */
45 uchar args; /* description of the args needed */
46 #ifndef NO_VISIBLE
47 short flags;
48 #else
49 uchar flags; /* other stuff */
50 #endif
51 }
52 vikeys[] =
53 {
54 /* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
55 #ifndef NO_EXTENSIONS
56 /* ^A find cursor word */ {m_wsrch, KEYWORD, MVMT|NREL|VIZ},
57 #else
58 /* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
59 #endif
60 /* ^B page backward */ {m_scroll, CURSOR, FRNT|VIZ},
61 /* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
62 /* ^D scroll dn 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
63 /* ^E scroll up */ {m_scroll, CURSOR, NCOL|VIZ},
64 /* ^F page forward */ {m_scroll, CURSOR, FRNT|VIZ},
65 /* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS},
66 /* ^H move left, like h*/ {m_left, CURSOR, MVMT|VIZ},
67 /* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
68 /* ^J move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL},
69 /* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
70 /* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
71 /* ^M mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
72 /* ^N move down */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
73 /* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
74 /* ^P move up */ {m_updnto, CURSOR, MVMT|LNMD|VIZ|INCL|NCOL},
75 /* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
76 /* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ},
77 /* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
78 #ifndef NO_TAGSTACK
79 /* ^T pop tagstack */ {v_pop, CURSOR, NO_FLAGS},
80 #else
81 /* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
82 #endif
83 /* ^U scroll up 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ},
84 /* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
85 /* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
86 /* ^X move to phys col */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
87 /* ^Y scroll down */ {m_scroll, CURSOR, NCOL|VIZ},
88 #ifdef SIGTSTP
89 /* ^Z suspend elvis */ {v_suspend, NO_ARGS, NO_FLAGS},
90 #else
91 /* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
92 #endif
93 /* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
94 /* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
95 /* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS},
96 /* ^^ previous file */ {v_switch, CURSOR, FRNT},
97 /* ^_ move to row */ {m_row, CURSOR, MVMT|NCOL|INCL|VIZ},
98 /* SPC move right,like l*/ {m_right, CURSOR, MVMT|INCL|VIZ},
99 /* ! run thru filter */ {v_filter, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
100 /* " select cut buffer*/ {v_selcut, C_K_CUT, PTMV|VIZ},
101 #ifndef NO_EXTENSIONS
102 /* # increment number */ {v_increment, KEYWORD, SDOT},
103 #else
104 /* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
105 #endif
106 /* $ move to rear */ {m_rear, CURSOR, MVMT|INCL|VIZ},
107 /* % move to match */ {m_match, CURSOR, MVMT|INCL|VIZ},
108 /* & repeat subst */ {v_again, CURSOR_MOVED, SDOT|NCOL|LNMD|INCL},
109 /* ' move to a mark */ {m_tomark, C_C_K_MARK, MVMT|FRNT|NREL|LNMD|INCL|VIZ},
110 #ifndef NO_SENTENCE
111 /* ( mv back sentence */ {m_sentence, CURSOR, MVMT|VIZ},
112 /* ) mv fwd sentence */ {m_sentence, CURSOR, MVMT|VIZ},
113 #else
114 /* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
115 /* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
116 #endif
117 #ifndef NO_ERRLIST
118 /* * errlist */ {v_errlist, CURSOR, FRNT|NREL},
119 #else
120 /* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
121 #endif
122 /* + mv front next ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
123 #ifndef NO_CHARSEARCH
124 /* , reverse [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
125 #else
126 /* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
127 #endif
128 /* - mv front prev ln */ {m_updnto, CURSOR, MVMT|FRNT|LNMD|VIZ|INCL},
129 /* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS},
130 /* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
131 /* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV|VIZ},
132 /* 1 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
133 /* 2 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
134 /* 3 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
135 /* 4 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
136 /* 5 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
137 /* 6 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
138 /* 7 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
139 /* 8 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
140 /* 9 part of count */ {NO_FUNC, DIGIT, PTMV|VIZ},
141 /* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS|VIZ},
142 #ifndef NO_CHARSEARCH
143 /* ; repeat [fFtT] cmd*/ {m__ch, CURSOR, MVMT|INCL|VIZ},
144 #else
145 /* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS|VIZ},
146 #endif
147 /* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
148 /* = preset filter */ {v_reformat, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
149 /* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL|VIZ},
150 /* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL|VIZ},
151 #ifndef NO_AT
152 /* @ execute a cutbuf */ {v_at, C_C_K_CUT, NO_FLAGS},
153 #else
154 /* @ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
155 #endif
156 /* A append at EOL */ {v_insert, CURSOR, SDOT},
157 /* B move back Word */ {m_bword, CURSOR, MVMT|VIZ},
158 /* C change to EOL */ {v_change, CURSOR_EOL, SDOT},
159 /* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT},
160 /* E move end of Word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
161 #ifndef NO_CHARSEARCH
162 /* F move bk to char */ {m_Fch, C_C_K_CHAR, MVMT|INCL|VIZ},
163 #else
164 /* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
165 #endif
166 /* G move to line # */ {m_updnto, CURSOR, MVMT|NREL|LNMD|FRNT|INCL|VIZ},
167 /* H move to row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
168 /* I insert at front */ {v_insert, CURSOR, SDOT},
169 /* J join lines */ {v_join, CURSOR, SDOT},
170 #ifndef NO_EXTENSIONS
171 /* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS},
172 #else
173 /* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
174 #endif
175 /* L move to last row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
176 /* M move to mid row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL},
177 /* N reverse prev srch*/ {m_nsrch, CURSOR, MVMT|NREL|VIZ},
178 /* O insert above line*/ {v_insert, CURSOR, SDOT},
179 /* P paste before */ {v_paste, CURSOR, SDOT},
180 /* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS},
181 /* R overtype */ {v_overtype, CURSOR, SDOT},
182 /* S change line */ {v_change, CURSOR_MOVED, SDOT},
183 #ifndef NO_CHARSEARCH
184 /* T move bk to char */ {m_Tch, C_C_K_CHAR, MVMT|INCL|VIZ},
185 #else
186 /* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
187 #endif
188 /* U undo whole line */ {v_undoline, CURSOR, FRNT},
189 #ifndef NO_VISIBLE
190 /* V start visible */ {v_start, CURSOR, INCL|LNMD|VIZ},
191 #else
192 /* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
193 #endif
194 /* W move forward Word*/ {m_fword, CURSOR, MVMT|INCL|NWRP|VIZ},
195 /* X delete to left */ {v_xchar, CURSOR, SDOT},
196 /* Y yank text */ {v_yank, CURSOR_MOVED, NCOL},
197 /* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS},
198 /* [ move back section*/ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
199 #ifndef NO_POPUP
200 /* \ pop-up menu */ {v_popup, CURSOR_MOVED, VIZ},
201 #else
202 /* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
203 #endif
204 /* ] move fwd section */ {m_paragraph, CURSOR, MVMT|LNMD|NREL|VIZ},
205 /* ^ move to front */ {m_front, CURSOR, MVMT|VIZ},
206 /* _ current line */ {m_updnto, CURSOR, MVMT|LNMD|FRNT|INCL},
207 /* ` move to mark */ {m_tomark, C_C_K_MARK, MVMT|NREL|VIZ},
208 /* a append at cursor */ {v_insert, CURSOR, SDOT},
209 /* b move back word */ {m_bword, CURSOR, MVMT|VIZ},
210 /* c change text */ {v_change, CURSOR_MOVED, SDOT|VIZ},
211 /* d delete op */ {v_delete, CURSOR_MOVED, SDOT|VIZ},
212 /* e move end word */ {m_eword, CURSOR, MVMT|INCL|VIZ},
213 #ifndef NO_CHARSEARCH
214 /* f move fwd for char*/ {m_fch, C_C_K_CHAR, MVMT|INCL|VIZ},
215 #else
216 /* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
217 #endif
218 /* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
219 /* h move left */ {m_left, CURSOR, MVMT|VIZ},
220 /* i insert at cursor */ {v_insert, CURSOR, SDOT},
221 /* j move down */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
222 /* k move up */ {m_updnto, CURSOR, MVMT|NCOL|LNMD|VIZ|INCL},
223 /* l move right */ {m_right, CURSOR, MVMT|INCL|VIZ},
224 /* m define a mark */ {v_mark, C_C_K_MARK, NO_FLAGS},
225 /* n repeat prev srch */ {m_nsrch, CURSOR, MVMT|NREL|VIZ},
226 /* o insert below line*/ {v_insert, CURSOR, SDOT},
227 /* p paste after */ {v_paste, CURSOR, SDOT},
228 /* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
229 /* r replace chars */ {v_replace, C_C_K_REP1, SDOT},
230 /* s subst N chars */ {v_subst, CURSOR, SDOT},
231 #ifndef NO_CHARSEARCH
232 /* t move fwd to char */ {m_tch, C_C_K_CHAR, MVMT|INCL|VIZ},
233 #else
234 /* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
235 #endif
236 /* u undo */ {v_undo, CURSOR, NO_FLAGS},
237 #ifndef NO_VISIBLE
238 /* v start visible */ {v_start, CURSOR, INCL|VIZ},
239 #else
240 /* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
241 #endif
242 /* w move fwd word */ {m_fword, CURSOR, MVMT|INCL|NWRP|VIZ},
243 /* x delete character */ {v_xchar, CURSOR, SDOT},
244 /* y yank text */ {v_yank, CURSOR_MOVED, NCOL|VIZ},
245 /* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL|VIZ},
246 /* { back paragraph */ {m_paragraph, CURSOR, MVMT|VIZ},
247 /* | move to column */ {m_tocol, CURSOR, MVMT|NREL|VIZ},
248 /* } fwd paragraph */ {m_paragraph, CURSOR, MVMT|VIZ},
249 /* ~ upper/lowercase */ {v_ulcase, CURSOR, SDOT},
250 /* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}
251 };
252
253
254
255 void vi()
256 {
257 REG int key; /* keystroke from user */
258 long count; /* numeric argument to some functions */
259 REG struct keystru *keyptr;/* pointer to vikeys[] element */
260 MARK tcurs; /* temporary cursor */
261 int prevkey;/* previous key, if d/c/y/</>/! */
262 MARK range; /* start of range for d/c/y/</>/! */
263 char text[132];
264 char *tptr;
265 int dotkey; /* last "key" of a change */
266 int dotpkey;/* last "prevkey" of a change */
267 int dotkey2;/* last extra "getkey()" of a change */
268 int dotcnt; /* last "count" of a change */
269 int firstkey;
270 REG int i;
271
272 /* tell the redraw() function to start from scratch */
273 redraw(MARK_UNSET, FALSE);
274
275 #ifdef lint
276 /* lint says that "range" might be used before it is set. This
277 * can't really happen due to the way "range" and "prevkey" are used,
278 * but lint doesn't know that. This line is here ONLY to keep lint
279 * happy.
280 */
281 range = 0L;
282 #endif
283
284 /* safeguard against '.' with no previous command */
285 dotkey = dotpkey = dotkey2 = dotcnt = 0;
286
287 /* go immediately into insert mode, if ":set inputmode" */
288 firstkey = 0;
289 #ifndef NO_EXTENSIONS
290 if (*o_inputmode)
291 {
292 firstkey = 'i';
293 }
294 #endif
295
296 /* Repeatedly handle VI commands */
297 for (count = 0, prevkey = '\0'; mode == MODE_VI; )
298 {
299 /* if we've moved off the undoable line, then we can't undo it at all */
300 if (markline(cursor) != U_line)
301 {
302 U_line = 0L;
303 }
304
305 /* report any changes from the previous command */
306 if (rptlines >= *o_report)
307 {
308 redraw(cursor, FALSE);
309 msg("%ld line%s %s", rptlines, (rptlines==1?"":"s"), rptlabel);
310 }
311 rptlines = 0L;
312
313 /* get the next command key. It must be ASCII */
314 if (firstkey)
315 {
316 key = firstkey;
317 firstkey = 0;
318 }
319 else
320 {
321 do
322 {
323 key = getkey(WHEN_VICMD);
324 } while (key < 0 || key > 127);
325 }
326 #ifdef DEBUG2
327 debout("\nkey='%c'\n", key);
328 #endif
329
330 #if ANY_UNIX
331 /* intercept mouse events from an xterm */
332 if (!strcmp(o_term, "xterm") && key == '\021')
333 {
334 /* read the next three characters */
335 text[0] = getkey(0);
336 text[1] = getkey(0);
337 text[2] = getkey(0);
338
339 /* valid-looking characters? */
340 if (text[0] >= ' ' && text[0] <= '#'
341 && (text[1] & 0xff) > ' '
342 && (text[2] & 0xff) > ' ')
343 {
344 /* force the cursor to the proper row */
345 cursor = MARK_AT_LINE(topline + (text[2] & 0xff) - '!');
346 if (cursor > MARK_LAST)
347 {
348 cursor = MARK_LAST;
349 }
350
351 /* simulate a column positioning command */
352 count = (text[1] & 0xff) - ' ';
353 key = '\030'; /* ^X, the column command */
354 }
355 else
356 {
357 /* cancel it */
358 key = '\033'; /* ESC */
359 }
360 }
361 #endif /* ANY_UNIX (xterm support) */
362
363 /* Convert a doubled-up operator such as "dd" into "d_" */
364 if (prevkey && key == prevkey)
365 {
366 key = '_';
367 }
368
369 #ifndef NO_VISIBLE
370 /* If not in the middle of a command, <Esc> cancels <v> */
371 if (!count && !prevkey && V_from && key == '\033')
372 {
373 key = 'v';
374 }
375 #endif
376
377 /* look up the structure describing this command */
378 keyptr = &vikeys[key];
379
380 /* '&' and uppercase operators always act like doubled */
381 if (!prevkey && keyptr->args == CURSOR_MOVED
382 && (key == '&' || isupper(key)))
383 {
384 range = cursor;
385 prevkey = key;
386 key = '_';
387 keyptr = &vikeys[key];
388 }
389
390 #ifndef NO_VISIBLE
391 /* if we're in the middle of a v/V command, reject commands
392 * that aren't operators or movement commands
393 */
394 if (V_from && !(keyptr->flags & VIZ))
395 {
396 beep();
397 prevkey = 0;
398 count = 0;
399 continue;
400 }
401 #endif
402
403 /* if we're in the middle of a d/c/y/</>/! command, reject
404 * anything but movement.
405 */
406 if (prevkey && !(keyptr->flags & (MVMT|PTMV)))
407 {
408 beep();
409 prevkey = 0;
410 count = 0;
411 continue;
412 }
413
414 /* set the "dot" variables, if we're supposed to */
415 if (((keyptr->flags & SDOT)
416 || (prevkey && vikeys[prevkey].flags & SDOT))
417 #ifndef NO_VISIBLE
418 && !V_from
419 #endif
420 )
421 {
422 dotkey = key;
423 dotpkey = prevkey;
424 dotkey2 = '\0';
425 dotcnt = count;
426
427 /* remember the line before any changes are made */
428 if (U_line != markline(cursor))
429 {
430 U_line = markline(cursor);
431 strcpy(U_text, fetchline(U_line));
432 }
433 }
434
435 /* if this is "." then set other vars from the "dot" vars */
436 if (key == '.')
437 {
438 key = dotkey;
439 keyptr = &vikeys[key];
440 prevkey = dotpkey;
441 if (prevkey)
442 {
443 range = cursor;
444 }
445 if (count == 0)
446 {
447 count = dotcnt;
448 }
449 else
450 {
451 dotcnt = count;
452 }
453 doingdot = TRUE;
454
455 /* remember the line before any changes are made */
456 if (U_line != markline(cursor))
457 {
458 U_line = markline(cursor);
459 strcpy(U_text, fetchline(U_line));
460 }
461 }
462 else
463 {
464 doingdot = FALSE;
465 }
466
467 /* process the key as a command */
468 tcurs = cursor;
469 force_flags = NO_FLAGS;
470 switch (keyptr->args & ARGSMASK)
471 {
472 case ZERO:
473 if (count == 0)
474 {
475 tcurs = cursor & ~(BLKSIZE - 1);
476 break;
477 }
478 /* else fall through & treat like other digits... */
479
480 case DIGIT:
481 count = count * 10 + key - '0';
482 break;
483
484 case KEYWORD:
485 /* Get word. If not on a word, fail */
486 tptr = get_cursor_word(cursor);
487 if (!tptr)
488 {
489 tcurs = MARK_UNSET;
490 break;
491 }
492
493 /* call the function */
494 tcurs = (*keyptr->func)(tptr, tcurs, count);
495 count = 0L;
496 break;
497
498 case NO_ARGS:
499 if (keyptr->func)
500 {
501 (*keyptr->func)();
502 }
503 else
504 {
505 beep();
506 }
507 count = 0L;
508 break;
509
510 case CURSOR:
511 tcurs = (*keyptr->func)(cursor, count, key, prevkey);
512 count = 0L;
513 break;
514
515 case CURSOR_CNT_KEY:
516 case CURSOR_KEY:
517 if (doingdot)
518 {
519 tcurs = (*keyptr->func)(cursor, count, dotkey2);
520 }
521 else
522 {
523 /* get a key */
524 i = getkey(KEYMODE(keyptr->args));
525 if (i == '\033') /* ESC */
526 {
527 count = 0;
528 tcurs = MARK_UNSET;
529 break; /* exit from "case CURSOR_CNT_KEY" */
530 }
531 else if (i == ctrl('V'))
532 {
533 i = getkey(0);
534 }
535
536 /* if part of an SDOT command, remember it */
537 if (keyptr->flags & SDOT
538 || (prevkey && vikeys[prevkey].flags & SDOT))
539 {
540 dotkey2 = i;
541 }
542
543 /* do it */
544 tcurs = (*keyptr->func)(cursor, count, i);
545 }
546 if ((keyptr->args & ARGSMASK) == CURSOR_CNT_KEY)
547 {
548 count = 0L;
549 }
550 break;
551
552 case CURSOR_MOVED:
553 #ifndef NO_VISIBLE
554 if (V_from)
555 {
556 range = cursor;
557 tcurs = V_from;
558 count = 0L;
559 prevkey = key;
560 key = (V_linemd ? 'V' : 'v');
561 keyptr = &vikeys[key];
562 }
563 else
564 #endif
565 {
566 prevkey = key;
567 range = cursor;
568 force_flags = LNMD|INCL;
569 }
570 break;
571
572 case CURSOR_EOL:
573 prevkey = key;
574 /* a zero-length line needs special treatment */
575 pfetch(markline(cursor));
576 if (plen == 0)
577 {
578 /* act on a zero-length section of text */
579 range = tcurs = cursor;
580 key = '0';
581 }
582 else
583 {
584 /* act like CURSOR_MOVED with '$' movement */
585 range = cursor;
586 tcurs = m_rear(cursor, 1L);
587 key = '$';
588 }
589 count = 0L;
590 keyptr = &vikeys[key];
591 break;
592
593 case CURSOR_TEXT:
594 do
595 {
596 text[0] = key;
597 text[1] = '\0';
598 if (doingdot || vgets(key, text + 1, sizeof text - 1) >= 0)
599 {
600 /* reassure user that <CR> was hit */
601 qaddch('\r');
602 refresh();
603
604 /* call the function with the text */
605 tcurs = (*keyptr->func)(cursor, text);
606 }
607 else
608 {
609 if (exwrote || mode == MODE_COLON)
610 {
611 redraw(MARK_UNSET, FALSE);
612 }
613 mode = MODE_VI;
614 }
615 } while (mode == MODE_COLON);
616 count = 0L;
617 break;
618 }
619
620 /* if that command took us out of vi mode, then exit the loop
621 * NOW, without tweaking the cursor or anything. This is very
622 * important when mode == MODE_QUIT.
623 */
624 if (mode != MODE_VI)
625 {
626 break;
627 }
628
629 /* now move the cursor, as appropriate */
630 if (prevkey && ((keyptr->flags & MVMT)
631 #ifndef NO_VISIBLE
632 || V_from
633 #endif
634 ) && count == 0L)
635 {
636 /* movements used as targets are less strict */
637 tcurs = adjmove(cursor, tcurs, (int)(keyptr->flags | force_flags));
638 }
639 else if (keyptr->args == CURSOR_MOVED)
640 {
641 /* the < and > keys have FRNT,
642 * but it shouldn't be applied yet
643 */
644 tcurs = adjmove(cursor, tcurs, FINL);
645 }
646 else
647 {
648 tcurs = adjmove(cursor, tcurs, (int)(keyptr->flags | force_flags | FINL));
649 }
650
651 /* was that the end of a d/c/y/</>/! command? */
652 if (prevkey && ((keyptr->flags & MVMT)
653 #ifndef NO_VISIBLE
654 || V_from
655 #endif
656 ) && count == 0L)
657 {
658 #ifndef NO_VISIBLE
659 /* turn off the hilight */
660 V_from = 0L;
661 #endif
662
663 /* if the movement command failed, cancel operation */
664 if (tcurs == MARK_UNSET)
665 {
666 prevkey = 0;
667 count = 0;
668 continue;
669 }
670
671 /* make sure range=front and tcurs=rear. Either way,
672 * leave cursor=range since that's where we started.
673 */
674 cursor = range;
675 if (tcurs < range)
676 {
677 range = tcurs;
678 tcurs = cursor;
679 }
680
681 /* The 'w' and 'W' destinations should never take us
682 * to the front of a line. Instead, they should take
683 * us only to the end of the preceding line.
684 */
685 if ((keyptr->flags & NWRP) == NWRP
686 && markline(range) < markline(tcurs)
687 && (markline(tcurs) > nlines || tcurs == m_front(tcurs, 0L)))
688 {
689 tcurs = (tcurs & ~(BLKSIZE - 1)) - BLKSIZE;
690 pfetch(markline(tcurs));
691 tcurs += plen;
692 }
693
694 /* adjust for line mode & inclusion of last char/line */
695 i = (keyptr->flags | vikeys[prevkey].flags);
696 switch ((i | force_flags) & (INCL|LNMD))
697 {
698 case INCL:
699 tcurs++;
700 break;
701
702 case INCL|LNMD:
703 tcurs += BLKSIZE;
704 range &= ~(BLKSIZE - 1);
705 tcurs &= ~(BLKSIZE - 1);
706 break;
707
708 case LNMD:
709 tcurs--; /* if at column 0, go to prev line */
710 range &= ~(BLKSIZE - 1);
711 tcurs &= ~(BLKSIZE - 1);
712 break;
713 }
714
715 /* run the function */
716 tcurs = (*vikeys[prevkey].func)(range, tcurs);
717 if (mode == MODE_VI)
718 {
719 (void)adjmove(cursor, cursor, FINL);
720 cursor = adjmove(cursor, tcurs, (int)(vikeys[prevkey].flags | FINL));
721 }
722
723 /* cleanup */
724 prevkey = 0;
725 }
726 else if (!prevkey)
727 {
728 if (tcurs != MARK_UNSET)
729 cursor = tcurs;
730 }
731 }
732 }
733
734 /* locate the work at the cursor, and return a pointer to a static character
735 * buffer containing that word (nul-terminated). If the cursor isn't on a
736 * word, then return NULL.
737 */
738 char *get_cursor_word(curs)
739 MARK curs;
740 {
741 static char text[132];
742 int i, j;
743
744 /* if not on a keyword, fail */
745 pfetch(markline(curs));
746 i = markidx(curs);
747 if (!isalnum(ptext[i]))
748 {
749 return (char *)0;
750 }
751
752 /* find the start of the keyword */
753 while (i > 0 && isalnum(ptext[i - 1]))
754 {
755 i--;
756 }
757
758 /* copy it into a buffer, and NUL-terminate it */
759 j = 0;
760 do
761 {
762 text[j++] = ptext[i++];
763 } while (isalnum(ptext[i]));
764 text[j] = '\0';
765
766 return text;
767 }
768
769
770 /* This function adjusts the MARK value that they return; here we make sure
771 * it isn't past the end of the line, and that the column hasn't been
772 * *accidentally* changed.
773 */
774 MARK adjmove(old, new, flags)
775 MARK old; /* the cursor position before the command */
776 REG MARK new; /* the cursor position after the command */
777 int flags; /* various flags regarding cursor mvmt */
778 {
779 static int colno; /* the column number that we want */
780 REG char *text; /* used to scan through the line's text */
781 REG int i;
782
783 #ifdef DEBUG2
784 debout("adjmove(%ld.%d, %ld.%d, 0x%x)\n", markline(old), markidx(old), markline(new), markidx(new), flags);
785 #endif
786 #ifdef DEBUG
787 watch();
788 #endif
789
790 /* if the command failed, bag it! */
791 if (new == MARK_UNSET)
792 {
793 if (flags & FINL)
794 {
795 beep();
796 return old;
797 }
798 return new;
799 }
800
801 /* if this is a non-relative movement, set the '' mark */
802 if (flags & NREL)
803 {
804 mark[26] = old;
805 }
806
807 /* make sure it isn't past the end of the file */
808 if (markline(new) < 1)
809 {
810 new = MARK_FIRST;
811 }
812 else if (markline(new) > nlines)
813 {
814 if (!(flags & FINL))
815 {
816 return MARK_EOF;
817 }
818 new = MARK_LAST; /* !!! or MARK_EOF? */
819 }
820
821 /* fetch the new line */
822 pfetch(markline(new));
823
824 /* move to the front, if we're supposed to */
825 if (flags & FRNT)
826 {
827 new = m_front(new, 1L);
828 }
829
830 /* change the column#, or change the mark to suit the column# */
831 if (!(flags & NCOL))
832 {
833 /* change the column# */
834 i = markidx(new);
835 if (i == BLKSIZE - 1)
836 {
837 new &= ~(BLKSIZE - 1);
838 if (plen > 0)
839 {
840 new += plen;
841 if (!(flags & INPM))
842 {
843 new--;
844 }
845 }
846 colno = BLKSIZE * 8; /* one heck of a big colno */
847 }
848 else if (plen > 0)
849 {
850 if (i >= plen)
851 {
852 new = (new & ~(BLKSIZE - 1)) + plen;
853 #ifndef NO_EXTENSIONS
854 if (!(flags & INPM))
855 #endif
856 {
857 new--;
858 }
859 }
860 colno = idx2col(new, ptext, FALSE);
861 }
862 else
863 {
864 new &= ~(BLKSIZE - 1);
865 colno = 0;
866 }
867 }
868 else
869 {
870 /* adjust the mark to get as close as possible to column# */
871 for (i = 0, text = ptext; i <= colno && *text; text++)
872 {
873 if (*text == '\t' && !*o_list)
874 {
875 i += *o_tabstop - (i % *o_tabstop);
876 }
877 else if (UCHAR(*text) < ' ' || *text == 127)
878 {
879 i += 2;
880 }
881 #ifndef NO_CHARATTR
882 else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
883 {
884 text += 2; /* plus one more in "for()" stmt */
885 }
886 #endif
887 else
888 {
889 i++;
890 }
891 }
892
893 if (text > ptext && !(i <= colno && (flags & INPM)))
894 {
895 text--;
896 }
897 new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
898 }
899
900 return new;
901 }
902
903
904 #ifdef DEBUG
905 watch()
906 {
907 static wasset;
908
909 if (*origname)
910 {
911 wasset = TRUE;
912 }
913 else if (wasset)
914 {
915 mode = MODE_EX;
916 msg("origname was clobbered");
917 endwin();
918 abort();
919 }
920
921 if (wasset && nlines == 0)
922 {
923 mode = MODE_EX;
924 msg("nlines=0");
925 endwin();
926 abort();
927 }
928 }
929 #endif
Something went wrong with that request. Please try again.