mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.1.1321: no docs or tests for listener functions
Problem: No docs or tests for listener functions. Solution: Add help and tests for listener_add() and listener_remove(). Invoke the callbacks before redrawing.
This commit is contained in:
parent
6d2399bd10
commit
a334772967
@ -2457,6 +2457,9 @@ line({expr}) Number line nr of cursor, last line or mark
|
||||
line2byte({lnum}) Number byte count of line {lnum}
|
||||
lispindent({lnum}) Number Lisp indent for line {lnum}
|
||||
list2str({list} [, {utf8}]) String turn numbers in {list} into a String
|
||||
listener_add({callback} [, {buf}])
|
||||
Number add a callback to listen to changes
|
||||
listener_remove({id}) none remove a listener callback
|
||||
localtime() Number current time
|
||||
log({expr}) Float natural logarithm (base e) of {expr}
|
||||
log10({expr}) Float logarithm of Float {expr} to base 10
|
||||
@ -6311,6 +6314,53 @@ list2str({list} [, {utf8}]) *list2str()*
|
||||
With utf-8 composing characters work as expected: >
|
||||
list2str([97, 769]) returns "á"
|
||||
<
|
||||
listener_add({callback} [, {buf}]) *listener_add()*
|
||||
Add a callback function that will be invoked when changes have
|
||||
been made to buffer {buf}.
|
||||
{buf} refers to a buffer name or number. For the accepted
|
||||
values, see |bufname()|. When {buf} is omitted the current
|
||||
buffer is used.
|
||||
Returns a unique ID that can be passed to |listener_remove()|.
|
||||
|
||||
The {callback} is invoked with a list of items that indicate a
|
||||
change. Each list item is a dictionary with these entries:
|
||||
lnum the first line number of the change
|
||||
end the first line below the change
|
||||
added number of lines added; negative if lines were
|
||||
deleted
|
||||
col first column in "lnum" that was affected by
|
||||
the change; one if unknown or the whole line
|
||||
was affected; this is a byte index, first
|
||||
character has a value of one.
|
||||
When lines are inserted the values are:
|
||||
lnum line below which the new line is added
|
||||
end equal to "lnum"
|
||||
added number of lines inserted
|
||||
col one
|
||||
When lines are deleted the values are:
|
||||
lnum the first deleted line
|
||||
end the line below the first deleted line, before
|
||||
the deletion was done
|
||||
added negative, number of lines deleted
|
||||
col one
|
||||
When lines are changed:
|
||||
lnum the first changed line
|
||||
end the line below the last changed line
|
||||
added zero
|
||||
col first column with a change or one
|
||||
|
||||
The {callback} is invoked just before the screen is updated.
|
||||
To trigger this in a script use the `:redraw` command.
|
||||
|
||||
The {callback} is not invoked when the buffer is first loaded.
|
||||
Use the |BufReadPost| autocmd event to handle the initial text
|
||||
of a buffer.
|
||||
The {callback} is also not invoked when the buffer is
|
||||
unloaded, use the |BufUnload| autocmd event for that.
|
||||
|
||||
listener_remove({id}) *listener_remove()*
|
||||
Remove a listener previously added with listener_add().
|
||||
|
||||
localtime() *localtime()*
|
||||
Return the current time, measured as seconds since 1st Jan
|
||||
1970. See also |strftime()| and |getftime()|.
|
||||
|
@ -812,6 +812,8 @@ Buffers, windows and the argument list:
|
||||
setbufline() replace a line in the specified buffer
|
||||
appendbufline() append a list of lines in the specified buffer
|
||||
deletebufline() delete lines from a specified buffer
|
||||
listener_add() add a callback to listen to changes
|
||||
listener_remove() remove a listener callback
|
||||
win_findbuf() find windows containing a buffer
|
||||
win_getid() get window ID of a window
|
||||
win_gotoid() go to window with ID
|
||||
|
17
src/change.c
17
src/change.c
@ -184,7 +184,7 @@ may_record_change(
|
||||
dict_add_number(dict, "lnum", (varnumber_T)lnum);
|
||||
dict_add_number(dict, "end", (varnumber_T)lnume);
|
||||
dict_add_number(dict, "added", (varnumber_T)xtra);
|
||||
dict_add_number(dict, "col", (varnumber_T)col);
|
||||
dict_add_number(dict, "col", (varnumber_T)col + 1);
|
||||
|
||||
list_append_dict(recorded_changes, dict);
|
||||
}
|
||||
@ -198,19 +198,27 @@ f_listener_add(typval_T *argvars, typval_T *rettv)
|
||||
char_u *callback;
|
||||
partial_T *partial;
|
||||
listener_T *lnr;
|
||||
buf_T *buf = curbuf;
|
||||
|
||||
callback = get_callback(&argvars[0], &partial);
|
||||
if (callback == NULL)
|
||||
return;
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
buf = get_buf_arg(&argvars[1]);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
lnr = (listener_T *)alloc_clear((sizeof(listener_T)));
|
||||
if (lnr == NULL)
|
||||
{
|
||||
free_callback(callback, partial);
|
||||
return;
|
||||
}
|
||||
lnr->lr_next = curbuf->b_listener;
|
||||
curbuf->b_listener = lnr;
|
||||
lnr->lr_next = buf->b_listener;
|
||||
buf->b_listener = lnr;
|
||||
|
||||
if (partial == NULL)
|
||||
lnr->lr_callback = vim_strsave(callback);
|
||||
@ -232,8 +240,9 @@ f_listener_remove(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
listener_T *next;
|
||||
listener_T *prev = NULL;
|
||||
int id = tv_get_number(argvars);
|
||||
buf_T *buf = curbuf;
|
||||
buf_T *buf;
|
||||
|
||||
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
|
||||
for (lnr = buf->b_listener; lnr != NULL; lnr = next)
|
||||
{
|
||||
next = lnr->lr_next;
|
||||
|
@ -2009,12 +2009,11 @@ tv_get_buf(typval_T *tv, int curtab_only)
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef FEAT_SIGNS
|
||||
/*
|
||||
* Get the buffer from "arg" and give an error and return NULL if it is not
|
||||
* valid.
|
||||
*/
|
||||
static buf_T *
|
||||
buf_T *
|
||||
get_buf_arg(typval_T *arg)
|
||||
{
|
||||
buf_T *buf;
|
||||
@ -2026,7 +2025,6 @@ get_buf_arg(typval_T *arg)
|
||||
semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "bufname(expr)" function
|
||||
|
@ -5,6 +5,7 @@ int find_internal_func(char_u *name);
|
||||
int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);
|
||||
buf_T *buflist_find_by_name(char_u *name, int curtab_only);
|
||||
buf_T *tv_get_buf(typval_T *tv, int curtab_only);
|
||||
buf_T *get_buf_arg(typval_T *arg);
|
||||
void execute_redir_str(char_u *value, int value_len);
|
||||
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
|
||||
float_T vim_round(float_T f);
|
||||
|
@ -564,6 +564,11 @@ update_screen(int type_arg)
|
||||
type = 0;
|
||||
}
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
// Before updating the screen, notify any listeners of changed text.
|
||||
invoke_listeners();
|
||||
#endif
|
||||
|
||||
if (must_redraw)
|
||||
{
|
||||
if (type < must_redraw) /* use maximal type */
|
||||
|
@ -168,6 +168,7 @@ NEW_TESTS = \
|
||||
test_lispwords \
|
||||
test_listchars \
|
||||
test_listdict \
|
||||
test_listener \
|
||||
test_listlbr \
|
||||
test_listlbr_utf8 \
|
||||
test_lua \
|
||||
@ -359,6 +360,7 @@ NEW_TESTS_RES = \
|
||||
test_lineending.res \
|
||||
test_listchars.res \
|
||||
test_listdict.res \
|
||||
test_listener.res \
|
||||
test_listlbr.res \
|
||||
test_lua.res \
|
||||
test_makeencoding.res \
|
||||
|
77
src/testdir/test_listener.vim
Normal file
77
src/testdir/test_listener.vim
Normal file
@ -0,0 +1,77 @@
|
||||
" tests for listener_add() and listener_remove()
|
||||
|
||||
func StoreList(l)
|
||||
let g:list = a:l
|
||||
endfunc
|
||||
|
||||
func AnotherStoreList(l)
|
||||
let g:list2 = a:l
|
||||
endfunc
|
||||
|
||||
func EvilStoreList(l)
|
||||
let g:list3 = a:l
|
||||
call assert_fails("call add(a:l, 'myitem')", "E742:")
|
||||
endfunc
|
||||
|
||||
func Test_listening()
|
||||
new
|
||||
call setline(1, ['one', 'two'])
|
||||
let id = listener_add({l -> StoreList(l)})
|
||||
call setline(1, 'one one')
|
||||
redraw
|
||||
call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], g:list)
|
||||
|
||||
" Two listeners, both get called.
|
||||
let id2 = listener_add({l -> AnotherStoreList(l)})
|
||||
let g:list = []
|
||||
let g:list2 = []
|
||||
exe "normal $asome\<Esc>"
|
||||
redraw
|
||||
call assert_equal([{'lnum': 1, 'end': 2, 'col': 8, 'added': 0}], g:list)
|
||||
call assert_equal([{'lnum': 1, 'end': 2, 'col': 8, 'added': 0}], g:list2)
|
||||
|
||||
call listener_remove(id2)
|
||||
let g:list = []
|
||||
let g:list2 = []
|
||||
call setline(3, 'three')
|
||||
redraw
|
||||
call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}], g:list)
|
||||
call assert_equal([], g:list2)
|
||||
|
||||
" the "o" command first adds an empty line and then changes it
|
||||
let g:list = []
|
||||
exe "normal Gofour\<Esc>"
|
||||
redraw
|
||||
call assert_equal([{'lnum': 4, 'end': 4, 'col': 1, 'added': 1},
|
||||
\ {'lnum': 4, 'end': 5, 'col': 1, 'added': 0}], g:list)
|
||||
|
||||
let g:list = []
|
||||
call listener_remove(id)
|
||||
call setline(1, 'asdfasdf')
|
||||
redraw
|
||||
call assert_equal([], g:list)
|
||||
|
||||
" Trying to change the list fails
|
||||
let id = listener_add({l -> EvilStoreList(l)})
|
||||
let g:list3 = []
|
||||
call setline(1, 'asdfasdf')
|
||||
redraw
|
||||
call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], g:list3)
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_listening_other_buf()
|
||||
new
|
||||
call setline(1, ['one', 'two'])
|
||||
let bufnr = bufnr('')
|
||||
normal ww
|
||||
let id = listener_add({l -> StoreList(l)}, bufnr)
|
||||
let g:list = []
|
||||
call setbufline(bufnr, 1, 'hello')
|
||||
redraw
|
||||
call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], g:list)
|
||||
|
||||
exe "buf " .. bufnr
|
||||
bwipe!
|
||||
endfunc
|
@ -767,6 +767,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1321,
|
||||
/**/
|
||||
1320,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user