Skip to content
Snippets Groups Projects
Commit 5a093437 authored by Bram Moolenaar's avatar Bram Moolenaar
Browse files

patch 8.0.1494: no autocmd triggered in Insert mode with visible popup menu

Problem:    No autocmd triggered in Insert mode with visible popup menu.
Solution:   Add TextChangedP. (Prabir Shrestha, Christian Brabandt,
            closes #2372, closes #1691)
            Fix that the TextChanged autocommands are not always triggered
            when sourcing a script.
parent 9b56a57c
No related branches found
No related tags found
No related merge requests found
*autocmd.txt* For Vim version 8.0. Last change: 2018 Feb 09 *autocmd.txt* For Vim version 8.0. Last change: 2018 Feb 10
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
...@@ -332,6 +332,9 @@ Name triggered by ~ ...@@ -332,6 +332,9 @@ Name triggered by ~
|TextChanged| after a change was made to the text in Normal mode |TextChanged| after a change was made to the text in Normal mode
|TextChangedI| after a change was made to the text in Insert mode |TextChangedI| after a change was made to the text in Insert mode
when popup menu is not visible
|TextChangedP| after a change was made to the text in Insert mode
when popup menu visible
|TextYankPost| after text is yanked or deleted |TextYankPost| after text is yanked or deleted
|ColorScheme| after loading a color scheme |ColorScheme| after loading a color scheme
...@@ -976,6 +979,11 @@ TextChangedI After a change was made to the text in the ...@@ -976,6 +979,11 @@ TextChangedI After a change was made to the text in the
current buffer in Insert mode. current buffer in Insert mode.
Not triggered when the popup menu is visible. Not triggered when the popup menu is visible.
Otherwise the same as TextChanged. Otherwise the same as TextChanged.
*TextChangedP*
TextChangedP After a change was made to the text in the
current buffer in Insert mode, only when the
popup menu is visible. Otherwise the same as
TextChanged.
*TextYankPost* *TextYankPost*
TextYankPost After text has been yanked or deleted in the TextYankPost After text has been yanked or deleted in the
current buffer. The following values of current buffer. The following values of
......
...@@ -1682,17 +1682,28 @@ ins_redraw( ...@@ -1682,17 +1682,28 @@ ins_redraw(
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
/* Trigger TextChangedI if b_changedtick differs. */ /* Trigger TextChangedI if b_changedtick differs. */
if (ready && has_textchangedI() if (ready && has_textchangedI()
&& last_changedtick != CHANGEDTICK(curbuf) && curbuf->b_last_changedtick != CHANGEDTICK(curbuf)
# ifdef FEAT_INS_EXPAND # ifdef FEAT_INS_EXPAND
&& !pum_visible() && !pum_visible()
# endif # endif
) )
{ {
if (last_changedtick_buf == curbuf) apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf);
apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); curbuf->b_last_changedtick = CHANGEDTICK(curbuf);
last_changedtick_buf = curbuf;
last_changedtick = CHANGEDTICK(curbuf);
} }
# ifdef FEAT_INS_EXPAND
/* Trigger TextChangedP if b_changedtick differs. When the popupmenu closes
* TextChangedI will need to trigger for backwards compatibility, thus use
* different b_last_changedtick* variables. */
if (ready && has_textchangedP()
&& curbuf->b_last_changedtick_pum != CHANGEDTICK(curbuf)
&& pum_visible())
{
apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf);
curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf);
}
# endif
#endif #endif
if (must_redraw) if (must_redraw)
......
...@@ -5037,9 +5037,8 @@ restore_backup: ...@@ -5037,9 +5037,8 @@ restore_backup:
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
/* b:changedtick is always incremented in unchanged() but that /* b:changedtick is always incremented in unchanged() but that
* should not trigger a TextChanged event. */ * should not trigger a TextChanged event. */
if (last_changedtick + 1 == CHANGEDTICK(buf) if (buf->b_last_changedtick + 1 == CHANGEDTICK(buf))
&& last_changedtick_buf == buf) buf->b_last_changedtick = CHANGEDTICK(buf);
last_changedtick = CHANGEDTICK(buf);
#endif #endif
u_unchanged(buf); u_unchanged(buf);
u_update_save_nr(buf); u_update_save_nr(buf);
...@@ -7851,6 +7850,7 @@ static struct event_name ...@@ -7851,6 +7850,7 @@ static struct event_name
{"TermResponse", EVENT_TERMRESPONSE}, {"TermResponse", EVENT_TERMRESPONSE},
{"TextChanged", EVENT_TEXTCHANGED}, {"TextChanged", EVENT_TEXTCHANGED},
{"TextChangedI", EVENT_TEXTCHANGEDI}, {"TextChangedI", EVENT_TEXTCHANGEDI},
{"TextChangedP", EVENT_TEXTCHANGEDP},
{"User", EVENT_USER}, {"User", EVENT_USER},
{"VimEnter", EVENT_VIMENTER}, {"VimEnter", EVENT_VIMENTER},
{"VimLeave", EVENT_VIMLEAVE}, {"VimLeave", EVENT_VIMLEAVE},
...@@ -9376,6 +9376,15 @@ has_textchangedI(void) ...@@ -9376,6 +9376,15 @@ has_textchangedI(void)
return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL); return (first_autopat[(int)EVENT_TEXTCHANGEDI] != NULL);
} }
/*
* Return TRUE when there is a TextChangedP autocommand defined.
*/
int
has_textchangedP(void)
{
return (first_autopat[(int)EVENT_TEXTCHANGEDP] != NULL);
}
/* /*
* Return TRUE when there is an InsertCharPre autocommand defined. * Return TRUE when there is an InsertCharPre autocommand defined.
*/ */
......
...@@ -1085,8 +1085,6 @@ EXTERN pos_T last_cursormoved /* for CursorMoved event */ ...@@ -1085,8 +1085,6 @@ EXTERN pos_T last_cursormoved /* for CursorMoved event */
= INIT_POS_T(0, 0, 0) = INIT_POS_T(0, 0, 0)
# endif # endif
; ;
EXTERN varnumber_T last_changedtick INIT(= 0); /* for TextChanged event */
EXTERN buf_T *last_changedtick_buf INIT(= NULL);
#endif #endif
EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */ EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */
......
...@@ -1201,13 +1201,10 @@ main_loop( ...@@ -1201,13 +1201,10 @@ main_loop(
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
/* Trigger TextChanged if b:changedtick differs. */ /* Trigger TextChanged if b:changedtick differs. */
if (!finish_op && has_textchanged() if (!finish_op && has_textchanged()
&& last_changedtick != CHANGEDTICK(curbuf)) && curbuf->b_last_changedtick != CHANGEDTICK(curbuf))
{ {
if (last_changedtick_buf == curbuf) apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, FALSE, curbuf);
apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, curbuf->b_last_changedtick = CHANGEDTICK(curbuf);
FALSE, curbuf);
last_changedtick_buf = curbuf;
last_changedtick = CHANGEDTICK(curbuf);
} }
#endif #endif
......
...@@ -48,6 +48,7 @@ int has_cursormoved(void); ...@@ -48,6 +48,7 @@ int has_cursormoved(void);
int has_cursormovedI(void); int has_cursormovedI(void);
int has_textchanged(void); int has_textchanged(void);
int has_textchangedI(void); int has_textchangedI(void);
int has_textchangedP(void);
int has_insertcharpre(void); int has_insertcharpre(void);
int has_cmdundefined(void); int has_cmdundefined(void);
int has_funcundefined(void); int has_funcundefined(void);
......
...@@ -1983,6 +1983,15 @@ struct file_buffer ...@@ -1983,6 +1983,15 @@ struct file_buffer
incremented for each change, also for undo */ incremented for each change, also for undo */
#define CHANGEDTICK(buf) ((buf)->b_ct_di.di_tv.vval.v_number) #define CHANGEDTICK(buf) ((buf)->b_ct_di.di_tv.vval.v_number)
#ifdef FEAT_AUTOCMD
varnumber_T b_last_changedtick; /* b:changedtick when TextChanged or
TextChangedI was last triggered. */
# ifdef FEAT_INS_EXPAND
varnumber_T b_last_changedtick_pum; /* b:changedtick when TextChangedP was
last triggered. */
# endif
#endif
int b_saving; /* Set to TRUE if we are in the middle of int b_saving; /* Set to TRUE if we are in the middle of
saving the buffer. */ saving the buffer. */
......
...@@ -1249,3 +1249,58 @@ function Test_dirchanged_auto() ...@@ -1249,3 +1249,58 @@ function Test_dirchanged_auto()
bwipe! bwipe!
call s:After_test_dirchanged() call s:After_test_dirchanged()
endfunc endfunc
" Test TextChangedI and TextChangedP
func Test_ChangedP()
new
call setline(1, ['foo', 'bar', 'foobar'])
call test_override("char_avail", 1)
set complete=. completeopt=menuone
func! TextChangedAutocmd(char)
let g:autocmd .= a:char
endfunc
au! TextChanged <buffer> :call TextChangedAutocmd('N')
au! TextChangedI <buffer> :call TextChangedAutocmd('I')
au! TextChangedP <buffer> :call TextChangedAutocmd('P')
call cursor(3, 1)
let g:autocmd = ''
call feedkeys("o\<esc>", 'tnix')
call assert_equal('I', g:autocmd)
let g:autocmd = ''
call feedkeys("Sf", 'tnix')
call assert_equal('II', g:autocmd)
let g:autocmd = ''
call feedkeys("Sf\<C-N>", 'tnix')
call assert_equal('IIP', g:autocmd)
let g:autocmd = ''
call feedkeys("Sf\<C-N>\<C-N>", 'tnix')
call assert_equal('IIPP', g:autocmd)
let g:autocmd = ''
call feedkeys("Sf\<C-N>\<C-N>\<C-N>", 'tnix')
call assert_equal('IIPPP', g:autocmd)
let g:autocmd = ''
call feedkeys("Sf\<C-N>\<C-N>\<C-N>\<C-N>", 'tnix')
call assert_equal('IIPPPP', g:autocmd)
call assert_equal(['foo', 'bar', 'foobar', 'foo'], getline(1, '$'))
" TODO: how should it handle completeopt=noinsert,noselect?
" CleanUp
call test_override("char_avail", 0)
au! TextChanged
au! TextChangedI
au! TextChangedP
delfu TextChangedAutocmd
unlet! g:autocmd
set complete&vim completeopt&vim
bw!
endfunc
...@@ -771,6 +771,8 @@ static char *(features[]) = ...@@ -771,6 +771,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1494,
/**/ /**/
1493, 1493,
/**/ /**/
......
...@@ -1337,8 +1337,11 @@ enum auto_event ...@@ -1337,8 +1337,11 @@ enum auto_event
EVENT_TABCLOSED, /* after closing a tab page */ EVENT_TABCLOSED, /* after closing a tab page */
EVENT_SHELLCMDPOST, /* after ":!cmd" */ EVENT_SHELLCMDPOST, /* after ":!cmd" */
EVENT_SHELLFILTERPOST, /* after ":1,2!cmd", ":w !cmd", ":r !cmd". */ EVENT_SHELLFILTERPOST, /* after ":1,2!cmd", ":w !cmd", ":r !cmd". */
EVENT_TEXTCHANGED, /* text was modified */ EVENT_TEXTCHANGED, /* text was modified not in Insert mode */
EVENT_TEXTCHANGEDI, /* text was modified in Insert mode*/ EVENT_TEXTCHANGEDI, /* text was modified in Insert mode without
popup menu visible */
EVENT_TEXTCHANGEDP, /* text was modified in Insert mode with popup
menu visible */
EVENT_CMDUNDEFINED, /* command undefined */ EVENT_CMDUNDEFINED, /* command undefined */
EVENT_OPTIONSET, /* option was set */ EVENT_OPTIONSET, /* option was set */
EVENT_TEXTYANKPOST, /* after some text was yanked */ EVENT_TEXTYANKPOST, /* after some text was yanked */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment