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