|
|
1.1 root 1: /* vcmd.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: /* This file contains the functions that handle VI commands */
12:
13:
14: #include "config.h"
15: #include "vi.h"
16: #if MSDOS
17: #include <process.h>
18: #include <string.h>
19: #endif
20: #if TOS
21: #include <osbind.h>
22: #include <string.h>
23: #endif
24: #if OSK
25: # include <stdio.h>
26: #endif
27:
28:
29: /* This function puts the editor in EX mode */
30: MARK v_quit()
31: {
32: move(LINES - 1, 0);
33: mode = MODE_EX;
34: return cursor;
35: }
36:
37: /* This function causes the screen to be redrawn */
38: MARK v_redraw()
39: {
40: redraw(MARK_UNSET, FALSE);
41: return cursor;
42: }
43:
44: /* This function executes a single EX command, and waits for a user keystroke
45: * before returning to the VI screen. If that keystroke is another ':', then
46: * another EX command is read and executed.
47: */
48: /*ARGSUSED*/
49: MARK v_1ex(m, text)
50: MARK m; /* the current line */
51: char *text; /* the first command to execute */
52: {
53: /* run the command. be careful about modes & output */
54: exwrote = (mode == MODE_COLON);
55: doexcmd(text);
56: exrefresh();
57:
58: /* if mode is no longer MODE_VI, then we should quit right away! */
59: if (mode != MODE_VI && mode != MODE_COLON)
60: return cursor;
61:
62: /* The command did some output. Wait for a keystoke. */
63: if (exwrote)
64: {
65: mode = MODE_VI;
66: msg("[Hit <RETURN> to continue]");
67: if (getkey(0) == ':')
68: { mode = MODE_COLON;
69: addch('\n');
70: }
71: else
72: redraw(MARK_UNSET, FALSE);
73: }
74:
75: return cursor;
76: }
77:
78: /* This function undoes the last change */
79: /*ARGSUSED*/
80: MARK v_undo(m)
81: MARK m; /* (ignored) */
82: {
83: if (undo())
84: {
85: redraw(MARK_UNSET, FALSE);
86: }
87: return cursor;
88: }
89:
90: /* This function deletes the character(s) that the cursor is on */
91: MARK v_xchar(m, cnt, cmd)
92: MARK m; /* where to start deletions */
93: long cnt; /* number of chars to delete */
94: int cmd; /* either 'x' or 'X' */
95: {
96: DEFAULT(1);
97:
98: /* for 'X', adjust so chars are deleted *BEFORE* cursor */
99: if (cmd == 'X')
100: {
101: if (markidx(m) < cnt)
102: return MARK_UNSET;
103: m -= cnt;
104: }
105:
106: /* make sure we don't try to delete more thars than there are */
107: pfetch(markline(m));
108: if (markidx(m + cnt) > plen)
109: {
110: cnt = plen - markidx(m);
111: }
112: if (cnt == 0L)
113: {
114: return MARK_UNSET;
115: }
116:
117: /* do it */
118: ChangeText
119: {
120: cut(m, m + cnt);
121: delete(m, m + cnt);
122: }
123: return m;
124: }
125:
126: /* This function defines a mark */
127: /*ARGSUSED*/
128: MARK v_mark(m, count, key)
129: MARK m; /* where the mark will be */
130: long count; /* (ignored) */
131: int key; /* the ASCII label of the mark */
132: {
133: if (key < 'a' || key > 'z')
134: {
135: msg("Marks must be from a to z");
136: }
137: else
138: {
139: mark[key - 'a'] = m;
140: }
141: return m;
142: }
143:
144: /* This function toggles upper & lower case letters */
145: MARK v_ulcase(m, cnt)
146: MARK m; /* where to make the change */
147: long cnt; /* number of chars to flip */
148: {
149: REG char *pos;
150: REG int i, j;
151: static char flip[] =
152: "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ[](){}<>";
153:
154: DEFAULT(1);
155:
156: /* fetch the current version of the line */
157: pfetch(markline(m));
158:
159: /* for each position in the line */
160: for (j = 0, i = markidx(m); j < cnt && ptext[i]; j++, i++)
161: {
162: tmpblk.c[j] = 0;
163:
164: /* one of the standard chars? */
165: for (pos = flip; *pos && *pos != ptext[i]; pos++)
166: {
167: }
168: if (*pos)
169: {
170: tmpblk.c[j] = flip[(int)(pos - flip) ^ 1];
171: }
172: #ifndef NO_DIGRAPH
173: else /* one of the non-standard chars? */
174: {
175: for (pos = o_flipcase; *pos && *pos != ptext[i]; pos++)
176: {
177: }
178: if (*pos)
179: {
180: tmpblk.c[j] = o_flipcase[(int)(pos - o_flipcase) ^ 1];
181: }
182: }
183: #endif
184:
185: /* if nothing special, then don't change it */
186: if (tmpblk.c[j] == 0)
187: {
188: tmpblk.c[j] = ptext[i];
189: }
190: }
191:
192: /* if the new text is different from the old, then change it */
193: if (strncmp(tmpblk.c, &ptext[markidx(m)], j))
194: {
195: ChangeText
196: {
197: tmpblk.c[j] = '\0';
198: change(m, m + j, tmpblk.c);
199: }
200: }
201:
202: return m + j;
203: }
204:
205:
206: MARK v_replace(m, cnt, key)
207: MARK m; /* first char to be replaced */
208: long cnt; /* number of chars to replace */
209: int key; /* what to replace them with */
210: {
211: REG char *text;
212: REG int i;
213:
214: DEFAULT(1);
215:
216: /* map ^M to '\n' */
217: if (key == '\r')
218: {
219: key = '\n';
220: }
221:
222: /* make sure the resulting line isn't too long */
223: if (cnt > BLKSIZE - 2 - markidx(m))
224: {
225: cnt = BLKSIZE - 2 - markidx(m);
226: }
227:
228: /* build a string of the desired character with the desired length */
229: for (text = tmpblk.c, i = cnt; i > 0; i--)
230: {
231: *text++ = key;
232: }
233: *text = '\0';
234:
235: /* make sure cnt doesn't extend past EOL */
236: pfetch(markline(m));
237: key = markidx(m);
238: if (key + cnt > plen)
239: {
240: cnt = plen - key;
241: }
242:
243: /* do the replacement */
244: ChangeText
245: {
246: change(m, m + cnt, tmpblk.c);
247: }
248:
249: if (*tmpblk.c == '\n')
250: {
251: return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
252: }
253: else
254: {
255: return m + cnt - 1;
256: }
257: }
258:
259: MARK v_overtype(m)
260: MARK m; /* where to start overtyping */
261: {
262: MARK end; /* end of a substitution */
263: static long width; /* width of a single-line replace */
264:
265: /* the "doingdot" version of replace is really a substitution */
266: if (doingdot)
267: {
268: /* was the last one really repeatable? */
269: if (width < 0)
270: {
271: msg("Can't repeat a multi-line overtype command");
272: return MARK_UNSET;
273: }
274:
275: /* replacing nothing by nothing? Don't bother */
276: if (width == 0)
277: {
278: return m;
279: }
280:
281: /* replace some chars by repeated text */
282: return v_subst(m, width);
283: }
284:
285: /* Normally, we input starting here, in replace mode */
286: ChangeText
287: {
288: end = input(m, m, WHEN_VIREP);
289: }
290:
291: /* if we ended on the same line we started on, then this
292: * overtype is repeatable via the dot key.
293: */
294: if (markline(end) == markline(m) && end >= m - 1L)
295: {
296: width = end - m + 1L;
297: }
298: else /* it isn't repeatable */
299: {
300: width = -1L;
301: }
302:
303: return end;
304: }
305:
306:
307: /* This function selects which cut buffer to use */
308: /*ARGSUSED*/
309: MARK v_selcut(m, cnt, key)
310: MARK m;
311: long cnt;
312: int key;
313: {
314: cutname(key);
315: return m;
316: }
317:
318: /* This function pastes text from a cut buffer */
319: /*ARGSUSED*/
320: MARK v_paste(m, cnt, cmd)
321: MARK m; /* where to paste the text */
322: long cnt; /* (ignored) */
323: int cmd; /* either 'p' or 'P' */
324: {
325: ChangeText
326: {
327: m = paste(m, cmd == 'p', FALSE);
328: }
329: return m;
330: }
331:
332: /* This function yanks text into a cut buffer */
333: MARK v_yank(m, n)
334: MARK m, n; /* range of text to yank */
335: {
336: cut(m, n);
337: return m;
338: }
339:
340: /* This function deletes a range of text */
341: MARK v_delete(m, n)
342: MARK m, n; /* range of text to delete */
343: {
344: /* illegal to try and delete nothing */
345: if (n <= m)
346: {
347: return MARK_UNSET;
348: }
349:
350: /* Do it */
351: ChangeText
352: {
353: cut(m, n);
354: delete(m, n);
355: }
356: return m;
357: }
358:
359:
360: /* This starts input mode without deleting anything */
361: MARK v_insert(m, cnt, key)
362: MARK m; /* where to start (sort of) */
363: long cnt; /* repeat how many times? */
364: int key; /* what command is this for? {a,A,i,I,o,O} */
365: {
366: int wasdot;
367: long reps;
368: int after; /* are we appending or inserting? */
369:
370: DEFAULT(1);
371:
372: ChangeText
373: {
374: /* tweak the insertion point, based on command key */
375: switch (key)
376: {
377: case 'i':
378: after = FALSE;
379: break;
380:
381: case 'a':
382: pfetch(markline(m));
383: if (plen > 0)
384: {
385: m++;
386: }
387: after = TRUE;
388: break;
389:
390: case 'I':
391: m = m_front(m, 1L);
392: after = FALSE;
393: break;
394:
395: case 'A':
396: pfetch(markline(m));
397: m = (m & ~(BLKSIZE - 1)) + plen;
398: after = TRUE;
399: break;
400:
401: case 'O':
402: m &= ~(BLKSIZE - 1);
403: add(m, "\n");
404: after = FALSE;
405: break;
406:
407: case 'o':
408: m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
409: add(m, "\n");
410: after = FALSE;
411: break;
412: }
413:
414: /* insert the same text once or more */
415: for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
416: {
417: m = input(m, m, WHEN_VIINP);
418: if (after)
419: {
420: m++;
421: }
422: }
423: if (after)
424: {
425: m--;
426: }
427:
428: doingdot = wasdot;
429: }
430:
431: #ifndef CRUNCH
432: # ifndef NO_EXTENSIONS
433: if (key == 'i' && *o_inputmode)
434: {
435: msg("Now in visual command mode! To return to input mode, hit <i>.");
436: }
437: # endif
438: #endif
439:
440: return m;
441: }
442:
443: /* This starts input mode with some text deleted */
444: MARK v_change(m, n)
445: MARK m, n; /* the range of text to change */
446: {
447: int lnmode; /* is this a line-mode change? */
448:
449: /* swap them if they're in reverse order */
450: if (m > n)
451: {
452: MARK tmp;
453: tmp = m;
454: m = n;
455: n = tmp;
456: }
457:
458: /* for line mode, retain the last newline char */
459: lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
460: if (lnmode)
461: {
462: n -= BLKSIZE;
463: pfetch(markline(n));
464: n = (n & ~(BLKSIZE - 1)) + plen;
465: }
466:
467: ChangeText
468: {
469: cut(m, n);
470: m = input(m, n, WHEN_VIINP);
471: }
472:
473: return m;
474: }
475:
476: /* This function replaces a given number of characters with input */
477: MARK v_subst(m, cnt)
478: MARK m; /* where substitutions start */
479: long cnt; /* number of chars to replace */
480: {
481: DEFAULT(1);
482:
483: /* make sure we don't try replacing past EOL */
484: pfetch(markline(m));
485: if (markidx(m) + cnt > plen)
486: {
487: cnt = plen - markidx(m);
488: }
489:
490: /* Go for it! */
491: ChangeText
492: {
493: cut(m, m + cnt);
494: m = input(m, m + cnt, WHEN_VIINP);
495: }
496: return m;
497: }
498:
499: /* This calls the ex "join" command to join some lines together */
500: MARK v_join(m, cnt)
501: MARK m; /* the first line to be joined */
502: long cnt; /* number of other lines to join */
503: {
504: MARK joint; /* where the lines were joined */
505:
506: DEFAULT(1);
507:
508: /* figure out where the joint will be */
509: pfetch(markline(m));
510: joint = (m & ~(BLKSIZE - 1)) + plen;
511:
512: /* join the lines */
513: cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
514: mustredraw = TRUE;
515:
516: /* the cursor should be left at the joint */
517: return joint;
518: }
519:
520: /* This calls the ex shifter command to shift some lines */
521: static MARK shift_help(m, n, excmd)
522: MARK m, n; /* range of lines to shift */
523: CMD excmd; /* which way do we shift? */
524: {
525: /* adjust for inclusive endmarks in ex */
526: n -= BLKSIZE;
527:
528: cmd_shift(m, n, excmd, 0, "");
529: return m;
530: }
531:
532: /* This calls the ex "<" command to shift some lines left */
533: MARK v_lshift(m, n)
534: MARK m, n; /* range of lines to shift */
535: {
536: return shift_help(m, n, CMD_SHIFTL);
537: }
538:
539: /* This calls the ex ">" command to shift some lines right */
540: MARK v_rshift(m, n)
541: MARK m, n; /* range of lines to shift */
542: {
543: return shift_help(m, n, CMD_SHIFTR);
544: }
545:
546: /* This runs some lines through a filter program */
547: MARK v_filter(m, n)
548: MARK m, n; /* range of lines to shift */
549: {
550: char cmdln[100]; /* a shell command line */
551:
552: /* adjust for inclusive endmarks in ex */
553: n -= BLKSIZE;
554:
555: if (vgets('!', cmdln, sizeof(cmdln)) > 0)
556: {
557: filter(m, n, cmdln);
558: }
559:
560: redraw(MARK_UNSET, FALSE);
561: return m;
562: }
563:
564:
565: /* This function runs the ex "file" command to show the file's status */
566: MARK v_status()
567: {
568: cmd_file(cursor, cursor, CMD_FILE, 0, "");
569: return cursor;
570: }
571:
572:
573: /* This function runs the ":&" command to repeat the previous :s// */
574: MARK v_again(m, n)
575: MARK m, n;
576: {
577: cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, "");
578: return cursor;
579: }
580:
581:
582:
583: /* This function switches to the previous file, if possible */
584: MARK v_switch()
585: {
586: if (!*prevorig)
587: msg("No previous file");
588: else
589: { strcpy(tmpblk.c, prevorig);
590: cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
591: }
592: return cursor;
593: }
594:
595: /* This function does a tag search on a keyword */
596: /*ARGSUSED*/
597: MARK v_tag(keyword, m, cnt)
598: char *keyword;
599: MARK m;
600: long cnt;
601: {
602: /* move the cursor to the start of the tag name, where m is */
603: cursor = m;
604:
605: /* perform the tag search */
606: cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
607:
608: return cursor;
609: }
610:
611: #ifndef NO_EXTENSIONS
612: /* This function looks up a keyword by calling the helpprog program */
613: /*ARGSUSED*/
614: MARK v_keyword(keyword, m, cnt)
615: char *keyword;
616: MARK m;
617: long cnt;
618: {
619: int waswarn;
620: char cmdline[130];
621:
622: move(LINES - 1, 0);
623: addstr("---------------------------------------------------------\n");
624: clrtoeol();
625: refresh();
626: sprintf(cmdline, "%s %s", o_keywordprg, keyword);
627: waswarn = *o_warn;
628: *o_warn = FALSE;
629: suspend_curses();
630: if (system(cmdline))
631: {
632: addstr("<<< failed >>>\n");
633: }
634: resume_curses(FALSE);
635: mode = MODE_VI;
636: redraw(MARK_UNSET, FALSE);
637: *o_warn = waswarn;
638:
639: return m;
640: }
641:
642:
643:
644: MARK v_increment(keyword, m, cnt)
645: char *keyword;
646: MARK m;
647: long cnt;
648: {
649: static sign;
650: char newval[12];
651: long atol();
652:
653: DEFAULT(1);
654:
655: /* get one more keystroke, unless doingdot */
656: if (!doingdot)
657: {
658: sign = getkey(0);
659: }
660:
661: /* adjust the number, based on that second keystroke */
662: switch (sign)
663: {
664: case '+':
665: case '#':
666: cnt = atol(keyword) + cnt;
667: break;
668:
669: case '-':
670: cnt = atol(keyword) - cnt;
671: break;
672:
673: case '=':
674: break;
675:
676: default:
677: return MARK_UNSET;
678: }
679: sprintf(newval, "%ld", cnt);
680:
681: ChangeText
682: {
683: change(m, m + strlen(keyword), newval);
684: }
685:
686: return m;
687: }
688: #endif
689:
690:
691: /* This function acts like the EX command "xit" */
692: /*ARGSUSED*/
693: MARK v_xit(m, cnt, key)
694: MARK m; /* ignored */
695: long cnt; /* ignored */
696: int key; /* must be a second 'Z' */
697: {
698: /* if second char wasn't 'Z', fail */
699: if (key != 'Z')
700: {
701: return MARK_UNSET;
702: }
703:
704: /* move the cursor to the bottom of the screen */
705: move(LINES - 1, 0);
706: clrtoeol();
707:
708: /* do the xit command */
709: cmd_xit(m, m, CMD_XIT, FALSE, "");
710:
711: /* return the cursor */
712: return m;
713: }
714:
715:
716: /* This function undoes changes to a single line, if possible */
717: MARK v_undoline(m)
718: MARK m; /* where we hope to undo the change */
719: {
720: /* make sure we have the right line in the buffer */
721: if (markline(m) != U_line)
722: {
723: return MARK_UNSET;
724: }
725:
726: /* fix it */
727: ChangeText
728: {
729: strcat(U_text, "\n");
730: change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text);
731: }
732:
733: /* nothing in the buffer anymore */
734: U_line = -1L;
735:
736: /* return, with the cursor at the front of the line */
737: return m & ~(BLKSIZE - 1);
738: }
739:
740:
741: #ifndef NO_ERRLIST
742: MARK v_errlist(m)
743: MARK m;
744: {
745: cmd_errlist(m, m, CMD_ERRLIST, FALSE, "");
746: return cursor;
747: }
748: #endif
749:
750:
751: #ifndef NO_AT
752: /*ARGSUSED*/
753: MARK v_at(m, cnt, key)
754: MARK m;
755: long cnt;
756: int key;
757: {
758: if (!fromcutbuf(key))
759: {
760: return MARK_UNSET;
761: }
762: return cursor;
763: }
764: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.