diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vim.c | 5 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 3 | ||||
-rw-r--r-- | src/nvim/edit.c | 14 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 8 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 4 | ||||
-rw-r--r-- | src/nvim/globals.h | 6 | ||||
-rw-r--r-- | src/nvim/memory.c | 1 | ||||
-rw-r--r-- | src/nvim/normal.c | 16 | ||||
-rw-r--r-- | src/nvim/state.c | 85 | ||||
-rw-r--r-- | src/nvim/terminal.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_autocmd.vim | 18 | ||||
-rw-r--r-- | src/nvim/vim.h | 2 |
13 files changed, 95 insertions, 71 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 7c7ada55a2..503a1c9f23 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1549,10 +1549,11 @@ Dictionary nvim_get_mode(void) FUNC_API_SINCE(2) FUNC_API_FAST { Dictionary rv = ARRAY_DICT_INIT; - char *modestr = get_mode(); + char modestr[MODE_MAX_LENGTH]; + get_mode(modestr); bool blocked = input_blocking(); - PUT(rv, "mode", STRING_OBJ(cstr_as_string(modestr))); + PUT(rv, "mode", STRING_OBJ(cstr_to_string(modestr))); PUT(rv, "blocking", BOOLEAN_OBJ(blocked)); return rv; diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 48c1bb740d..f65b5ba983 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1083,8 +1083,7 @@ int autocmd_register(int64_t id, event_T event, char_u *pat, int patlen, int gro // need to initialize last_mode for the first ModeChanged autocmd if (event == EVENT_MODECHANGED && !has_event(EVENT_MODECHANGED)) { - xfree(last_mode); - last_mode = get_mode(); + get_mode(last_mode); } // If the event is CursorMoved, update the last cursor position diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 3eb4ab9517..e223841326 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -387,7 +387,7 @@ static void insert_enter(InsertState *s) State = INSERT; } - trigger_modechanged(); + may_trigger_modechanged(); stop_insert_mode = false; // need to position cursor again when on a TAB @@ -2097,7 +2097,7 @@ static void ins_ctrl_x(void) ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X; } - trigger_modechanged(); + may_trigger_modechanged(); } // Whether other than default completion has been selected. @@ -2710,7 +2710,7 @@ void set_completion(colnr_T startcol, list_T *list) show_pum(save_w_wrow, save_w_leftcol); } - trigger_modechanged(); + may_trigger_modechanged(); ui_flush(); } @@ -3890,7 +3890,7 @@ static bool ins_compl_prep(int c) ins_apply_autocmds(EVENT_COMPLETEDONE); } - trigger_modechanged(); + may_trigger_modechanged(); /* reset continue_* if we left expansion-mode, if we stay they'll be * (re)set properly in ins_complete() */ @@ -4641,7 +4641,7 @@ static int ins_compl_get_exp(pos_T *ini) compl_curr_match = compl_old_match; } } - trigger_modechanged(); + may_trigger_modechanged(); return i; } @@ -8051,7 +8051,7 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) State = NORMAL; - trigger_modechanged(); + may_trigger_modechanged(); // need to position cursor again when on a TAB if (gchar_cursor() == TAB) { curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); @@ -8155,7 +8155,7 @@ static void ins_insert(int replaceState) } else { State = replaceState | (State & LANGMAP); } - trigger_modechanged(); + may_trigger_modechanged(); AppendCharToRedobuff(K_INS); showmode(); ui_cursor_shape(); // may show different cursor shape diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index f7d9f76534..d365e075e6 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6094,15 +6094,17 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "mode()" function static void f_mode(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - char *mode = get_mode(); + char buf[MODE_MAX_LENGTH]; + + get_mode(buf); // Clear out the minor mode when the argument is not a non-zero number or // non-empty string. if (!non_zero_arg(&argvars[0])) { - mode[1] = NUL; + buf[1] = NUL; } - rettv->vval.v_string = (char_u *)mode; + rettv->vval.v_string = vim_strsave((char_u *)buf); rettv->v_type = VAR_STRING; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1f17101aca..482bf69f67 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -187,7 +187,7 @@ void do_exmode(void) exmode_active = true; State = NORMAL; - trigger_modechanged(); + may_trigger_modechanged(); // When using ":global /pat/ visual" and then "Q" we return to continue // the :global command. diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index dd6e4630d2..a7c0b06050 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -921,7 +921,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent, bool init } tl_ret = true; } - trigger_modechanged(); + may_trigger_modechanged(); state_enter(&s->state); @@ -6556,7 +6556,7 @@ static int open_cmdwin(void) cmdmsg_rl = save_cmdmsg_rl; State = save_State; - trigger_modechanged(); + may_trigger_modechanged(); setmouse(); return cmdwin_result; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 4aa49337cf..42a7fcc3ab 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -746,7 +746,11 @@ EXTERN bool listcmd_busy INIT(= false); // set when :argdo, :windo or // :bufdo is executing EXTERN bool need_start_insertmode INIT(= false); // start insert mode soon -EXTERN char *last_mode INIT(= NULL); + +#define MODE_MAX_LENGTH 4 // max mode length returned in get_mode() + // including the final NUL character + +EXTERN char last_mode[MODE_MAX_LENGTH] INIT(= "n"); EXTERN char_u *last_cmdline INIT(= NULL); // last command line (for ":) EXTERN char_u *repeat_cmdline INIT(= NULL); // command line for "." EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline diff --git a/src/nvim/memory.c b/src/nvim/memory.c index c895cc1ec6..14930238e5 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -631,7 +631,6 @@ void free_all_mem(void) clear_sb_text(true); // free any scrollback text // Free some global vars. - xfree(last_mode); xfree(last_cmdline); xfree(new_last_cmdline); set_keep_msg(NULL, 0); diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 9cee2de0c5..dcfd73a631 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -481,7 +481,7 @@ static void normal_prepare(NormalState *s) if (finish_op != c) { ui_cursor_shape(); // may show different cursor shape } - trigger_modechanged(); + may_trigger_modechanged(); // When not finishing an operator and no register name typed, reset the count. if (!finish_op && !s->oa.regname) { @@ -920,7 +920,7 @@ normal_end: // Reset finish_op, in case it was set s->c = finish_op; finish_op = false; - trigger_modechanged(); + may_trigger_modechanged(); // Redraw the cursor with another shape, if we were in Operator-pending // mode or did a replace command. if (s->c || s->ca.cmdchar == 'r') { @@ -959,7 +959,7 @@ normal_end: if (restart_VIsual_select == 1) { VIsual_select = true; VIsual_select_reg = 0; - trigger_modechanged(); + may_trigger_modechanged(); showmode(); restart_VIsual_select = 0; } @@ -2299,7 +2299,7 @@ void end_visual_mode(void) may_clear_cmdline(); adjust_cursor_eol(); - trigger_modechanged(); + may_trigger_modechanged(); } /* @@ -4113,7 +4113,7 @@ static void nv_ctrlg(cmdarg_T *cap) { if (VIsual_active) { // toggle Selection/Visual mode VIsual_select = !VIsual_select; - trigger_modechanged(); + may_trigger_modechanged(); showmode(); } else if (!checkclearop(cap->oap)) { // print full name if count given or :cd used @@ -4157,7 +4157,7 @@ static void nv_ctrlo(cmdarg_T *cap) { if (VIsual_active && VIsual_select) { VIsual_select = false; - trigger_modechanged(); + may_trigger_modechanged(); showmode(); restart_VIsual_select = 2; // restart Select mode later } else { @@ -5945,7 +5945,7 @@ static void nv_visual(cmdarg_T *cap) // or char/line mode VIsual_mode = cap->cmdchar; showmode(); - trigger_modechanged(); + may_trigger_modechanged(); } redraw_curbuf_later(INVERTED); // update the inversion } else { // start Visual mode @@ -6056,7 +6056,7 @@ static void n_start_visual_mode(int c) foldAdjustVisual(); - trigger_modechanged(); + may_trigger_modechanged(); setmouse(); // Check for redraw after changing the state. conceal_check_cursor_line(); diff --git a/src/nvim/state.c b/src/nvim/state.c index 34e3ddf654..056828574f 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -156,102 +156,105 @@ int get_real_state(void) return State; } -/// @returns[allocated] mode string -char *get_mode(void) +/// Returns the current mode as a string in "buf[MODE_MAX_LENGTH]", NUL +/// terminated. +/// The first character represents the major mode, the following ones the minor +/// ones. +void get_mode(char *buf) { - char *buf = xcalloc(MODE_MAX_LENGTH, sizeof(char)); + int i = 0; if (VIsual_active) { if (VIsual_select) { - buf[0] = (char)(VIsual_mode + 's' - 'v'); + buf[i++] = (char)(VIsual_mode + 's' - 'v'); } else { - buf[0] = (char)VIsual_mode; + buf[i++] = (char)VIsual_mode; if (restart_VIsual_select) { - buf[1] = 's'; + buf[i++] = 's'; } } } else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE || State == CONFIRM) { - buf[0] = 'r'; + buf[i++] = 'r'; if (State == ASKMORE) { - buf[1] = 'm'; + buf[i++] = 'm'; } else if (State == CONFIRM) { - buf[1] = '?'; + buf[i++] = '?'; } } else if (State == EXTERNCMD) { - buf[0] = '!'; + buf[i++] = '!'; } else if (State & INSERT) { if (State & VREPLACE_FLAG) { - buf[0] = 'R'; - buf[1] = 'v'; + buf[i++] = 'R'; + buf[i++] = 'v'; if (ins_compl_active()) { - buf[2] = 'c'; + buf[i++] = 'c'; } else if (ctrl_x_mode_not_defined_yet()) { - buf[2] = 'x'; + buf[i++] = 'x'; } } else { if (State & REPLACE_FLAG) { - buf[0] = 'R'; + buf[i++] = 'R'; } else { - buf[0] = 'i'; + buf[i++] = 'i'; } if (ins_compl_active()) { - buf[1] = 'c'; + buf[i++] = 'c'; } else if (ctrl_x_mode_not_defined_yet()) { - buf[1] = 'x'; + buf[i++] = 'x'; } } } else if ((State & CMDLINE) || exmode_active) { - buf[0] = 'c'; + buf[i++] = 'c'; if (exmode_active) { - buf[1] = 'v'; + buf[i++] = 'v'; } } else if (State & TERM_FOCUS) { - buf[0] = 't'; + buf[i++] = 't'; } else { - buf[0] = 'n'; + buf[i++] = 'n'; if (finish_op) { - buf[1] = 'o'; + buf[i++] = 'o'; // to be able to detect force-linewise/blockwise/charwise operations - buf[2] = (char)motion_force; + buf[i++] = (char)motion_force; } else if (restart_edit == 'I' || restart_edit == 'R' || restart_edit == 'V') { - buf[1] = 'i'; - buf[2] = (char)restart_edit; + buf[i++] = 'i'; + buf[i++] = (char)restart_edit; } else if (curbuf->terminal) { - buf[1] = 't'; + buf[i++] = 't'; } } - return buf; + buf[i] = NUL; } -/// Fires a ModeChanged autocmd. -void trigger_modechanged(void) +/// Fires a ModeChanged autocmd if appropriate. +void may_trigger_modechanged(void) { if (!has_event(EVENT_MODECHANGED)) { return; } - char *mode = get_mode(); - if (STRCMP(mode, last_mode) == 0) { - xfree(mode); + char curr_mode[MODE_MAX_LENGTH]; + char_u pattern_buf[2 * MODE_MAX_LENGTH]; + + get_mode(curr_mode); + if (STRCMP(curr_mode, last_mode) == 0) { return; } save_v_event_T save_v_event; dict_T *v_event = get_v_event(&save_v_event); - tv_dict_add_str(v_event, S_LEN("new_mode"), mode); + tv_dict_add_str(v_event, S_LEN("new_mode"), curr_mode); tv_dict_add_str(v_event, S_LEN("old_mode"), last_mode); + tv_dict_set_keys_readonly(v_event); - char_u *pat_pre = concat_str((char_u *)last_mode, (char_u *)":"); - char_u *pat = concat_str(pat_pre, (char_u *)mode); - xfree(pat_pre); + // concatenate modes in format "old_mode:new_mode" + vim_snprintf((char *)pattern_buf, sizeof(pattern_buf), "%s:%s", last_mode, curr_mode); - apply_autocmds(EVENT_MODECHANGED, pat, NULL, false, curbuf); - xfree(last_mode); - last_mode = mode; + apply_autocmds(EVENT_MODECHANGED, pattern_buf, NULL, false, curbuf); + STRCPY(last_mode, curr_mode); - xfree(pat); restore_v_event(v_event, &save_v_event); } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 5c8789ec37..f4baa92f5b 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -422,7 +422,7 @@ void terminal_enter(void) curwin->w_redr_status = true; // For mode() in statusline. #8323 ui_busy_start(); apply_autocmds(EVENT_TERMENTER, NULL, NULL, false, curbuf); - trigger_modechanged(); + may_trigger_modechanged(); s->state.execute = terminal_execute; s->state.check = terminal_check; diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index c1a120efa4..e3362cd28f 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2661,5 +2661,23 @@ func Test_bufwipeout_changes_window() %bwipe! endfunc +func Test_v_event_readonly() + autocmd CompleteChanged * let v:event.width = 0 + call assert_fails("normal! i\<C-X>\<C-V>", 'E46:') + au! CompleteChanged + + autocmd DirChangedPre * let v:event.directory = '' + call assert_fails('cd .', 'E46:') + au! DirChangedPre + + autocmd ModeChanged * let v:event.new_mode = '' + call assert_fails('normal! cc', 'E46:') + au! ModeChanged + + autocmd TextYankPost * let v:event.operator = '' + call assert_fails('normal! yy', 'E46:') + au! TextYankPost +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/vim.h b/src/nvim/vim.h index f65dd4f0d4..64333e9c3d 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -72,8 +72,6 @@ enum { NUMBUFLEN = 65, }; #define TERM_FOCUS 0x2000 // Terminal focus mode #define CMDPREVIEW 0x4000 // Showing 'inccommand' command "live" preview. -#define MODE_MAX_LENGTH 4 // max mode length returned in mode() - // all mode bits used for mapping #define MAP_ALL_MODES (0x3f | SELECTMODE | TERM_FOCUS) |