OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / elvis-tiny / vcmd.c
1 /* vcmd.c */
2
3 /* Author:
4  *      Steve Kirkendall
5  *      14407 SW Teal Blvd. #C
6  *      Beaverton, OR 97005
7  *      kirkenda@cs.pdx.edu
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 && mode == MODE_VI)
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