diff options
| -rw-r--r-- | src/nvim/edit.c | 64 | ||||
| -rw-r--r-- | src/nvim/screen.c | 12 | ||||
| -rw-r--r-- | src/nvim/testdir/test_autocmd.vim | 26 | 
3 files changed, 83 insertions, 19 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 6231ecd977..085f12473e 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -276,7 +276,7 @@ static void insert_enter(InsertState *s)      set_vim_var_string(VV_INSERTMODE, (char *) s->ptr, 1);      set_vim_var_string(VV_CHAR, NULL, -1); -    apply_autocmds(EVENT_INSERTENTER, NULL, NULL, false, curbuf); +    ins_apply_autocmds(EVENT_INSERTENTER);      // Make sure the cursor didn't move.  Do call check_cursor_col() in      // case the text was modified.  Since Insert mode was not started yet @@ -469,7 +469,7 @@ static void insert_enter(InsertState *s)    foldUpdateAfterInsert();    if (s->cmdchar != 'r' && s->cmdchar != 'v') { -    apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL, false, curbuf); +    ins_apply_autocmds(EVENT_INSERTLEAVE);    }    did_cursorhold = false;  } @@ -1376,7 +1376,7 @@ ins_redraw (        // Make sure curswant is correct, an autocommand may call        // getcurpos()        update_curswant(); -      apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, false, curbuf); +      ins_apply_autocmds(EVENT_CURSORMOVEDI);      }      if (curwin->w_p_cole > 0) {        conceal_old_cursor_line = last_cursormoved.lnum; @@ -1390,8 +1390,18 @@ ins_redraw (    if (ready && has_event(EVENT_TEXTCHANGEDI)        && curbuf->b_last_changedtick != buf_get_changedtick(curbuf)        && !pum_visible()) { +    aco_save_T aco; +    varnumber_T tick = buf_get_changedtick(curbuf); + +    // save and restore curwin and curbuf, in case the autocmd changes them +    aucmd_prepbuf(&aco, curbuf);      apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf); +    aucmd_restbuf(&aco);      curbuf->b_last_changedtick = buf_get_changedtick(curbuf); +    if (tick != buf_get_changedtick(curbuf)) {  // see ins_apply_autocmds() +      u_save(curwin->w_cursor.lnum, +             (linenr_T)(curwin->w_cursor.lnum + 1)); +    }    }    // Trigger TextChangedP if changedtick differs. When the popupmenu closes @@ -1400,8 +1410,18 @@ ins_redraw (    if (ready && has_event(EVENT_TEXTCHANGEDP)        && curbuf->b_last_changedtick_pum != buf_get_changedtick(curbuf)        && pum_visible()) { -      apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, false, curbuf); -      curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf); +    aco_save_T aco; +    varnumber_T tick = buf_get_changedtick(curbuf); + +    // save and restore curwin and curbuf, in case the autocmd changes them +    aucmd_prepbuf(&aco, curbuf); +    apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, false, curbuf); +    aucmd_restbuf(&aco); +    curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf); +    if (tick != buf_get_changedtick(curbuf)) {  // see ins_apply_autocmds() +      u_save(curwin->w_cursor.lnum, +             (linenr_T)(curwin->w_cursor.lnum + 1)); +    }    }    if (must_redraw) @@ -3392,12 +3412,12 @@ static bool ins_compl_prep(int c)          do_c_expr_indent();        /* Trigger the CompleteDone event to give scripts a chance to act         * upon the completion. */ -      apply_autocmds(EVENT_COMPLETEDONE, NULL, NULL, FALSE, curbuf); +      ins_apply_autocmds(EVENT_COMPLETEDONE);      }    } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)      /* Trigger the CompleteDone event to give scripts a chance to act       * upon the (possibly failed) completion. */ -    apply_autocmds(EVENT_COMPLETEDONE, NULL, NULL, FALSE, curbuf); +    ins_apply_autocmds(EVENT_COMPLETEDONE);    /* reset continue_* if we left expansion-mode, if we stay they'll be     * (re)set properly in ins_complete() */ @@ -7399,7 +7419,7 @@ static void ins_insert(int replaceState)    set_vim_var_string(VV_INSERTMODE, ((State & REPLACE_FLAG) ? "i" :                                       replaceState == VREPLACE ? "v" :                                       "r"), 1); -  apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, false, curbuf); +  ins_apply_autocmds(EVENT_INSERTCHANGE);    if (State & REPLACE_FLAG) {      State = INSERT | (State & LANGMAP);    } else { @@ -8661,12 +8681,13 @@ static char_u *do_insert_char_pre(int c)    set_vim_var_string(VV_CHAR, buf, -1);    char_u *res = NULL; -  if (apply_autocmds(EVENT_INSERTCHARPRE, NULL, NULL, FALSE, curbuf)) { -    /* Get the value of v:char.  It may be empty or more than one -     * character.  Only use it when changed, otherwise continue with the -     * original character to avoid breaking autoindent. */ -    if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) +  if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) { +    // Get the value of v:char.  It may be empty or more than one +    // character.  Only use it when changed, otherwise continue with the +    // original character to avoid breaking autoindent. +    if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) {        res = vim_strsave(get_vim_var_str(VV_CHAR)); +    }    }    set_vim_var_string(VV_CHAR, NULL, -1); @@ -8675,6 +8696,23 @@ static char_u *do_insert_char_pre(int c)    return res;  } +/// Trigger "event" and take care of fixing undo. +static int ins_apply_autocmds(event_T event) +{ +  varnumber_T tick = buf_get_changedtick(curbuf); +  int r; + +  r = apply_autocmds(event, NULL, NULL, false, curbuf); + +  // If u_savesub() was called then we are not prepared to start +  // a new line.  Call u_save() with no contents to fix that. +  if (tick != buf_get_changedtick(curbuf)) { +    u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); +  } + +  return r; +} +  static void show_pum(int prev_w_wrow, int prev_w_leftcol)  {    // RedrawingDisabled may be set when invoked through complete(). diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 31b0d0aa54..bcfef89cc2 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -423,7 +423,7 @@ void update_screen(int type)      /* redraw status line after the window to minimize cursor movement */      if (wp->w_redr_status) { -      win_redr_status(wp); +      win_redr_status(wp, true);  // any popup menu will be redrawn below      }    }    end_search_hl(); @@ -589,7 +589,7 @@ void update_debug_sign(const buf_T *const buf, const linenr_T lnum)        win_update(wp);      }      if (wp->w_redr_status) { -      win_redr_status(wp); +      win_redr_status(wp, false);      }    } @@ -4542,7 +4542,7 @@ void redraw_statuslines(void)  {    FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {      if (wp->w_redr_status) { -      win_redr_status(wp); +      win_redr_status(wp, false);      }    }    if (redraw_tabline) @@ -4809,7 +4809,9 @@ win_redr_status_matches (  /// Redraw the status line of window `wp`.  ///  /// If inversion is possible we use it. Else '=' characters are used. -static void win_redr_status(win_T *wp) +/// If "ignore_pum" is true, also redraw statusline when the popup menu is +/// displayed. +static void win_redr_status(win_T *wp, int ignore_pum)  {    int row;    char_u      *p; @@ -4832,7 +4834,7 @@ static void win_redr_status(win_T *wp)    if (wp->w_status_height == 0) {      // no status line, can only be last window      redraw_cmdline = true; -  } else if (!redrawing() || pum_drawn()) { +  } else if (!redrawing() || (!ignore_pum && pum_drawn())) {      // Don't redraw right now, do it later. Don't update status line when      // popup menu is visible and may be drawn over it      wp->w_redr_status = true; diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 772b3f721c..e4ab3ccea8 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -567,7 +567,7 @@ func Test_OptionSet()    " Cleanup    au! OptionSet    for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp'] -    exe printf(":set %s&vi", opt) +    exe printf(":set %s&vim", opt)    endfor    call test_override('starting', 0)    delfunc! AutoCommandOptionSet @@ -1221,3 +1221,27 @@ func Test_ChangedP()    bw!  endfunc + +let g:setline_handled = v:false +func! SetLineOne() +  if !g:setline_handled +    call setline(1, "(x)") +    let g:setline_handled = v:true +  endif +endfunc + +func Test_TextChangedI_with_setline() +  throw 'skipped: Nvim does not support test_override()' +  new +  call test_override('char_avail', 1) +  autocmd TextChangedI <buffer> call SetLineOne() +  call feedkeys("i(\<CR>\<Esc>", 'tx') +  call assert_equal('(', getline(1)) +  call assert_equal('x)', getline(2)) +  undo +  call assert_equal('', getline(1)) +  call assert_equal('', getline(2)) + +  call test_override('starting', 0) +  bwipe! +endfunc  | 
