mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
normal: Extract normal_finish_command
from normal_execute
This commit is contained in:
parent
5abd25f6fb
commit
4c6e417d2a
@ -70,6 +70,7 @@ typedef struct normal_state {
|
|||||||
VimState state;
|
VimState state;
|
||||||
linenr_T conceal_old_cursor_line;
|
linenr_T conceal_old_cursor_line;
|
||||||
linenr_T conceal_new_cursor_line;
|
linenr_T conceal_new_cursor_line;
|
||||||
|
bool command_finished;
|
||||||
bool ctrl_w;
|
bool ctrl_w;
|
||||||
bool need_flushbuf;
|
bool need_flushbuf;
|
||||||
bool conceal_update_lines;
|
bool conceal_update_lines;
|
||||||
@ -82,8 +83,11 @@ typedef struct normal_state {
|
|||||||
oparg_T oa; // operator arguments
|
oparg_T oa; // operator arguments
|
||||||
cmdarg_T ca; // command arguments
|
cmdarg_T ca; // command arguments
|
||||||
int mapped_len;
|
int mapped_len;
|
||||||
|
int old_mapped_len;
|
||||||
int idx;
|
int idx;
|
||||||
int c;
|
int c;
|
||||||
|
int old_col;
|
||||||
|
pos_T old_pos;
|
||||||
} NormalState;
|
} NormalState;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -800,179 +804,12 @@ static bool normal_get_command_count(NormalState *s)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int normal_execute(VimState *state, int key)
|
static void normal_finish_command(NormalState *s)
|
||||||
{
|
{
|
||||||
NormalState *s = (NormalState *)state;
|
if (s->command_finished) {
|
||||||
s->ctrl_w = false; /* got CTRL-W command */
|
|
||||||
int old_col = curwin->w_curswant;
|
|
||||||
pos_T old_pos; /* cursor position before command */
|
|
||||||
static int old_mapped_len = 0;
|
|
||||||
s->c = key;
|
|
||||||
|
|
||||||
LANGMAP_ADJUST(s->c, true);
|
|
||||||
|
|
||||||
// If a mapping was started in Visual or Select mode, remember the length
|
|
||||||
// of the mapping. This is used below to not return to Insert mode for as
|
|
||||||
// long as the mapping is being executed.
|
|
||||||
if (restart_edit == 0) {
|
|
||||||
old_mapped_len = 0;
|
|
||||||
} else if (old_mapped_len || (VIsual_active && s->mapped_len == 0
|
|
||||||
&& typebuf_maplen() > 0)) {
|
|
||||||
old_mapped_len = typebuf_maplen();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->c == NUL) {
|
|
||||||
s->c = K_ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In Select mode, typed text replaces the selection.
|
|
||||||
if (VIsual_active && VIsual_select && (vim_isprintc(s->c)
|
|
||||||
|| s->c == NL || s->c == CAR || s->c == K_KENTER)) {
|
|
||||||
// Fake a "c"hange command. When "restart_edit" is set (e.g., because
|
|
||||||
// 'insertmode' is set) fake a "d"elete command, Insert mode will
|
|
||||||
// restart automatically.
|
|
||||||
// Insert the typed character in the typeahead buffer, so that it can
|
|
||||||
// be mapped in Insert mode. Required for ":lmap" to work.
|
|
||||||
ins_char_typebuf(s->c);
|
|
||||||
if (restart_edit != 0) {
|
|
||||||
s->c = 'd';
|
|
||||||
} else {
|
|
||||||
s->c = 'c';
|
|
||||||
}
|
|
||||||
msg_nowait = true; // don't delay going to insert mode
|
|
||||||
old_mapped_len = 0; // do go to Insert mode
|
|
||||||
}
|
|
||||||
|
|
||||||
s->need_flushbuf = add_to_showcmd(s->c);
|
|
||||||
|
|
||||||
while (normal_get_command_count(s)) continue;
|
|
||||||
|
|
||||||
if (s->c == K_EVENT) {
|
|
||||||
// Save the count values so that ca.opcount and ca.count0 are exactly
|
|
||||||
// the same when coming back here after handling K_EVENT.
|
|
||||||
s->oa.prev_opcount = s->ca.opcount;
|
|
||||||
s->oa.prev_count0 = s->ca.count0;
|
|
||||||
} else if (s->ca.opcount != 0) {
|
|
||||||
// If we're in the middle of an operator (including after entering a
|
|
||||||
// yank buffer with '"') AND we had a count before the operator, then
|
|
||||||
// that count overrides the current value of ca.count0.
|
|
||||||
// What this means effectively, is that commands like "3dw" get turned
|
|
||||||
// into "d3w" which makes things fall into place pretty neatly.
|
|
||||||
// If you give a count before AND after the operator, they are
|
|
||||||
// multiplied.
|
|
||||||
if (s->ca.count0) {
|
|
||||||
s->ca.count0 *= s->ca.opcount;
|
|
||||||
} else {
|
|
||||||
s->ca.count0 = s->ca.opcount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always remember the count. It will be set to zero (on the next call,
|
|
||||||
// above) when there is no pending operator.
|
|
||||||
// When called from main(), save the count for use by the "count" built-in
|
|
||||||
// variable.
|
|
||||||
s->ca.opcount = s->ca.count0;
|
|
||||||
s->ca.count1 = (s->ca.count0 == 0 ? 1 : s->ca.count0);
|
|
||||||
|
|
||||||
// Only set v:count when called from main() and not a stuffed command.
|
|
||||||
// Do set it for redo.
|
|
||||||
if (s->toplevel && readbuf1_empty()) {
|
|
||||||
set_vcount(s->ca.count0, s->ca.count1, s->set_prevcount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the command character in the table of commands.
|
|
||||||
// For CTRL-W we already got nchar when looking for a count.
|
|
||||||
if (s->ctrl_w) {
|
|
||||||
s->ca.nchar = s->c;
|
|
||||||
s->ca.cmdchar = Ctrl_W;
|
|
||||||
} else {
|
|
||||||
s->ca.cmdchar = s->c;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->idx = find_command(s->ca.cmdchar);
|
|
||||||
|
|
||||||
if (s->idx < 0) {
|
|
||||||
// Not a known command: beep.
|
|
||||||
clearopbeep(&s->oa);
|
|
||||||
goto normal_end;
|
goto normal_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (text_locked() && (nv_cmds[s->idx].cmd_flags & NV_NCW)) {
|
|
||||||
// This command is not allowed while editing a cmdline: beep.
|
|
||||||
clearopbeep(&s->oa);
|
|
||||||
text_locked_msg();
|
|
||||||
goto normal_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((nv_cmds[s->idx].cmd_flags & NV_NCW) && curbuf_locked()) {
|
|
||||||
goto normal_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In Visual/Select mode, a few keys are handled in a special way.
|
|
||||||
if (VIsual_active && normal_handle_special_visual_command(s)) {
|
|
||||||
goto normal_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curwin->w_p_rl && KeyTyped && !KeyStuffed
|
|
||||||
&& (nv_cmds[s->idx].cmd_flags & NV_RL)) {
|
|
||||||
// Invert horizontal movements and operations. Only when typed by the
|
|
||||||
// user directly, not when the result of a mapping or "x" translated
|
|
||||||
// to "dl".
|
|
||||||
normal_invert_horizontal(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an additional character if we need one.
|
|
||||||
if (normal_need_aditional_char(s)) {
|
|
||||||
normal_get_additional_char(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush the showcmd characters onto the screen so we can see them while
|
|
||||||
// the command is being executed. Only do this when the shown command was
|
|
||||||
// actually displayed, otherwise this will slow down a lot when executing
|
|
||||||
// mappings.
|
|
||||||
if (s->need_flushbuf) {
|
|
||||||
ui_flush();
|
|
||||||
}
|
|
||||||
if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_EVENT) {
|
|
||||||
did_cursorhold = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
State = NORMAL;
|
|
||||||
|
|
||||||
if (s->ca.nchar == ESC) {
|
|
||||||
clearop(&s->oa);
|
|
||||||
if (restart_edit == 0 && goto_im()) {
|
|
||||||
restart_edit = 'a';
|
|
||||||
}
|
|
||||||
goto normal_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->ca.cmdchar != K_IGNORE) {
|
|
||||||
msg_didout = false; // don't scroll screen up for normal command
|
|
||||||
msg_col = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
old_pos = curwin->w_cursor; // remember where cursor was
|
|
||||||
|
|
||||||
// When 'keymodel' contains "startsel" some keys start Select/Visual
|
|
||||||
// mode.
|
|
||||||
if (!VIsual_active && km_startsel) {
|
|
||||||
if (nv_cmds[s->idx].cmd_flags & NV_SS) {
|
|
||||||
start_selection();
|
|
||||||
unshift_special(&s->ca);
|
|
||||||
s->idx = find_command(s->ca.cmdchar);
|
|
||||||
} else if ((nv_cmds[s->idx].cmd_flags & NV_SSS)
|
|
||||||
&& (mod_mask & MOD_MASK_SHIFT)) {
|
|
||||||
start_selection();
|
|
||||||
mod_mask &= ~MOD_MASK_SHIFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the command!
|
|
||||||
// Call the command function found in the commands table.
|
|
||||||
s->ca.arg = nv_cmds[s->idx].cmd_arg;
|
|
||||||
(nv_cmds[s->idx].cmd_func)(&s->ca);
|
|
||||||
|
|
||||||
// If we didn't start or finish an operator, reset oap->regname, unless we
|
// If we didn't start or finish an operator, reset oap->regname, unless we
|
||||||
// need it later.
|
// need it later.
|
||||||
if (!finish_op
|
if (!finish_op
|
||||||
@ -984,12 +821,12 @@ static int normal_execute(VimState *state, int key)
|
|||||||
|
|
||||||
// Get the length of mapped chars again after typing a count, second
|
// Get the length of mapped chars again after typing a count, second
|
||||||
// character or "z333<cr>".
|
// character or "z333<cr>".
|
||||||
if (old_mapped_len > 0) {
|
if (s->old_mapped_len > 0) {
|
||||||
old_mapped_len = typebuf_maplen();
|
s->old_mapped_len = typebuf_maplen();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an operation is pending, handle it...
|
// If an operation is pending, handle it...
|
||||||
do_pending_operator(&s->ca, old_col, false);
|
do_pending_operator(&s->ca, s->old_col, false);
|
||||||
|
|
||||||
// Wait for a moment when a message is displayed that will be overwritten
|
// Wait for a moment when a message is displayed that will be overwritten
|
||||||
// by the mode message.
|
// by the mode message.
|
||||||
@ -1002,8 +839,8 @@ static int normal_execute(VimState *state, int key)
|
|||||||
// Also wait a bit after an error message, e.g. for "^O:".
|
// Also wait a bit after an error message, e.g. for "^O:".
|
||||||
// Don't redraw the screen, it would remove the message.
|
// Don't redraw the screen, it would remove the message.
|
||||||
if (((p_smd && msg_silent == 0 && (restart_edit != 0 || (VIsual_active
|
if (((p_smd && msg_silent == 0 && (restart_edit != 0 || (VIsual_active
|
||||||
&& old_pos.lnum == curwin->w_cursor.lnum
|
&& s->old_pos.lnum == curwin->w_cursor.lnum
|
||||||
&& old_pos.col == curwin->w_cursor.col))
|
&& s->old_pos.col == curwin->w_cursor.col))
|
||||||
&& (clear_cmdline || redraw_cmdline)
|
&& (clear_cmdline || redraw_cmdline)
|
||||||
&& (msg_didout || (msg_didany && msg_scroll))
|
&& (msg_didout || (msg_didany && msg_scroll))
|
||||||
&& !msg_nowait
|
&& !msg_nowait
|
||||||
@ -1089,7 +926,7 @@ normal_end:
|
|||||||
// if still inside a mapping that started in Visual mode).
|
// if still inside a mapping that started in Visual mode).
|
||||||
// May switch from Visual to Select mode after CTRL-O command.
|
// May switch from Visual to Select mode after CTRL-O command.
|
||||||
if (s->oa.op_type == OP_NOP
|
if (s->oa.op_type == OP_NOP
|
||||||
&& ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0)
|
&& ((restart_edit != 0 && !VIsual_active && s->old_mapped_len == 0)
|
||||||
|| restart_VIsual_select == 1)
|
|| restart_VIsual_select == 1)
|
||||||
&& !(s->ca.retval & CA_COMMAND_BUSY)
|
&& !(s->ca.retval & CA_COMMAND_BUSY)
|
||||||
&& stuff_empty()
|
&& stuff_empty()
|
||||||
@ -1099,7 +936,7 @@ normal_end:
|
|||||||
showmode();
|
showmode();
|
||||||
restart_VIsual_select = 0;
|
restart_VIsual_select = 0;
|
||||||
}
|
}
|
||||||
if (restart_edit != 0 && !VIsual_active && old_mapped_len == 0) {
|
if (restart_edit != 0 && !VIsual_active && s->old_mapped_len == 0) {
|
||||||
(void)edit(restart_edit, false, 1L);
|
(void)edit(restart_edit, false, 1L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1110,6 +947,187 @@ normal_end:
|
|||||||
|
|
||||||
// Save count before an operator for next time
|
// Save count before an operator for next time
|
||||||
opcount = s->ca.opcount;
|
opcount = s->ca.opcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int normal_execute(VimState *state, int key)
|
||||||
|
{
|
||||||
|
NormalState *s = (NormalState *)state;
|
||||||
|
s->command_finished = false;
|
||||||
|
s->ctrl_w = false; /* got CTRL-W command */
|
||||||
|
s->old_col = curwin->w_curswant;
|
||||||
|
s->c = key;
|
||||||
|
|
||||||
|
LANGMAP_ADJUST(s->c, true);
|
||||||
|
|
||||||
|
// If a mapping was started in Visual or Select mode, remember the length
|
||||||
|
// of the mapping. This is used below to not return to Insert mode for as
|
||||||
|
// long as the mapping is being executed.
|
||||||
|
if (restart_edit == 0) {
|
||||||
|
s->old_mapped_len = 0;
|
||||||
|
} else if (s->old_mapped_len || (VIsual_active && s->mapped_len == 0
|
||||||
|
&& typebuf_maplen() > 0)) {
|
||||||
|
s->old_mapped_len = typebuf_maplen();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->c == NUL) {
|
||||||
|
s->c = K_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In Select mode, typed text replaces the selection.
|
||||||
|
if (VIsual_active && VIsual_select && (vim_isprintc(s->c)
|
||||||
|
|| s->c == NL || s->c == CAR || s->c == K_KENTER)) {
|
||||||
|
// Fake a "c"hange command. When "restart_edit" is set (e.g., because
|
||||||
|
// 'insertmode' is set) fake a "d"elete command, Insert mode will
|
||||||
|
// restart automatically.
|
||||||
|
// Insert the typed character in the typeahead buffer, so that it can
|
||||||
|
// be mapped in Insert mode. Required for ":lmap" to work.
|
||||||
|
ins_char_typebuf(s->c);
|
||||||
|
if (restart_edit != 0) {
|
||||||
|
s->c = 'd';
|
||||||
|
} else {
|
||||||
|
s->c = 'c';
|
||||||
|
}
|
||||||
|
msg_nowait = true; // don't delay going to insert mode
|
||||||
|
s->old_mapped_len = 0; // do go to Insert mode
|
||||||
|
}
|
||||||
|
|
||||||
|
s->need_flushbuf = add_to_showcmd(s->c);
|
||||||
|
|
||||||
|
while (normal_get_command_count(s)) continue;
|
||||||
|
|
||||||
|
if (s->c == K_EVENT) {
|
||||||
|
// Save the count values so that ca.opcount and ca.count0 are exactly
|
||||||
|
// the same when coming back here after handling K_EVENT.
|
||||||
|
s->oa.prev_opcount = s->ca.opcount;
|
||||||
|
s->oa.prev_count0 = s->ca.count0;
|
||||||
|
} else if (s->ca.opcount != 0) {
|
||||||
|
// If we're in the middle of an operator (including after entering a
|
||||||
|
// yank buffer with '"') AND we had a count before the operator, then
|
||||||
|
// that count overrides the current value of ca.count0.
|
||||||
|
// What this means effectively, is that commands like "3dw" get turned
|
||||||
|
// into "d3w" which makes things fall into place pretty neatly.
|
||||||
|
// If you give a count before AND after the operator, they are
|
||||||
|
// multiplied.
|
||||||
|
if (s->ca.count0) {
|
||||||
|
s->ca.count0 *= s->ca.opcount;
|
||||||
|
} else {
|
||||||
|
s->ca.count0 = s->ca.opcount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always remember the count. It will be set to zero (on the next call,
|
||||||
|
// above) when there is no pending operator.
|
||||||
|
// When called from main(), save the count for use by the "count" built-in
|
||||||
|
// variable.
|
||||||
|
s->ca.opcount = s->ca.count0;
|
||||||
|
s->ca.count1 = (s->ca.count0 == 0 ? 1 : s->ca.count0);
|
||||||
|
|
||||||
|
// Only set v:count when called from main() and not a stuffed command.
|
||||||
|
// Do set it for redo.
|
||||||
|
if (s->toplevel && readbuf1_empty()) {
|
||||||
|
set_vcount(s->ca.count0, s->ca.count1, s->set_prevcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the command character in the table of commands.
|
||||||
|
// For CTRL-W we already got nchar when looking for a count.
|
||||||
|
if (s->ctrl_w) {
|
||||||
|
s->ca.nchar = s->c;
|
||||||
|
s->ca.cmdchar = Ctrl_W;
|
||||||
|
} else {
|
||||||
|
s->ca.cmdchar = s->c;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->idx = find_command(s->ca.cmdchar);
|
||||||
|
|
||||||
|
if (s->idx < 0) {
|
||||||
|
// Not a known command: beep.
|
||||||
|
clearopbeep(&s->oa);
|
||||||
|
s->command_finished = true;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text_locked() && (nv_cmds[s->idx].cmd_flags & NV_NCW)) {
|
||||||
|
// This command is not allowed while editing a cmdline: beep.
|
||||||
|
clearopbeep(&s->oa);
|
||||||
|
text_locked_msg();
|
||||||
|
s->command_finished = true;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nv_cmds[s->idx].cmd_flags & NV_NCW) && curbuf_locked()) {
|
||||||
|
s->command_finished = true;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In Visual/Select mode, a few keys are handled in a special way.
|
||||||
|
if (VIsual_active && normal_handle_special_visual_command(s)) {
|
||||||
|
s->command_finished = true;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curwin->w_p_rl && KeyTyped && !KeyStuffed
|
||||||
|
&& (nv_cmds[s->idx].cmd_flags & NV_RL)) {
|
||||||
|
// Invert horizontal movements and operations. Only when typed by the
|
||||||
|
// user directly, not when the result of a mapping or "x" translated
|
||||||
|
// to "dl".
|
||||||
|
normal_invert_horizontal(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an additional character if we need one.
|
||||||
|
if (normal_need_aditional_char(s)) {
|
||||||
|
normal_get_additional_char(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the showcmd characters onto the screen so we can see them while
|
||||||
|
// the command is being executed. Only do this when the shown command was
|
||||||
|
// actually displayed, otherwise this will slow down a lot when executing
|
||||||
|
// mappings.
|
||||||
|
if (s->need_flushbuf) {
|
||||||
|
ui_flush();
|
||||||
|
}
|
||||||
|
if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_EVENT) {
|
||||||
|
did_cursorhold = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
State = NORMAL;
|
||||||
|
|
||||||
|
if (s->ca.nchar == ESC) {
|
||||||
|
clearop(&s->oa);
|
||||||
|
if (restart_edit == 0 && goto_im()) {
|
||||||
|
restart_edit = 'a';
|
||||||
|
}
|
||||||
|
s->command_finished = true;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->ca.cmdchar != K_IGNORE) {
|
||||||
|
msg_didout = false; // don't scroll screen up for normal command
|
||||||
|
msg_col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->old_pos = curwin->w_cursor; // remember where cursor was
|
||||||
|
|
||||||
|
// When 'keymodel' contains "startsel" some keys start Select/Visual
|
||||||
|
// mode.
|
||||||
|
if (!VIsual_active && km_startsel) {
|
||||||
|
if (nv_cmds[s->idx].cmd_flags & NV_SS) {
|
||||||
|
start_selection();
|
||||||
|
unshift_special(&s->ca);
|
||||||
|
s->idx = find_command(s->ca.cmdchar);
|
||||||
|
} else if ((nv_cmds[s->idx].cmd_flags & NV_SSS)
|
||||||
|
&& (mod_mask & MOD_MASK_SHIFT)) {
|
||||||
|
start_selection();
|
||||||
|
mod_mask &= ~MOD_MASK_SHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the command!
|
||||||
|
// Call the command function found in the commands table.
|
||||||
|
s->ca.arg = nv_cmds[s->idx].cmd_arg;
|
||||||
|
(nv_cmds[s->idx].cmd_func)(&s->ca);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
normal_finish_command(s);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user