5 * 14407 SW Teal Blvd. #C
11 /* This file contains the functions that handle VI commands */
30 /* This function puts the editor in EX mode */
38 /* This function causes the screen to be redrawn */
41 redraw(MARK_UNSET
, FALSE
);
45 /* This function executes a string of EX commands, and waits for a user keystroke
46 * before returning to the VI screen. If that keystroke is another ':', then
47 * another EX command is read and executed.
51 MARK m
; /* the current line */
52 char *text
; /* the first command to execute */
54 /* run the command. be careful about modes & output */
55 exwrote
= (mode
== MODE_COLON
);
59 /* if mode is no longer MODE_VI, then we should quit right away! */
60 if (mode
!= MODE_VI
&& mode
!= MODE_COLON
)
63 /* The command did some output. Wait for a keystoke. */
67 msg("[Hit <RETURN> to continue]");
73 redraw(MARK_UNSET
, FALSE
);
79 /* This function undoes the last change */
82 MARK m
; /* (ignored) */
86 redraw(MARK_UNSET
, FALSE
);
91 /* This function deletes the character(s) that the cursor is on */
92 MARK
v_xchar(m
, cnt
, cmd
)
93 MARK m
; /* where to start deletions */
94 long cnt
; /* number of chars to delete */
95 int cmd
; /* either 'x' or 'X' */
99 /* for 'X', adjust so chars are deleted *BEFORE* cursor */
102 if (markidx(m
) < cnt
)
107 /* make sure we don't try to delete more thars than there are */
109 if (markidx(m
+ cnt
) > plen
)
111 cnt
= plen
- markidx(m
);
127 /* This function defines a mark */
129 MARK
v_mark(m
, count
, key
)
130 MARK m
; /* where the mark will be */
131 long count
; /* (ignored) */
132 int key
; /* the ASCII label of the mark */
134 if (key
< 'a' || key
> 'z')
136 msg("Marks must be from a to z");
145 /* This function toggles upper & lower case letters */
146 MARK
v_ulcase(m
, cnt
)
147 MARK m
; /* where to make the change */
148 long cnt
; /* number of chars to flip */
155 /* fetch the current version of the line */
158 /* for each position in the line */
159 for (j
= 0, pos
= &ptext
[markidx(m
)]; j
< cnt
&& *pos
; j
++, pos
++)
163 tmpblk
.c
[j
] = tolower(*pos
);
167 tmpblk
.c
[j
] = toupper(*pos
);
171 /* if the new text is different from the old, then change it */
172 if (strncmp(tmpblk
.c
, &ptext
[markidx(m
)], j
))
177 change(m
, m
+ j
, tmpblk
.c
);
185 MARK
v_replace(m
, cnt
, key
)
186 MARK m
; /* first char to be replaced */
187 long cnt
; /* number of chars to replace */
188 int key
; /* what to replace them with */
201 /* make sure the resulting line isn't too long */
202 if (cnt
> BLKSIZE
- 2 - markidx(m
))
204 cnt
= BLKSIZE
- 2 - markidx(m
);
207 /* build a string of the desired character with the desired length */
208 for (text
= tmpblk
.c
, i
= cnt
; i
> 0; i
--)
214 /* make sure cnt doesn't extend past EOL */
217 if (key
+ cnt
> plen
)
222 /* do the replacement */
225 change(m
, m
+ cnt
, tmpblk
.c
);
228 if (*tmpblk
.c
== '\n')
230 return (m
& ~(BLKSIZE
- 1)) + cnt
* BLKSIZE
;
239 MARK m
; /* where to start overtyping */
241 MARK end
; /* end of a substitution */
242 static long width
; /* width of a single-line replace */
244 /* the "doingdot" version of replace is really a substitution */
247 /* was the last one really repeatable? */
250 msg("Can't repeat a multi-line overtype command");
254 /* replacing nothing by nothing? Don't bother */
260 /* replace some chars by repeated text */
261 return v_subst(m
, width
);
264 /* Normally, we input starting here, in replace mode */
267 end
= input(m
, m
, WHEN_VIREP
, FALSE
);
270 /* if we ended on the same line we started on, then this
271 * overtype is repeatable via the dot key.
273 if (markline(end
) == markline(m
) && end
>= m
- 1L)
275 width
= end
- m
+ 1L;
277 else /* it isn't repeatable */
286 /* This function selects which cut buffer to use */
288 MARK
v_selcut(m
, cnt
, key
)
297 /* This function pastes text from a cut buffer */
299 MARK
v_paste(m
, cnt
, cmd
)
300 MARK m
; /* where to paste the text */
301 long cnt
; /* (ignored) */
302 int cmd
; /* either 'p' or 'P' */
308 /* paste the text, and find out where it ends */
309 dest
= paste(m
, cmd
== 'p', TRUE
);
311 /* was that a line-mode paste? */
312 if (dest
&& markline(dest
) != markline(m
))
314 /* line-mode pastes leave the cursor at the front
315 * of the first pasted line.
328 /* This function yanks text into a cut buffer */
330 MARK m
, n
; /* range of text to yank */
336 /* This function deletes a range of text */
338 MARK m
, n
; /* range of text to delete */
340 /* illegal to try and delete nothing */
356 /* This starts input mode without deleting anything */
357 MARK
v_insert(m
, cnt
, key
)
358 MARK m
; /* where to start (sort of) */
359 long cnt
; /* repeat how many times? */
360 int key
; /* what command is this for? {a,A,i,I,o,O} */
364 int above
; /* boolean: new line going above old line? */
370 /* tweak the insertion point, based on command key */
391 m
= (m
& ~(BLKSIZE
- 1)) + plen
;
401 m
= (m
& ~(BLKSIZE
- 1)) + BLKSIZE
;
406 /* insert the same text once or more */
407 for (reps
= cnt
, wasdot
= doingdot
; reps
> 0; reps
--, doingdot
= TRUE
)
409 m
= input(m
, m
, WHEN_VIINP
, above
) + 1;
420 # ifndef NO_EXTENSIONS
421 if (key
== 'i' && *o_inputmode
&& mode
== MODE_VI
)
423 msg("Now in command mode! To return to input mode, hit <i>");
431 /* This starts input mode with some text deleted */
433 MARK m
, n
; /* the range of text to change */
435 int lnmode
; /* is this a line-mode change? */
437 /* swap them if they're in reverse order */
446 /* for line mode, retain the last newline char */
447 lnmode
= (markidx(m
) == 0 && markidx(n
) == 0 && m
!= n
);
452 n
= (n
& ~(BLKSIZE
- 1)) + plen
;
458 m
= input(m
, n
, WHEN_VIINP
, FALSE
);
464 /* This function replaces a given number of characters with input */
466 MARK m
; /* where substitutions start */
467 long cnt
; /* number of chars to replace */
471 /* make sure we don't try replacing past EOL */
473 if (markidx(m
) + cnt
> plen
)
475 cnt
= plen
- markidx(m
);
482 m
= input(m
, m
+ cnt
, WHEN_VIINP
, FALSE
);
487 /* This calls the ex "join" command to join some lines together */
489 MARK m
; /* the first line to be joined */
490 long cnt
; /* number of other lines to join */
492 MARK joint
; /* where the lines were joined */
496 /* figure out where the joint will be */
498 joint
= (m
& ~(BLKSIZE
- 1)) + plen
;
501 cmd_join(m
, m
+ MARK_AT_LINE(cnt
), CMD_JOIN
, 0, "");
503 /* the cursor should be left at the joint */
508 /* This calls the ex "<" command to shift some lines left */
510 MARK m
, n
; /* range of lines to shift */
512 /* adjust for inclusive endmarks in ex */
515 cmd_shift(m
, n
, CMD_SHIFTL
, FALSE
, (char *)0);
520 /* This calls the ex ">" command to shift some lines right */
522 MARK m
, n
; /* range of lines to shift */
524 /* adjust for inclusive endmarks in ex */
527 cmd_shift(m
, n
, CMD_SHIFTR
, FALSE
, (char *)0);
532 /* This filters some lines through a preset program, to reformat them */
533 MARK
v_reformat(m
, n
)
534 MARK m
, n
; /* range of lines to shift */
536 /* adjust for inclusive endmarks in ex */
539 /* run the filter command */
540 filter(m
, n
, o_equalprg
, TRUE
);
542 redraw(MARK_UNSET
, FALSE
);
547 /* This runs some lines through a filter program */
549 MARK m
, n
; /* range of lines to shift */
551 char cmdln
[150]; /* a shell command line */
553 /* adjust for inclusive endmarks in ex */
556 if (vgets('!', cmdln
, sizeof(cmdln
)) > 0)
558 filter(m
, n
, cmdln
, TRUE
);
561 redraw(MARK_UNSET
, FALSE
);
566 /* This function runs the ex "file" command to show the file's status */
569 cmd_file(cursor
, cursor
, CMD_FILE
, 0, "");
574 /* This function runs the ":&" command to repeat the previous :s// */
578 cmd_substitute(m
, n
- BLKSIZE
, CMD_SUBAGAIN
, TRUE
, "");
584 /* This function switches to the previous file, if possible */
588 msg("No previous file");
590 { strcpy(tmpblk
.c
, prevorig
);
591 cmd_edit(cursor
, cursor
, CMD_EDIT
, 0, tmpblk
.c
);
596 /* This function does a tag search on a keyword */
598 MARK
v_tag(keyword
, m
, cnt
)
603 /* move the cursor to the start of the tag name, where m is */
606 /* perform the tag search */
607 cmd_tag(cursor
, cursor
, CMD_TAG
, 0, keyword
);
612 #ifndef NO_EXTENSIONS
613 /* This function looks up a keyword by calling the helpprog program */
615 MARK
v_keyword(keyword
, m
, cnt
)
624 addstr("---------------------------------------------------------\n");
627 sprintf(cmdline
, "%s %s", o_keywordprg
, keyword
);
633 addstr("<<< failed >>>\n");
635 resume_curses(FALSE
);
637 redraw(MARK_UNSET
, FALSE
);
645 MARK
v_increment(keyword
, m
, cnt
)
656 /* get one more keystroke, unless doingdot */
662 /* adjust the number, based on that second keystroke */
667 cnt
= atol(keyword
) + cnt
;
671 cnt
= atol(keyword
) - cnt
;
680 sprintf(newval
, "%ld", cnt
);
684 change(m
, m
+ strlen(keyword
), newval
);
692 /* This function acts like the EX command "xit" */
694 MARK
v_xit(m
, cnt
, key
)
695 MARK m
; /* ignored */
696 long cnt
; /* ignored */
697 int key
; /* must be a second 'Z' */
699 /* if second char wasn't 'Z', fail */
705 /* move the cursor to the bottom of the screen */
709 /* do the xit command */
710 cmd_xit(m
, m
, CMD_XIT
, FALSE
, "");
712 /* return the cursor */
717 /* This function undoes changes to a single line, if possible */
719 MARK m
; /* where we hope to undo the change */
721 /* make sure we have the right line in the buffer */
722 if (markline(m
) != U_line
)
730 strcat(U_text
, "\n");
731 change(MARK_AT_LINE(U_line
), MARK_AT_LINE(U_line
+ 1), U_text
);
734 /* nothing in the buffer anymore */
737 /* return, with the cursor at the front of the line */
738 return m
& ~(BLKSIZE
- 1);
746 cmd_errlist(m
, m
, CMD_ERRLIST
, FALSE
, "");
754 MARK
v_at(m
, cnt
, key
)
761 size
= cb2str(key
, tmpblk
.c
, BLKSIZE
);
762 if (size
<= 0 || size
== BLKSIZE
)
767 execmap(0, tmpblk
.c
, FALSE
);
776 cmd_suspend(MARK_UNSET
, MARK_UNSET
, CMD_SUSPEND
, FALSE
, "");
784 MARK
v_start(m
, cnt
, cmd
)
785 MARK m
; /* starting point for a v or V command */
786 long cnt
; /* ignored */
787 int cmd
; /* either 'v' or 'V' */
796 V_linemd
= isupper(cmd
);
803 # define MENU_HEIGHT 11
804 # define MENU_WIDTH 23
806 MARK m
, n
; /* the range of text to change */
809 int y
, x
; /* position where the window will pop up at */
810 int key
; /* keystroke from the user */
811 int sel
; /* index of the selected operation */
812 static int dfltsel
;/* default value of sel */
813 static char *labels
[11] =
823 " ! external filter ",
828 /* try to position the menu near the cursor */
829 x
= physcol
- (MENU_WIDTH
/ 2);
832 else if (x
+ MENU_WIDTH
+ 2 > COLS
)
833 x
= COLS
- MENU_WIDTH
- 2;
834 if (markline(cursor
) < topline
|| markline(cursor
) > botline
)
836 else if (markline(cursor
) + 1L + MENU_HEIGHT
> botline
)
837 y
= (int)(markline(cursor
) - topline
) - MENU_HEIGHT
;
839 y
= (int)(markline(cursor
) - topline
) + 1L;
842 for (sel
= 0; sel
< MENU_HEIGHT
; sel
++)
850 qaddstr(labels
[sel
]);
854 /* get a selection */
855 move(y
+ dfltsel
, x
+ 4);
856 for (sel
= dfltsel
; (key
= getkey(WHEN_POPUP
)) != '\\' && key
!= '\r'; )
858 /* erase the selection arrow */
862 qaddstr(labels
[sel
]);
865 /* process the user's keystroke */
866 if (key
== 'j' && sel
< MENU_HEIGHT
- 1)
870 else if (key
== 'k' && sel
> 0)
874 else if (key
== '\033')
881 for (i
= 1; i
< MENU_HEIGHT
&& labels
[i
][1] != key
; i
++)
891 /* redraw the arrow, possibly in a new place */
895 qaddstr(labels
[sel
]);
897 move(y
+ sel
, x
+ 4);
900 /* in most cases, the default selection is "paste after" */
903 /* perform the appropriate action */
911 case 1: /* delete (cut) */
915 case 2: /* yank (copy) */
919 case 3: /* paste after */
920 m
= v_paste(n
, 1L, 'P');
923 case 4: /* paste before */
924 m
= v_paste(m
, 1L, 'P');
928 case 5: /* more indented */
933 case 6: /* less indented */
938 case 7: /* reformat */
939 m
= v_reformat(m
, n
);
943 case 8: /* external filter */
948 case 9: /* save & exit */
949 /* get confirmation first */
953 } while (key
!= '\\' && key
!= 'Z' && key
!= '\r' /* good */
954 && key
!= '\033'); /* bad */
957 m
= v_xit(m
, 0L, 'Z');
961 case 10: /* undo previous */
967 /* arrange for the menu to be erased (except that "chg from kbd"
968 * already erased it, and "save & exit" doesn't care)
970 if (sel
!= 5 && sel
!= 9)
971 redraw(MARK_UNSET
, FALSE
);
975 #endif /* undef NO_POPUP */