/* This file contains the functions that handle VI commands */
/* This function puts the editor in EX mode */
/* This function causes the screen to be redrawn */
redraw(MARK_UNSET
, FALSE
);
/* This function executes a string of EX commands, and waits for a user keystroke
* before returning to the VI screen. If that keystroke is another ':', then
* another EX command is read and executed.
MARK m
; /* the current line */
char *text
; /* the first command to execute */
/* run the command. be careful about modes & output */
exwrote
= (mode
== MODE_COLON
);
/* if mode is no longer MODE_VI, then we should quit right away! */
if (mode
!= MODE_VI
&& mode
!= MODE_COLON
)
/* The command did some output. Wait for a keystoke. */
msg("[Hit <RETURN> to continue]");
redraw(MARK_UNSET
, FALSE
);
/* This function undoes the last change */
redraw(MARK_UNSET
, FALSE
);
/* This function deletes the character(s) that the cursor is on */
MARK
v_xchar(m
, cnt
, cmd
)
MARK m
; /* where to start deletions */
long cnt
; /* number of chars to delete */
int cmd
; /* either 'x' or 'X' */
/* for 'X', adjust so chars are deleted *BEFORE* cursor */
/* make sure we don't try to delete more thars than there are */
if (markidx(m
+ cnt
) > plen
)
/* This function defines a mark */
MARK
v_mark(m
, count
, key
)
MARK m
; /* where the mark will be */
long count
; /* (ignored) */
int key
; /* the ASCII label of the mark */
if (key
< 'a' || key
> 'z')
msg("Marks must be from a to z");
/* This function toggles upper & lower case letters */
MARK m
; /* where to make the change */
long cnt
; /* number of chars to flip */
/* fetch the current version of the line */
/* for each position in the line */
for (j
= 0, pos
= &ptext
[markidx(m
)]; j
< cnt
&& *pos
; j
++, pos
++)
tmpblk
.c
[j
] = tolower(*pos
);
tmpblk
.c
[j
] = toupper(*pos
);
/* if the new text is different from the old, then change it */
if (strncmp(tmpblk
.c
, &ptext
[markidx(m
)], j
))
change(m
, m
+ j
, tmpblk
.c
);
MARK
v_replace(m
, cnt
, key
)
MARK m
; /* first char to be replaced */
long cnt
; /* number of chars to replace */
int key
; /* what to replace them with */
/* make sure the resulting line isn't too long */
if (cnt
> BLKSIZE
- 2 - markidx(m
))
cnt
= BLKSIZE
- 2 - markidx(m
);
/* build a string of the desired character with the desired length */
for (text
= tmpblk
.c
, i
= cnt
; i
> 0; i
--)
/* make sure cnt doesn't extend past EOL */
change(m
, m
+ cnt
, tmpblk
.c
);
return (m
& ~(BLKSIZE
- 1)) + cnt
* BLKSIZE
;
MARK m
; /* where to start overtyping */
MARK end
; /* end of a substitution */
static long width
; /* width of a single-line replace */
/* the "doingdot" version of replace is really a substitution */
/* was the last one really repeatable? */
msg("Can't repeat a multi-line overtype command");
/* replacing nothing by nothing? Don't bother */
/* replace some chars by repeated text */
return v_subst(m
, width
);
/* Normally, we input starting here, in replace mode */
end
= input(m
, m
, WHEN_VIREP
, FALSE
);
/* if we ended on the same line we started on, then this
* overtype is repeatable via the dot key.
if (markline(end
) == markline(m
) && end
>= m
- 1L)
else /* it isn't repeatable */
/* This function selects which cut buffer to use */
MARK
v_selcut(m
, cnt
, key
)
/* This function pastes text from a cut buffer */
MARK
v_paste(m
, cnt
, cmd
)
MARK m
; /* where to paste the text */
long cnt
; /* (ignored) */
int cmd
; /* either 'p' or 'P' */
/* paste the text, and find out where it ends */
dest
= paste(m
, cmd
== 'p', TRUE
);
/* was that a line-mode paste? */
if (dest
&& markline(dest
) != markline(m
))
/* line-mode pastes leave the cursor at the front
* of the first pasted line.
/* This function yanks text into a cut buffer */
MARK m
, n
; /* range of text to yank */
/* This function deletes a range of text */
MARK m
, n
; /* range of text to delete */
/* illegal to try and delete nothing */
/* This starts input mode without deleting anything */
MARK
v_insert(m
, cnt
, key
)
MARK m
; /* where to start (sort of) */
long cnt
; /* repeat how many times? */
int key
; /* what command is this for? {a,A,i,I,o,O} */
int above
; /* boolean: new line going above old line? */
/* tweak the insertion point, based on command key */
m
= (m
& ~(BLKSIZE
- 1)) + plen
;
m
= (m
& ~(BLKSIZE
- 1)) + BLKSIZE
;
/* insert the same text once or more */
for (reps
= cnt
, wasdot
= doingdot
; reps
> 0; reps
--, doingdot
= TRUE
)
m
= input(m
, m
, WHEN_VIINP
, above
) + 1;
if (key
== 'i' && *o_inputmode
&& mode
== MODE_VI
)
msg("Now in command mode! To return to input mode, hit <i>");
/* This starts input mode with some text deleted */
MARK m
, n
; /* the range of text to change */
int lnmode
; /* is this a line-mode change? */
/* swap them if they're in reverse order */
/* for line mode, retain the last newline char */
lnmode
= (markidx(m
) == 0 && markidx(n
) == 0 && m
!= n
);
n
= (n
& ~(BLKSIZE
- 1)) + plen
;
m
= input(m
, n
, WHEN_VIINP
, FALSE
);
/* This function replaces a given number of characters with input */
MARK m
; /* where substitutions start */
long cnt
; /* number of chars to replace */
/* make sure we don't try replacing past EOL */
if (markidx(m
) + cnt
> plen
)
m
= input(m
, m
+ cnt
, WHEN_VIINP
, FALSE
);
/* This calls the ex "join" command to join some lines together */
MARK m
; /* the first line to be joined */
long cnt
; /* number of other lines to join */
MARK joint
; /* where the lines were joined */
/* figure out where the joint will be */
joint
= (m
& ~(BLKSIZE
- 1)) + plen
;
cmd_join(m
, m
+ MARK_AT_LINE(cnt
), CMD_JOIN
, 0, "");
/* the cursor should be left at the joint */
/* This calls the ex "<" command to shift some lines left */
MARK m
, n
; /* range of lines to shift */
/* adjust for inclusive endmarks in ex */
cmd_shift(m
, n
, CMD_SHIFTL
, FALSE
, (char *)0);
/* This calls the ex ">" command to shift some lines right */
MARK m
, n
; /* range of lines to shift */
/* adjust for inclusive endmarks in ex */
cmd_shift(m
, n
, CMD_SHIFTR
, FALSE
, (char *)0);
/* This filters some lines through a preset program, to reformat them */
MARK m
, n
; /* range of lines to shift */
/* adjust for inclusive endmarks in ex */
/* run the filter command */
filter(m
, n
, o_equalprg
, TRUE
);
redraw(MARK_UNSET
, FALSE
);
/* This runs some lines through a filter program */
MARK m
, n
; /* range of lines to shift */
char cmdln
[150]; /* a shell command line */
/* adjust for inclusive endmarks in ex */
if (vgets('!', cmdln
, sizeof(cmdln
)) > 0)
filter(m
, n
, cmdln
, TRUE
);
redraw(MARK_UNSET
, FALSE
);
/* This function runs the ex "file" command to show the file's status */
cmd_file(cursor
, cursor
, CMD_FILE
, 0, "");
/* This function runs the ":&" command to repeat the previous :s// */
cmd_substitute(m
, n
- BLKSIZE
, CMD_SUBAGAIN
, TRUE
, "");
/* This function switches to the previous file, if possible */
{ strcpy(tmpblk
.c
, prevorig
);
cmd_edit(cursor
, cursor
, CMD_EDIT
, 0, tmpblk
.c
);
/* This function does a tag search on a keyword */
MARK
v_tag(keyword
, m
, cnt
)
/* move the cursor to the start of the tag name, where m is */
/* perform the tag search */
cmd_tag(cursor
, cursor
, CMD_TAG
, 0, keyword
);
/* This function looks up a keyword by calling the helpprog program */
MARK
v_keyword(keyword
, m
, cnt
)
addstr("---------------------------------------------------------\n");
sprintf(cmdline
, "%s %s", o_keywordprg
, keyword
);
addstr("<<< failed >>>\n");
redraw(MARK_UNSET
, FALSE
);
MARK
v_increment(keyword
, m
, cnt
)
/* get one more keystroke, unless doingdot */
/* adjust the number, based on that second keystroke */
cnt
= atol(keyword
) + cnt
;
cnt
= atol(keyword
) - cnt
;
sprintf(newval
, "%ld", cnt
);
change(m
, m
+ strlen(keyword
), newval
);
/* This function acts like the EX command "xit" */
int key
; /* must be a second 'Z' */
/* if second char wasn't 'Z', fail */
/* move the cursor to the bottom of the screen */
cmd_xit(m
, m
, CMD_XIT
, FALSE
, "");
/* This function undoes changes to a single line, if possible */
MARK m
; /* where we hope to undo the change */
/* make sure we have the right line in the buffer */
if (markline(m
) != U_line
)
change(MARK_AT_LINE(U_line
), MARK_AT_LINE(U_line
+ 1), U_text
);
/* nothing in the buffer anymore */
/* return, with the cursor at the front of the line */
return m
& ~(BLKSIZE
- 1);
cmd_errlist(m
, m
, CMD_ERRLIST
, FALSE
, "");
size
= cb2str(key
, tmpblk
.c
, BLKSIZE
);
if (size
<= 0 || size
== BLKSIZE
)
execmap(0, tmpblk
.c
, FALSE
);
cmd_suspend(MARK_UNSET
, MARK_UNSET
, CMD_SUSPEND
, FALSE
, "");
MARK
v_start(m
, cnt
, cmd
)
MARK m
; /* starting point for a v or V command */
int cmd
; /* either 'v' or 'V' */
MARK m
, n
; /* the range of text to change */
int y
, x
; /* position where the window will pop up at */
int key
; /* keystroke from the user */
int sel
; /* index of the selected operation */
static int dfltsel
;/* default value of sel */
static char *labels
[11] =
/* try to position the menu near the cursor */
x
= physcol
- (MENU_WIDTH
/ 2);
else if (x
+ MENU_WIDTH
+ 2 > COLS
)
x
= COLS
- MENU_WIDTH
- 2;
if (markline(cursor
) < topline
|| markline(cursor
) > botline
)
else if (markline(cursor
) + 1L + MENU_HEIGHT
> botline
)
y
= (int)(markline(cursor
) - topline
) - MENU_HEIGHT
;
y
= (int)(markline(cursor
) - topline
) + 1L;
for (sel
= 0; sel
< MENU_HEIGHT
; sel
++)
move(y
+ dfltsel
, x
+ 4);
for (sel
= dfltsel
; (key
= getkey(WHEN_POPUP
)) != '\\' && key
!= '\r'; )
/* erase the selection arrow */
/* process the user's keystroke */
if (key
== 'j' && sel
< MENU_HEIGHT
- 1)
else if (key
== 'k' && sel
> 0)
for (i
= 1; i
< MENU_HEIGHT
&& labels
[i
][1] != key
; i
++)
/* redraw the arrow, possibly in a new place */
/* in most cases, the default selection is "paste after" */
/* perform the appropriate action */
case 1: /* delete (cut) */
case 2: /* yank (copy) */
case 3: /* paste after */
case 4: /* paste before */
case 5: /* more indented */
case 6: /* less indented */
case 8: /* external filter */
case 9: /* save & exit */
/* get confirmation first */
} while (key
!= '\\' && key
!= 'Z' && key
!= '\r' /* good */
&& key
!= '\033'); /* bad */
case 10: /* undo previous */
/* arrange for the menu to be erased (except that "chg from kbd"
* already erased it, and "save & exit" doesn't care)
if (sel
!= 5 && sel
!= 9)
redraw(MARK_UNSET
, FALSE
);
#endif /* undef NO_POPUP */