edit: Move most code from edit() to insert_{enter,check,execute}

Refactor insert mode to use `state_enter` as an event loop:

- Move o_lnum(static variable) outside function
- Move code before the insert mode loop into `insert_enter`
- Move code before `safe_vgetc()` call into `insert_check`
- Move code after `safe_vgetc()` call into `insert_execute`
- Remove doESCkey label and handle insert mode repeating in the `insert_enter`
  function
- Remove do_intr label(this is not the place for platform-specific interrupt
  charts)
This commit is contained in:
Thiago de Arruda
2015-10-15 15:50:34 -03:00
parent f5b333f532
commit 091e7d033c

View File

@@ -254,52 +254,10 @@ static int did_add_space = FALSE; /* auto_format() added an extra space
static int dont_sync_undo = false; // CTRL-G U prevents syncing undo
// for the next left/right cursor
/*
* edit(): Start inserting text.
*
* "cmdchar" can be:
* 'i' normal insert command
* 'a' normal append command
* 'R' replace command
* 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
* but still only one <CR> is inserted. The <Esc> is not used for redo.
* 'g' "gI" command.
* 'V' "gR" command for Virtual Replace mode.
* 'v' "gr" command for single character Virtual Replace mode.
*
* This function is not called recursively. For CTRL-O commands, it returns
* and lets the caller handle the Normal-mode command.
*
* Return TRUE if a CTRL-O command caused the return (insert mode pending).
*/
int
edit (
int cmdchar,
int startln, /* if set, insert at start of line */
long count
)
{
static linenr_T o_lnum = 0;
InsertState state, *s = &state;
memset(s, 0, sizeof(InsertState));
if (curbuf->terminal) {
if (ex_normal_busy) {
// don't enter terminal mode from `ex_normal`, which can result in all
// kinds of havoc(such as terminal mode recursiveness). Instead, set a
// flag that allow us to force-set the value of `restart_edit` before
// `ex_normal` returns
restart_edit = 'i';
force_restart_edit = true;
} else {
terminal_enter();
}
return false;
}
s->cmdchar = cmdchar;
s->startln = startln;
s->count = count;
static void insert_enter(InsertState *s)
{
s->did_backspace = true;
s->old_topfill = -1;
s->replaceState = REPLACE;
@@ -311,34 +269,15 @@ edit (
// set Insstart_orig to Insstart
update_Insstart_orig = true;
// Don't allow inserting in the sandbox.
if (sandbox != 0) {
EMSG(_(e_sandbox));
return false;
}
// Don't allow changes in the buffer while editing the cmdline. The
// caller of getcmdline() may get confused.
if (textlock != 0) {
EMSG(_(e_secure));
return false;
}
// Don't allow recursive insert mode when busy with completion.
if (compl_started || compl_busy || pum_visible()) {
EMSG(_(e_secure));
return false;
}
ins_compl_clear(); // clear stuff for CTRL-X mode
// Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
if (cmdchar != 'r' && cmdchar != 'v') {
if (s->cmdchar != 'r' && s->cmdchar != 'v') {
pos_T save_cursor = curwin->w_cursor;
if (cmdchar == 'R') {
if (s->cmdchar == 'R') {
s->ptr = (char_u *)"r";
} else if (cmdchar == 'V') {
} else if (s->cmdchar == 'V') {
s->ptr = (char_u *)"v";
} else {
s->ptr = (char_u *)"i";
@@ -376,7 +315,7 @@ edit (
Insstart = where_paste_started;
} else {
Insstart = curwin->w_cursor;
if (startln) {
if (s->startln) {
Insstart.col = 0;
}
}
@@ -388,24 +327,24 @@ edit (
ai_col = 0;
}
if (cmdchar != NUL && restart_edit == 0) {
if (s->cmdchar != NUL && restart_edit == 0) {
ResetRedobuff();
AppendNumberToRedobuff(count);
if (cmdchar == 'V' || cmdchar == 'v') {
AppendNumberToRedobuff(s->count);
if (s->cmdchar == 'V' || s->cmdchar == 'v') {
// "gR" or "gr" command
AppendCharToRedobuff('g');
AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
AppendCharToRedobuff((s->cmdchar == 'v') ? 'r' : 'R');
} else {
AppendCharToRedobuff(cmdchar);
if (cmdchar == 'g') { // "gI" command
AppendCharToRedobuff(s->cmdchar);
if (s->cmdchar == 'g') { // "gI" command
AppendCharToRedobuff('I');
} else if (cmdchar == 'r') { // "r<CR>" command
count = 1; // insert only one <CR>
} else if (s->cmdchar == 'r') { // "r<CR>" command
s->count = 1; // insert only one <CR>
}
}
}
if (cmdchar == 'R') {
if (s->cmdchar == 'R') {
if (p_fkmap && p_ri) {
beep_flush();
EMSG(farsi_text_3); // encoded in Farsi
@@ -413,7 +352,7 @@ edit (
} else {
State = REPLACE;
}
} else if (cmdchar == 'V' || cmdchar == 'v') {
} else if (s->cmdchar == 'V' || s->cmdchar == 'v') {
State = VREPLACE;
s->replaceState = VREPLACE;
orig_line_count = curbuf->b_ml.ml_line_count;
@@ -525,9 +464,27 @@ edit (
old_indent = 0;
do {
state_enter(&s->state);
// If s->count != 0, `ins_esc` will prepare the redo buffer for reprocessing
// and return false, causing `state_enter` to be called again.
} while (!ins_esc(&s->count, s->cmdchar, s->nomove));
// Main loop in Insert mode: repeat until Insert mode is left.
for (;; ) {
// Always update o_lnum, so that a "CTRL-O ." that adds a line
// still puts the cursor back after the inserted text.
if (ins_at_eol && gchar_cursor() == NUL) {
o_lnum = curwin->w_cursor.lnum;
}
if (s->cmdchar != 'r' && s->cmdchar != 'v') {
apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL, false, curbuf);
}
did_cursorhold = false;
}
static int insert_check(VimState *state)
{
InsertState *s = (InsertState *)state;
if (!revins_legal) {
revins_scol = -1; // reset on illegal motions
} else {
@@ -535,7 +492,7 @@ edit (
}
if (arrow_used) { // don't repeat insert when arrow key used
count = 0;
s->count = 0;
}
if (update_Insstart_orig) {
@@ -544,8 +501,8 @@ edit (
if (stop_insert_mode) {
// ":stopinsert" used or 'insertmode' reset
count = 0;
goto doESCkey;
s->count = 0;
return 0; // exit insert mode
}
// set curwin->w_curswant for next K_DOWN or K_UP
@@ -626,8 +583,6 @@ edit (
update_curswant();
s->old_topline = curwin->w_topline;
s->old_topfill = curwin->w_topfill;
// Get a character for Insert mode. Ignore K_IGNORE.
s->lastc = s->c; // remember previous char for CTRL-D
// After using CTRL-G U the next cursor key will not break undo.
@@ -637,14 +592,18 @@ edit (
dont_sync_undo = false;
}
input_enable_events();
do {
s->c = safe_vgetc();
} while (s->c == K_IGNORE);
input_disable_events();
return 1;
}
// Don't want K_EVENT with cursorhold for the second key, e.g., after
// CTRL-V.
static int insert_execute(VimState *state, int key)
{
if (key == K_IGNORE) {
return -1; // get another key
}
InsertState *s = (InsertState *)state;
s->c = key;
// Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V.
did_cursorhold = true;
if (p_hkmap && KeyTyped) {
@@ -667,7 +626,7 @@ edit (
if ((s->c == K_BS || s->c == Ctrl_H)
&& curwin->w_cursor.col > compl_col
&& (s->c = ins_compl_bs()) == NUL) {
continue;
return 1; // continue
}
// When no match was selected or it was edited.
@@ -680,7 +639,7 @@ edit (
|| (int)STRLEN(compl_shown_match->cp_str)
> curwin->w_cursor.col - compl_col)) {
ins_compl_addfrommatch();
continue;
return 1; // continue
}
// A non-white character that fits in with the current
@@ -698,7 +657,7 @@ edit (
} else {
ins_compl_addleader(s->c);
}
continue;
return 1; // continue
}
// Pressing CTRL-Y selects the current match. When
@@ -716,7 +675,7 @@ edit (
// fix up the text when finishing completion.
compl_get_longest = false;
if (ins_compl_prep(s->c)) {
continue;
return 1; // continue
}
// CTRL-\ CTRL-N goes to Normal mode,
@@ -735,15 +694,15 @@ edit (
vungetc(s->c);
s->c = Ctrl_BSL;
} else if (s->c == Ctrl_G && p_im) {
continue;
return 1; // continue
} else {
if (s->c == Ctrl_O) {
ins_ctrl_o();
ins_at_eol = false; // cursor keeps its column
s->nomove = true;
}
count = 0;
goto doESCkey;
s->count = 0;
return 0;
}
}
@@ -756,7 +715,7 @@ edit (
if (s->c == Ctrl_V || s->c == Ctrl_Q) {
ins_ctrl_v();
s->c = Ctrl_V; // pretend CTRL-V is last typed character
continue;
return 1; // continue
}
if (cindent_on()
@@ -790,7 +749,7 @@ edit (
// does, a CTRL-O and c will be stuffed, we need to get these
// characters.
if (ins_start_select(s->c)) {
continue;
return 1; // continue
}
// The big switch to handle a character in insert mode.
@@ -809,12 +768,9 @@ edit (
cmdwin_result = K_IGNORE;
got_int = false; // don't stop executing autocommands et al
s->nomove = true;
goto doESCkey;
return 0; // exit insert mode
}
#ifdef UNIX
do_intr:
#endif
// when 'insertmode' set, and not halfway through a mapping, don't leave
// Insert mode
if (goto_im()) {
@@ -826,22 +782,7 @@ do_intr:
}
break;
}
doESCkey:
// This is the ONLY return from edit()!
// Always update o_lnum, so that a "CTRL-O ." that adds a line
// still puts the cursor back after the inserted text.
if (ins_at_eol && gchar_cursor() == NUL) {
o_lnum = curwin->w_cursor.lnum;
}
if (ins_esc(&count, cmdchar, s->nomove)) {
if (cmdchar != 'r' && cmdchar != 'v') {
apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL, false, curbuf);
}
did_cursorhold = false;
return s->c == Ctrl_O;
}
continue;
return 0; // exit insert mode
case Ctrl_Z: // suspend when 'insertmode' set
if (!p_im) {
@@ -868,8 +809,8 @@ doESCkey:
s->nomove = true;
}
count = 0;
goto doESCkey;
s->count = 0;
return 0; // exit insert mode
case K_INS: // toggle insert/replace mode
case K_KINS:
@@ -887,7 +828,7 @@ doESCkey:
if (p_im) {
need_start_insertmode = true;
}
goto doESCkey;
return 0; // exit insert mode
case K_ZERO: // Insert the previously inserted text.
@@ -896,8 +837,9 @@ doESCkey:
// For ^@ the trailing ESC will end the insert, unless there is an
// error.
if (stuff_inserted(NUL, 1L, (s->c == Ctrl_A)) == FAIL
&& s->c != Ctrl_A && !p_im)
goto doESCkey; // quit insert mode
&& s->c != Ctrl_A && !p_im) {
return 0; // exit insert mode
}
s->inserted_space = false;
break;
@@ -1128,10 +1070,10 @@ doESCkey:
if (cmdwin_type != 0) {
// Execute the command in the cmdline window.
cmdwin_result = CAR;
goto doESCkey;
return 0;
}
if (ins_eol(s->c) && !p_im) {
goto doESCkey; // out of memory
return 0; // out of memory
}
auto_format(false, false);
s->inserted_space = false;
@@ -1181,7 +1123,7 @@ doESCkey:
if (echeck_abbr(Ctrl_L + ABBR_OFF)) {
break;
}
goto doESCkey;
return 0; // exit insert mode
}
goto normalchar;
}
@@ -1211,10 +1153,6 @@ docomplete:
break;
default:
#ifdef UNIX
if (s->c == intr_char) // special interrupt char
goto do_intr;
#endif
normalchar:
// Insert a normal character.
@@ -1301,8 +1239,77 @@ force_cindent:
}
}
}
} // for (;;)
// NOTREACHED
return 1; // continue
}
/*
* edit(): Start inserting text.
*
* "cmdchar" can be:
* 'i' normal insert command
* 'a' normal append command
* 'R' replace command
* 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
* but still only one <CR> is inserted. The <Esc> is not used for redo.
* 'g' "gI" command.
* 'V' "gR" command for Virtual Replace mode.
* 'v' "gr" command for single character Virtual Replace mode.
*
* This function is not called recursively. For CTRL-O commands, it returns
* and lets the caller handle the Normal-mode command.
*
* Return TRUE if a CTRL-O command caused the return (insert mode pending).
*/
int
edit (
int cmdchar,
int startln, /* if set, insert at start of line */
long count
)
{
if (curbuf->terminal) {
if (ex_normal_busy) {
// don't enter terminal mode from `ex_normal`, which can result in all
// kinds of havoc(such as terminal mode recursiveness). Instead, set a
// flag that allow us to force-set the value of `restart_edit` before
// `ex_normal` returns
restart_edit = 'i';
force_restart_edit = true;
} else {
terminal_enter();
}
return false;
}
// Don't allow inserting in the sandbox.
if (sandbox != 0) {
EMSG(_(e_sandbox));
return false;
}
// Don't allow changes in the buffer while editing the cmdline. The
// caller of getcmdline() may get confused.
if (textlock != 0) {
EMSG(_(e_secure));
return false;
}
// Don't allow recursive insert mode when busy with completion.
if (compl_started || compl_busy || pum_visible()) {
EMSG(_(e_secure));
return false;
}
InsertState state, *s = &state;
memset(s, 0, sizeof(InsertState));
s->state.execute = insert_execute;
s->state.check = insert_check;
s->cmdchar = cmdchar;
s->startln = startln;
s->count = count;
insert_enter(s);
return s->c == Ctrl_O;
}
/*