summaryrefslogtreecommitdiff
path: root/data/vim/patches/8.1.1332
diff options
context:
space:
mode:
Diffstat (limited to 'data/vim/patches/8.1.1332')
-rw-r--r--data/vim/patches/8.1.1332622
1 files changed, 622 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.1332 b/data/vim/patches/8.1.1332
new file mode 100644
index 000000000..7771e86c3
--- /dev/null
+++ b/data/vim/patches/8.1.1332
@@ -0,0 +1,622 @@
+To: vim_dev@googlegroups.com
+Subject: Patch 8.1.1332
+Fcc: outbox
+From: Bram Moolenaar <Bram@moolenaar.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+------------
+
+Patch 8.1.1332
+Problem: Cannot flush change listeners without also redrawing. The line
+ numbers in the list of changes may become invalid.
+Solution: Add listener_flush(). Invoke listeners before adding a change
+ that makes line numbers invalid.
+Files: src/evalfunc.c, src/change.c, src/proto/change.pro,
+ src/screen.c, runtime/doc/eval.txt, src/testdir/test_listener.vim
+
+
+*** ../vim-8.1.1331/src/evalfunc.c 2019-05-12 13:07:10.563191431 +0200
+--- src/evalfunc.c 2019-05-14 18:48:29.245329088 +0200
+***************
+*** 768,773 ****
+--- 768,774 ----
+ {"lispindent", 1, 1, f_lispindent},
+ {"list2str", 1, 2, f_list2str},
+ {"listener_add", 1, 2, f_listener_add},
++ {"listener_flush", 0, 1, f_listener_flush},
+ {"listener_remove", 1, 1, f_listener_remove},
+ {"localtime", 0, 0, f_localtime},
+ #ifdef FEAT_FLOAT
+*** ../vim-8.1.1331/src/change.c 2019-05-11 21:14:02.332269584 +0200
+--- src/change.c 2019-05-14 20:20:30.221554995 +0200
+***************
+*** 169,174 ****
+--- 169,214 ----
+
+ if (curbuf->b_listener == NULL)
+ return;
++
++ // If the new change is going to change the line numbers in already listed
++ // changes, then flush.
++ if (recorded_changes != NULL && xtra != 0)
++ {
++ listitem_T *li;
++ linenr_T nr;
++
++ for (li = recorded_changes->lv_first; li != NULL; li = li->li_next)
++ {
++ nr = (linenr_T)dict_get_number(
++ li->li_tv.vval.v_dict, (char_u *)"lnum");
++ if (nr >= lnum || nr > lnume)
++ {
++ if (li->li_next == NULL && lnum == nr
++ && col + 1 == (colnr_T)dict_get_number(
++ li->li_tv.vval.v_dict, (char_u *)"col"))
++ {
++ dictitem_T *di;
++
++ // Same start point and nothing is following, entries can
++ // be merged.
++ di = dict_find(li->li_tv.vval.v_dict, (char_u *)"end", -1);
++ nr = tv_get_number(&di->di_tv);
++ if (lnume > nr)
++ di->di_tv.vval.v_number = lnume;
++ di = dict_find(li->li_tv.vval.v_dict,
++ (char_u *)"added", -1);
++ di->di_tv.vval.v_number += xtra;
++ return;
++ }
++
++ // the current change is going to make the line number in the
++ // older change invalid, flush now
++ invoke_listeners(curbuf);
++ break;
++ }
++ }
++ }
++
+ if (recorded_changes == NULL)
+ {
+ recorded_changes = list_alloc();
+***************
+*** 231,236 ****
+--- 271,293 ----
+ }
+
+ /*
++ * listener_flush() function
++ */
++ void
++ f_listener_flush(typval_T *argvars, typval_T *rettv UNUSED)
++ {
++ buf_T *buf = curbuf;
++
++ if (argvars[0].v_type != VAR_UNKNOWN)
++ {
++ buf = get_buf_arg(&argvars[0]);
++ if (buf == NULL)
++ return;
++ }
++ invoke_listeners(buf);
++ }
++
++ /*
+ * listener_remove() function
+ */
+ void
+***************
+*** 264,288 ****
+ * listener_add().
+ */
+ void
+! invoke_listeners(void)
+ {
+ listener_T *lnr;
+ typval_T rettv;
+ int dummy;
+! typval_T argv[2];
+
+! if (recorded_changes == NULL) // nothing changed
+ return;
+- argv[0].v_type = VAR_LIST;
+- argv[0].vval.v_list = recorded_changes;
+
+! for (lnr = curbuf->b_listener; lnr != NULL; lnr = lnr->lr_next)
+ {
+ call_func(lnr->lr_callback, -1, &rettv,
+! 1, argv, NULL, 0L, 0L, &dummy, TRUE, lnr->lr_partial, NULL);
+ clear_tv(&rettv);
+ }
+
+ list_unref(recorded_changes);
+ recorded_changes = NULL;
+ }
+--- 321,376 ----
+ * listener_add().
+ */
+ void
+! invoke_listeners(buf_T *buf)
+ {
+ listener_T *lnr;
+ typval_T rettv;
+ int dummy;
+! typval_T argv[6];
+! listitem_T *li;
+! linenr_T start = MAXLNUM;
+! linenr_T end = 0;
+! linenr_T added = 0;
+
+! if (recorded_changes == NULL // nothing changed
+! || buf->b_listener == NULL) // no listeners
+ return;
+
+! argv[0].v_type = VAR_NUMBER;
+! argv[0].vval.v_number = buf->b_fnum; // a:bufnr
+!
+!
+! for (li = recorded_changes->lv_first; li != NULL; li = li->li_next)
+! {
+! varnumber_T lnum;
+!
+! lnum = dict_get_number(li->li_tv.vval.v_dict, (char_u *)"lnum");
+! if (start > lnum)
+! start = lnum;
+! lnum = dict_get_number(li->li_tv.vval.v_dict, (char_u *)"end");
+! if (lnum > end)
+! end = lnum;
+! added = dict_get_number(li->li_tv.vval.v_dict, (char_u *)"added");
+! }
+! argv[1].v_type = VAR_NUMBER;
+! argv[1].vval.v_number = start;
+! argv[2].v_type = VAR_NUMBER;
+! argv[2].vval.v_number = end;
+! argv[3].v_type = VAR_NUMBER;
+! argv[3].vval.v_number = added;
+!
+! argv[4].v_type = VAR_LIST;
+! argv[4].vval.v_list = recorded_changes;
+! ++textlock;
+!
+! for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
+ {
+ call_func(lnr->lr_callback, -1, &rettv,
+! 5, argv, NULL, 0L, 0L, &dummy, TRUE, lnr->lr_partial, NULL);
+ clear_tv(&rettv);
+ }
+
++ --textlock;
+ list_unref(recorded_changes);
+ recorded_changes = NULL;
+ }
+*** ../vim-8.1.1331/src/proto/change.pro 2019-05-11 19:14:11.589313987 +0200
+--- src/proto/change.pro 2019-05-14 19:02:12.920839840 +0200
+***************
+*** 3,10 ****
+ void changed(void);
+ void changed_internal(void);
+ void f_listener_add(typval_T *argvars, typval_T *rettv);
+ void f_listener_remove(typval_T *argvars, typval_T *rettv);
+! void invoke_listeners(void);
+ void changed_bytes(linenr_T lnum, colnr_T col);
+ void inserted_bytes(linenr_T lnum, colnr_T col, int added);
+ void appended_lines(linenr_T lnum, long count);
+--- 3,11 ----
+ void changed(void);
+ void changed_internal(void);
+ void f_listener_add(typval_T *argvars, typval_T *rettv);
++ void f_listener_flush(typval_T *argvars, typval_T *rettv);
+ void f_listener_remove(typval_T *argvars, typval_T *rettv);
+! void invoke_listeners(buf_T *buf);
+ void changed_bytes(linenr_T lnum, colnr_T col);
+ void inserted_bytes(linenr_T lnum, colnr_T col, int added);
+ void appended_lines(linenr_T lnum, long count);
+*** ../vim-8.1.1331/src/screen.c 2019-05-11 21:14:02.336269566 +0200
+--- src/screen.c 2019-05-14 18:52:55.103887107 +0200
+***************
+*** 565,572 ****
+ }
+
+ #ifdef FEAT_EVAL
+! // Before updating the screen, notify any listeners of changed text.
+! invoke_listeners();
+ #endif
+
+ if (must_redraw)
+--- 565,577 ----
+ }
+
+ #ifdef FEAT_EVAL
+! {
+! buf_T *buf;
+!
+! // Before updating the screen, notify any listeners of changed text.
+! FOR_ALL_BUFFERS(buf)
+! invoke_listeners(buf);
+! }
+ #endif
+
+ if (must_redraw)
+*** ../vim-8.1.1331/runtime/doc/eval.txt 2019-05-12 13:53:46.906851000 +0200
+--- runtime/doc/eval.txt 2019-05-14 21:17:56.054323991 +0200
+***************
+*** 2459,2464 ****
+--- 2459,2465 ----
+ list2str({list} [, {utf8}]) String turn numbers in {list} into a String
+ listener_add({callback} [, {buf}])
+ Number add a callback to listen to changes
++ listener_flush([{buf}]) none invoke listener callbacks
+ listener_remove({id}) none remove a listener callback
+ localtime() Number current time
+ log({expr}) Float natural logarithm (base e) of {expr}
+***************
+*** 6322,6329 ****
+ 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. The list cannot be changed. Each list item is a
+ dictionary with these entries:
+ lnum the first line number of the change
+ end the first line below the change
+--- 6323,6343 ----
+ buffer is used.
+ Returns a unique ID that can be passed to |listener_remove()|.
+
+! The {callback} is invoked with four arguments:
+! a:bufnr the buffer that was changed
+! a:start first changed line number
+! a:end first line number below the change
+! a:added total number of lines added, negative if lines
+! were deleted
+! a:changes a List of items with details about the changes
+!
+! Example: >
+! func Listener(bufnr, start, end, added, changes)
+! echo 'lines ' .. a:start .. ' until ' .. a:end .. ' changed'
+! endfunc
+! call listener_add('Listener', bufnr)
+!
+! < The List cannot be changed. Each item in a:changes is a
+ dictionary with these entries:
+ lnum the first line number of the change
+ end the first line below the change
+***************
+*** 6337,6371 ****
+ 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 entries are in the order the changes was made, thus the
+! most recent change is at the end. One has to go through the
+! list from end to start to compute the line numbers in the
+! current state of the text.
+!
+! When using the same function for multiple buffers, you can
+! pass the buffer to that function using a |Partial|.
+! Example: >
+! func Listener(bufnr, changes)
+! " ...
+! endfunc
+! let bufnr = ...
+! call listener_add(function('Listener', [bufnr]), bufnr)
+!
+! < 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
+--- 6351,6382 ----
+ lnum line below which the new line is added
+ end equal to "lnum"
+ added number of lines inserted
+! col 1
+ 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 1
+ When lines are changed:
+ lnum the first changed line
+ end the line below the last changed line
+! added 0
+! col first column with a change or 1
+
+! The entries are in the order the changes were made, thus the
+! most recent change is at the end. The line numbers are valid
+! when the callback is invoked, but later changes may make them
+! invalid, thus keeping a copy for later might not work.
+!
+! The {callback} is invoked just before the screen is updated,
+! when |listener_flush()| is called or when a change is being
+! made that changes the line count in a way it causes a line
+! number in the list of changes to become invalid.
+!
+! The {callback} is invoked with the text locked, see
+! |textlock|. If you do need to make changes to the buffer, use
+! a timer to do this later |timer_start()|.
+
+ The {callback} is not invoked when the buffer is first loaded.
+ Use the |BufReadPost| autocmd event to handle the initial text
+***************
+*** 6373,6378 ****
+--- 6384,6397 ----
+ The {callback} is also not invoked when the buffer is
+ unloaded, use the |BufUnload| autocmd event for that.
+
++ listener_flush([{buf}]) *listener_flush()*
++ Invoke listener callbacks for buffer {buf}. If there are no
++ pending changes then no callbacks are invoked.
++
++ {buf} refers to a buffer name or number. For the accepted
++ values, see |bufname()|. When {buf} is omitted the current
++ buffer is used.
++
+ listener_remove({id}) *listener_remove()*
+ Remove a listener previously added with listener_add().
+
+*** ../vim-8.1.1331/src/testdir/test_listener.vim 2019-05-12 14:36:22.938437845 +0200
+--- src/testdir/test_listener.vim 2019-05-14 20:56:05.034204412 +0200
+***************
+*** 16,24 ****
+ func Test_listening()
+ new
+ call setline(1, ['one', 'two'])
+! let id = listener_add({l -> s:StoreList(l)})
+ call setline(1, 'one one')
+! redraw
+ call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list)
+
+ " Undo is also a change
+--- 16,25 ----
+ func Test_listening()
+ new
+ call setline(1, ['one', 'two'])
+! let s:list = []
+! let id = listener_add({b, s, e, a, l -> s:StoreList(l)})
+ call setline(1, 'one one')
+! call listener_flush()
+ call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list)
+
+ " Undo is also a change
+***************
+*** 26,37 ****
+ call append(2, 'two two')
+ undo
+ redraw
+! call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1},
+! \ {'lnum': 3, 'end': 4, 'col': 1, 'added': -1}, ], s:list)
+ 1
+
+! " Two listeners, both get called.
+! let id2 = listener_add({l -> s:AnotherStoreList(l)})
+ let s:list = []
+ let s:list2 = []
+ exe "normal $asome\<Esc>"
+--- 27,40 ----
+ call append(2, 'two two')
+ undo
+ redraw
+! " the two changes get merged
+! call assert_equal([{'lnum': 3, 'end': 4, 'col': 1, 'added': 0}], s:list)
+ 1
+
+! " Two listeners, both get called. Also check column.
+! call setline(1, ['one one', 'two'])
+! call listener_flush()
+! let id2 = listener_add({b, s, e, a, l -> s:AnotherStoreList(l)})
+ let s:list = []
+ let s:list2 = []
+ exe "normal $asome\<Esc>"
+***************
+*** 39,45 ****
+--- 42,51 ----
+ call assert_equal([{'lnum': 1, 'end': 2, 'col': 8, 'added': 0}], s:list)
+ call assert_equal([{'lnum': 1, 'end': 2, 'col': 8, 'added': 0}], s:list2)
+
++ " removing listener works
+ call listener_remove(id2)
++ call setline(1, ['one one', 'two'])
++ call listener_flush()
+ let s:list = []
+ let s:list2 = []
+ call setline(3, 'three')
+***************
+*** 47,58 ****
+ call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}], s:list)
+ call assert_equal([], s:list2)
+
+ " the "o" command first adds an empty line and then changes it
+ let s: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}], s:list)
+
+ " Remove last listener
+ let s:list = []
+--- 53,94 ----
+ call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}], s:list)
+ call assert_equal([], s:list2)
+
++ " a change above a previous change without a line number change is reported
++ " together
++ call setline(1, ['one one', 'two'])
++ call listener_flush()
++ call append(2, 'two two')
++ call setline(1, 'something')
++ call listener_flush()
++ call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1},
++ \ {'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list)
++
++ " an insert just above a previous change that was the last one gets merged
++ call setline(1, ['one one', 'two'])
++ call listener_flush()
++ call setline(2, 'something')
++ call append(1, 'two two')
++ call listener_flush()
++ call assert_equal([{'lnum': 2, 'end': 3, 'col': 1, 'added': 1}], s:list)
++
++ " an insert above a previous change causes a flush
++ call setline(1, ['one one', 'two'])
++ call listener_flush()
++ call setline(2, 'something')
++ call append(0, 'two two')
++ call assert_equal([{'lnum': 2, 'end': 3, 'col': 1, 'added': 0}], s:list)
++ call listener_flush()
++ call assert_equal([{'lnum': 1, 'end': 1, 'col': 1, 'added': 1}], s:list)
++
+ " the "o" command first adds an empty line and then changes it
++ %del
++ call setline(1, ['one one', 'two'])
++ call listener_flush()
+ let s:list = []
+ exe "normal Gofour\<Esc>"
+ redraw
+! call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1},
+! \ {'lnum': 3, 'end': 4, 'col': 1, 'added': 0}], s:list)
+
+ " Remove last listener
+ let s:list = []
+***************
+*** 62,68 ****
+ call assert_equal([], s:list)
+
+ " Trying to change the list fails
+! let id = listener_add({l -> s:EvilStoreList(l)})
+ let s:list3 = []
+ call setline(1, 'asdfasdf')
+ redraw
+--- 98,104 ----
+ call assert_equal([], s:list)
+
+ " Trying to change the list fails
+! let id = listener_add({b, s, e, a, l -> s:EvilStoreList(l)})
+ let s:list3 = []
+ call setline(1, 'asdfasdf')
+ redraw
+***************
+*** 72,80 ****
+ bwipe!
+ endfunc
+
+! func s:StoreBufList(buf, l)
+ let s:bufnr = a:buf
+! let s:list = a:l
+ endfunc
+
+ func Test_listening_other_buf()
+--- 108,171 ----
+ bwipe!
+ endfunc
+
+! func s:StoreListArgs(buf, start, end, added, list)
+! let s:buf = a:buf
+! let s:start = a:start
+! let s:end = a:end
+! let s:added = a:added
+! let s:list = a:list
+! endfunc
+!
+! func Test_listener_args()
+! new
+! call setline(1, ['one', 'two'])
+! let s:list = []
+! let id = listener_add('s:StoreListArgs')
+!
+! " just one change
+! call setline(1, 'one one')
+! call listener_flush()
+! call assert_equal(bufnr(''), s:buf)
+! call assert_equal(1, s:start)
+! call assert_equal(2, s:end)
+! call assert_equal(0, s:added)
+! call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list)
+!
+! " two disconnected changes
+! call setline(1, ['one', 'two', 'three', 'four'])
+! call listener_flush()
+! call setline(1, 'one one')
+! call setline(3, 'three three')
+! call listener_flush()
+! call assert_equal(bufnr(''), s:buf)
+! call assert_equal(1, s:start)
+! call assert_equal(4, s:end)
+! call assert_equal(0, s:added)
+! call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0},
+! \ {'lnum': 3, 'end': 4, 'col': 1, 'added': 0}], s:list)
+!
+! " add and remove lines
+! call setline(1, ['one', 'two', 'three', 'four', 'five', 'six'])
+! call listener_flush()
+! call append(2, 'two two')
+! 4del
+! call append(5, 'five five')
+! call listener_flush()
+! call assert_equal(bufnr(''), s:buf)
+! call assert_equal(3, s:start)
+! call assert_equal(6, s:end)
+! call assert_equal(1, s:added)
+! call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1},
+! \ {'lnum': 4, 'end': 5, 'col': 1, 'added': -1},
+! \ {'lnum': 6, 'end': 6, 'col': 1, 'added': 1}], s:list)
+!
+! call listener_remove(id)
+! bwipe!
+! endfunc
+!
+! func s:StoreBufList(buf, start, end, added, list)
+ let s:bufnr = a:buf
+! let s:list = a:list
+ endfunc
+
+ func Test_listening_other_buf()
+***************
+*** 82,88 ****
+ call setline(1, ['one', 'two'])
+ let bufnr = bufnr('')
+ normal ww
+! let id = listener_add(function('s:StoreBufList', [bufnr]), bufnr)
+ let s:list = []
+ call setbufline(bufnr, 1, 'hello')
+ redraw
+--- 173,179 ----
+ call setline(1, ['one', 'two'])
+ let bufnr = bufnr('')
+ normal ww
+! let id = listener_add(function('s:StoreBufList'), bufnr)
+ let s:list = []
+ call setbufline(bufnr, 1, 'hello')
+ redraw
+*** ../vim-8.1.1331/src/version.c 2019-05-14 17:57:14.861402461 +0200
+--- src/version.c 2019-05-14 21:18:19.926188697 +0200
+***************
+*** 769,770 ****
+--- 769,772 ----
+ { /* Add new patch number below this line */
++ /**/
++ 1332,
+ /**/
+
+--
+Hanson's Treatment of Time:
+ There are never enough hours in a day, but always too
+ many days before Saturday.
+
+ /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
+/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
+\\\ an exciting new programming language -- http://www.Zimbu.org ///
+ \\\ help me help AIDS victims -- http://ICCF-Holland.org ///