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