# HG changeset patch # User Christian Brabandt # Date 1691787605 -7200 # Node ID 257ab4ee8e4a5ec65c16a99756c65178863e3162 # Parent 755e3243423925149d2b32d6b5291a5fcbf951dc patch 9.0.1686: undotree() only works for the current buffer Commit: https://github.com/vim/vim/commit/5fee11114975b7405b7ccd3ee8758e54bf559760 Author: Devin J. Pohly Date: Sun Apr 23 20:26:59 2023 -0500 patch 9.0.1686: undotree() only works for the current buffer Problem: undotree() only works for the current buffer Solution: Add an optional "buffer number" parameter to undotree(). If omitted, use the current buffer for backwards compatibility. closes: #4001 closes: #12292 Signed-off-by: Christian Brabandt Co-authored-by: zeertzjq Co-authored-by: Devin J. Pohly diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -707,7 +707,7 @@ trunc({expr}) Float truncate Float {ex type({expr}) Number type of value {expr} typename({expr}) String representation of the type of {expr} undofile({name}) String undo file name for {name} -undotree() List undo file tree +undotree([{buf}]) List undo file tree for buffer {buf} uniq({list} [, {func} [, {dict}]]) List remove adjacent duplicates from a list utf16idx({string}, {idx} [, {countcc} [, {charidx}]]) @@ -10073,9 +10073,10 @@ undofile({name}) *undofile()* Can also be used as a |method|: > GetFilename()->undofile() -undotree() *undotree()* - Return the current state of the undo tree in a dictionary with - the following items: +undotree([{buf}]) *undotree()* + Return the current state of the undo tree for the current + buffer, or for a specific buffer if {buf} is given. The + result is a dictionary with the following items: "seq_last" The highest undo sequence number used. "seq_cur" The sequence number of the current position in the undo tree. This differs from "seq_last" diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -5535,7 +5535,6 @@ 7 Add undo for a range of lines. Can - Undo history wrong when ":next file" re-uses a buffer. (#5426) ex_next() should pass flag to do_argfile(), then to do_ecmd(). Is there a test for this? -- Add buffer argument to undotree(). (#4001) - Undo problem: "g-" doesn't go back, gets stuck. (Björn Linse, 2016 Jul 18) - Undo message is not always properly displayed. Patch by Ken Takata, 2013 oct 3. Doesn't work properly according to Yukihiro Nakadaira. diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1373,7 +1373,7 @@ Various: *various-functions* libcallnr() idem, returning a number undofile() get the name of the undo file - undotree() return the state of the undo tree + undotree() return the state of the undo tree for a buffer shiftwidth() effective value of 'shiftwidth' diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2798,7 +2798,7 @@ static funcentry_T global_functions[] = ret_string, f_typename}, {"undofile", 1, 1, FEARG_1, arg1_string, ret_string, f_undofile}, - {"undotree", 0, 0, 0, NULL, + {"undotree", 0, 1, FEARG_1, arg1_buffer, ret_dict_any, f_undotree}, {"uniq", 1, 3, FEARG_1, arg13_sortuniq, ret_first_arg, f_uniq}, diff --git a/src/testdir/test_undo.vim b/src/testdir/test_undo.vim --- a/src/testdir/test_undo.vim +++ b/src/testdir/test_undo.vim @@ -93,6 +93,53 @@ func FillBuffer() endfor endfunc +func Test_undotree_bufnr() + new + let buf1 = bufnr() + + normal! Aabc + set ul=100 + + " Save undo tree without bufnr as ground truth for buffer 1 + let d1 = undotree() + + new + let buf2 = bufnr() + + normal! Adef + set ul=100 + + normal! Aghi + set ul=100 + + " Save undo tree without bufnr as ground truth for buffer 2 + let d2 = undotree() + + " Check undotree() with bufnr argument + let d = undotree(buf1) + call assert_equal(d1, d) + call assert_notequal(d2, d) + + let d = undotree(buf2) + call assert_notequal(d1, d) + call assert_equal(d2, d) + + " Switch buffers and check again + wincmd p + + let d = undotree(buf1) + call assert_equal(d1, d) + + let d = undotree(buf2) + call assert_notequal(d1, d) + call assert_equal(d2, d) + + " Drop created windows + set ul& + new + only! +endfunc + func Test_global_local_undolevels() new one set undolevels=5 diff --git a/src/undo.c b/src/undo.c --- a/src/undo.c +++ b/src/undo.c @@ -3629,7 +3629,7 @@ curbufIsChanged(void) * Recursive. */ static void -u_eval_tree(u_header_T *first_uhp, list_T *list) +u_eval_tree(buf_T *buf, u_header_T *first_uhp, list_T *list) { u_header_T *uhp = first_uhp; dict_T *dict; @@ -3641,9 +3641,9 @@ u_eval_tree(u_header_T *first_uhp, list_ return; dict_add_number(dict, "seq", uhp->uh_seq); dict_add_number(dict, "time", (long)uhp->uh_time); - if (uhp == curbuf->b_u_newhead) + if (uhp == buf->b_u_newhead) dict_add_number(dict, "newhead", 1); - if (uhp == curbuf->b_u_curhead) + if (uhp == buf->b_u_curhead) dict_add_number(dict, "curhead", 1); if (uhp->uh_save_nr > 0) dict_add_number(dict, "save", uhp->uh_save_nr); @@ -3655,7 +3655,7 @@ u_eval_tree(u_header_T *first_uhp, list_ if (alt_list != NULL) { // Recursive call to add alternate undo tree. - u_eval_tree(uhp->uh_alt_next.ptr, alt_list); + u_eval_tree(buf, uhp->uh_alt_next.ptr, alt_list); dict_add_list(dict, "alt", alt_list); } } @@ -3721,28 +3721,40 @@ u_undofile_reset_and_delete(buf_T *buf) #endif /* - * "undotree()" function + * "undotree(expr)" function */ void f_undotree(typval_T *argvars UNUSED, typval_T *rettv) { + typval_T *tv = &argvars[0]; + buf_T *buf; + dict_T *dict; + list_T *list; + + if (in_vim9script() && check_for_opt_buffer_arg(argvars, 0) == FAIL) + return; + + if (tv->v_type == VAR_UNKNOWN) + buf = curbuf; + else + buf = tv_get_buf_from_arg(tv); + if (rettv_dict_alloc(rettv) == FAIL) return; - dict_T *dict = rettv->vval.v_dict; - list_T *list; - - dict_add_number(dict, "synced", (long)curbuf->b_u_synced); - dict_add_number(dict, "seq_last", curbuf->b_u_seq_last); - dict_add_number(dict, "save_last", curbuf->b_u_save_nr_last); - dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur); - dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur); - dict_add_number(dict, "save_cur", curbuf->b_u_save_nr_cur); + dict = rettv->vval.v_dict; + + dict_add_number(dict, "synced", (long)buf->b_u_synced); + dict_add_number(dict, "seq_last", buf->b_u_seq_last); + dict_add_number(dict, "save_last", buf->b_u_save_nr_last); + dict_add_number(dict, "seq_cur", buf->b_u_seq_cur); + dict_add_number(dict, "time_cur", (long)buf->b_u_time_cur); + dict_add_number(dict, "save_cur", buf->b_u_save_nr_cur); list = list_alloc(); if (list != NULL) { - u_eval_tree(curbuf->b_u_oldhead, list); + u_eval_tree(buf, buf->b_u_oldhead, list); dict_add_list(dict, "entries", list); } } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1686, +/**/ 1685, /**/ 1684,