* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Christos Zoulas of Cornell University.
* %sccs.include.redist.c%
#if !defined(lint) && !defined(SCCSID)
static char sccsid
[] = "@(#)vi.c 5.2 (Berkeley) %G%";
#endif /* not lint && not SCCSID */
* vi.c: Vi mode commands.
private el_action_t cv_action
__P((EditLine
*, int));
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
el
->el_chared
.c_vcmd
.action
= NOP
;
el
->el_chared
.c_vcmd
.pos
= 0;
el
->el_chared
.c_undo
.isize
= 0;
el
->el_chared
.c_undo
.dsize
= 0;
kp
= el
->el_chared
.c_undo
.buf
;
for (cp
= el
->el_line
.buffer
; cp
< el
->el_line
.lastchar
; cp
++) {
el
->el_chared
.c_undo
.dsize
++;
el
->el_chared
.c_undo
.action
= INSERT
;
el
->el_chared
.c_undo
.ptr
= el
->el_line
.buffer
;
el
->el_line
.lastchar
= el
->el_line
.buffer
;
el
->el_line
.cursor
= el
->el_line
.buffer
;
el
->el_map
.current
= el
->el_map
.key
;
el
->el_chared
.c_vcmd
.pos
= el
->el_line
.cursor
;
el
->el_chared
.c_vcmd
.action
= c
;
* I don't think that this is needed. But we keep it for now
else if (el_chared
.c_vcmd
.action
== NOP
) {
el
->el_chared
.c_vcmd
.pos
= el
->el_line
.cursor
;
el
->el_chared
.c_vcmd
.action
= c
;
el
->el_chared
.c_vcmd
.action
= 0;
el
->el_chared
.c_vcmd
.pos
= 0;
* Paste previous deletion before or after the cursor
c_undo_t
*un
= &el
->el_chared
.c_undo
;
(void) fprintf(el
->el_errfile
, "Paste: %x \"%s\" +%d -%d\n",
un
->action
, un
->buf
, un
->isize
, un
->dsize
);
if (!c
&& el
->el_line
.cursor
< el
->el_line
.lastchar
)
ptr
= el
->el_line
.cursor
;
if (el
->el_line
.cursor
+ un
->isize
> el
->el_line
.lastchar
)
(void) memcpy(ptr
, un
->buf
, un
->isize
);
* Vi paste previous deletion to the right of the cursor
* Vi paste previous deletion to the left of the cursor
* Vi move to the previous space delimited word
vi_prev_space_word(el
, c
)
if (el
->el_line
.cursor
== el
->el_line
.buffer
)
el
->el_line
.cursor
= cv_prev_word(el
, el
->el_line
.cursor
,
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
* Vi move to the previous word
if (el
->el_line
.cursor
== el
->el_line
.buffer
)
el
->el_line
.cursor
= cv_prev_word(el
, el
->el_line
.cursor
,
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
* Vi move to the next space delimited word
vi_next_space_word(el
, c
)
if (el
->el_line
.cursor
== el
->el_line
.lastchar
)
el
->el_line
.cursor
= cv_next_word(el
, el
->el_line
.cursor
,
if (el
->el_map
.type
== MAP_VI
)
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
* Vi move to the next word
if (el
->el_line
.cursor
== el
->el_line
.lastchar
)
el
->el_line
.cursor
= cv_next_word(el
, el
->el_line
.cursor
,
if (el
->el_map
.type
== MAP_VI
)
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
* Vi change case of character under the cursor and advance one character
if (el
->el_line
.cursor
< el
->el_line
.lastchar
) {
*el
->el_line
.cursor
++ = tolower(c
);
*el
->el_line
.cursor
++ = toupper(c
);
* Vi change prefix command
* Delete with insert == change: first we delete and then we leave in
return cv_action(el
, DELETE
|INSERT
);
* Vi enter insert mode at the beginning of line
el
->el_line
.cursor
= el
->el_line
.buffer
;
el
->el_chared
.c_vcmd
.ins
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.ptr
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.action
= DELETE
;
el
->el_map
.current
= el
->el_map
.key
;
* Vi replace character under the cursor with the next character typed
el
->el_map
.current
= el
->el_map
.key
;
el
->el_state
.inputmode
= MODE_REPLACE_1
;
el
->el_chared
.c_undo
.action
= CHANGE
;
el
->el_chared
.c_undo
.ptr
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.isize
= 0;
el
->el_chared
.c_undo
.dsize
= 0;
el
->el_map
.current
= el
->el_map
.key
;
el
->el_state
.inputmode
= MODE_REPLACE
;
el
->el_chared
.c_undo
.action
= CHANGE
;
el
->el_chared
.c_undo
.ptr
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.isize
= 0;
el
->el_chared
.c_undo
.dsize
= 0;
* Vi replace character under the cursor and enter insert mode
vi_substitute_char(el
, c
)
c_delafter(el
, el
->el_state
.argument
);
el
->el_map
.current
= el
->el_map
.key
;
* Vi substitute entire line
vi_substitute_line(el
, c
)
(void) em_kill_line(el
, 0);
el
->el_map
.current
= el
->el_map
.key
;
* Vi change to end of line
(void) ed_kill_line(el
, 0);
el
->el_map
.current
= el
->el_map
.key
;
el
->el_map
.current
= el
->el_map
.key
;
el
->el_chared
.c_vcmd
.ins
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.ptr
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.action
= DELETE
;
* Vi enter insert mode after the cursor
el
->el_map
.current
= el
->el_map
.key
;
if (el
->el_line
.cursor
< el
->el_line
.lastchar
) {
if (el
->el_line
.cursor
> el
->el_line
.lastchar
)
el
->el_line
.cursor
= el
->el_line
.lastchar
;
el
->el_chared
.c_vcmd
.ins
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.ptr
= el
->el_line
.cursor
;
el
->el_chared
.c_undo
.action
= DELETE
;
* Vi enter insert mode at end of line
el
->el_map
.current
= el
->el_map
.key
;
el
->el_line
.cursor
= el
->el_line
.lastchar
;
/* Mark where insertion begins */
el
->el_chared
.c_vcmd
.ins
= el
->el_line
.lastchar
;
el
->el_chared
.c_undo
.ptr
= el
->el_line
.lastchar
;
el
->el_chared
.c_undo
.action
= DELETE
;
* Vi delete prefix command
return cv_action(el
, DELETE
);
* Vi move to the end of the current space delimited word
if (el
->el_line
.cursor
== el
->el_line
.lastchar
)
el
->el_line
.cursor
= cv__endword(el
->el_line
.cursor
, el
->el_line
.lastchar
,
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
* Vi move to the end of the current word
if (el
->el_line
.cursor
== el
->el_line
.lastchar
)
el
->el_line
.cursor
= cv__endword(el
->el_line
.cursor
, el
->el_line
.lastchar
,
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
c_undo_t
*un
= &el
->el_chared
.c_undo
;
(void) fprintf(el
->el_errfile
, "Undo: %x \"%s\" +%d -%d\n",
un
->action
, un
->buf
, un
->isize
, un
->dsize
);
(void) memcpy(un
->buf
, un
->ptr
, un
->dsize
);
for (cp
= un
->ptr
; cp
<= el
->el_line
.lastchar
; cp
++)
el
->el_line
.lastchar
-= un
->dsize
;
el
->el_line
.cursor
= un
->ptr
;
size
= un
->isize
- un
->dsize
;
while (size
-- > 0 && cp
< el
->el_line
.lastchar
) {
for (; cp
<= el
->el_line
.lastchar
; cp
++) {
el
->el_line
.lastchar
-= size
;
el
->el_line
.cursor
= un
->ptr
;
el
->el_line
.cursor
= un
->ptr
;
memcpy(un
->ptr
, un
->buf
, un
->isize
);
el
->el_line
.cursor
= un
->ptr
;
size
= (int) (el
->el_line
.cursor
- el
->el_line
.lastchar
);
for(i
= 0; i
< size
; i
++) {
* Vi enter command mode (use alternative key bindings)
/* [Esc] cancels pending action */
el
->el_chared
.c_vcmd
.ins
= 0;
el
->el_chared
.c_vcmd
.action
= NOP
;
el
->el_chared
.c_vcmd
.pos
= 0;
el
->el_state
.doingarg
= 0;
size
= el
->el_chared
.c_undo
.ptr
- el
->el_line
.cursor
;
if (el
->el_chared
.c_undo
.action
== (INSERT
|DELETE
) ||
el
->el_chared
.c_undo
.action
== DELETE
)
el
->el_chared
.c_undo
.dsize
= size
;
el
->el_chared
.c_undo
.isize
= size
;
el
->el_state
.inputmode
= MODE_INSERT
;
el
->el_map
.current
= el
->el_map
.alt
;
if (el
->el_line
.cursor
> el
->el_line
.buffer
)
* Vi move to the beginning of line
if (el
->el_state
.doingarg
) {
if (el
->el_state
.argument
> 1000000)
(el
->el_state
.argument
* 10) + (c
- '0');
el
->el_line
.cursor
= el
->el_line
.buffer
;
if (el
->el_chared
.c_vcmd
.action
& DELETE
) {
/* vi_delete_prev_char():
* Vi move to previous character (backspace)
vi_delete_prev_char(el
, c
)
if (el
->el_chared
.c_vcmd
.ins
== 0)
if (el
->el_chared
.c_vcmd
.ins
>
el
->el_line
.cursor
- el
->el_state
.argument
)
c_delbefore(el
, el
->el_state
.argument
);
el
->el_line
.cursor
-= el
->el_state
.argument
;
} /* end v_del_char_prev */
* Vi list choices for completion or indicate end of file if empty line
if (el
->el_line
.cursor
== el
->el_line
.lastchar
&&
el
->el_line
.cursor
== el
->el_line
.buffer
) {
term_overwrite(el
, STReof
, 4); /* then do a EOF */
*el
->el_line
.lastchar
= '\0'; /* just in case */
* Vi cut from beginning of line to cursor
kp
= el
->el_chared
.c_kill
.buf
;
while (cp
< el
->el_line
.cursor
)
*kp
++ = *cp
++; /* copy it */
el
->el_chared
.c_kill
.last
= kp
;
c_delbefore(el
, el
->el_line
.cursor
- el
->el_line
.buffer
);
el
->el_line
.cursor
= el
->el_line
.buffer
; /* zap! */
* Vi search history previous
return cv_search(el
, ED_SEARCH_PREV_HISTORY
);
return cv_search(el
, ED_SEARCH_NEXT_HISTORY
);
/* vi_repeat_search_next():
* Vi repeat current search in the same search direction
vi_repeat_search_next(el
, c
)
if (el
->el_search
.patlen
== 0)
return cv_repeat_srch(el
, el
->el_search
.patdir
);
/* vi_repeat_search_prev():
* Vi repeat current search in the opposite search direction
vi_repeat_search_prev(el
, c
)
if (el
->el_search
.patlen
== 0)
return cv_repeat_srch(el
,
el
->el_search
.patdir
== ED_SEARCH_PREV_HISTORY
?
ED_SEARCH_NEXT_HISTORY
: ED_SEARCH_PREV_HISTORY
);
* Vi move to the character specified next
if (el_getc(el
, &ch
) != 1)
return ed_end_of_file(el
, 0);
el
->el_search
.chadir
= CHAR_FWD
;
el
->el_search
.chacha
= ch
;
return cv_csearch_fwd(el
, ch
, el
->el_state
.argument
, 0);
* Vi move to the character specified previous
if (el_getc(el
, &ch
) != 1)
return ed_end_of_file(el
, 0);
el
->el_search
.chadir
= CHAR_BACK
;
el
->el_search
.chacha
= ch
;
return cv_csearch_back(el
, ch
, el
->el_state
.argument
, 0);
* Vi move up to the character specified next
if (el_getc(el
, &ch
) != 1)
return ed_end_of_file(el
, 0);
return cv_csearch_fwd(el
, ch
, el
->el_state
.argument
, 1);
* Vi move up to the character specified previous
if (el_getc(el
, &ch
) != 1)
return ed_end_of_file(el
, 0);
return cv_csearch_back(el
, ch
, el
->el_state
.argument
, 1);
/* vi_repeat_next_char():
* Vi repeat current character search in the same search direction
vi_repeat_next_char(el
, c
)
if (el
->el_search
.chacha
== 0)
return el
->el_search
.chadir
== CHAR_FWD
?
cv_csearch_fwd(el
, el
->el_search
.chacha
, el
->el_state
.argument
, 0) :
cv_csearch_back(el
, el
->el_search
.chacha
, el
->el_state
.argument
, 0);
/* vi_repeat_prev_char():
* Vi repeat current character search in the opposite search direction
vi_repeat_prev_char(el
, c
)
if (el
->el_search
.chacha
== 0)
return el
->el_search
.chadir
== CHAR_BACK
?
cv_csearch_fwd(el
, el
->el_search
.chacha
, el
->el_state
.argument
, 0) :
cv_csearch_back(el
, el
->el_search
.chacha
, el
->el_state
.argument
, 0);