diff options
-rw-r--r-- | ci/common/build.sh | 2 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 4 | ||||
-rw-r--r-- | runtime/doc/options.txt | 3 | ||||
-rw-r--r-- | src/nvim/buffer.c | 14 | ||||
-rw-r--r-- | src/nvim/diff.c | 83 | ||||
-rw-r--r-- | src/nvim/eval.c | 12 | ||||
-rw-r--r-- | src/nvim/mark.c | 6 | ||||
-rw-r--r-- | src/nvim/mbyte.c | 4 | ||||
-rw-r--r-- | src/nvim/strings.c | 9 | ||||
-rw-r--r-- | src/nvim/testdir/setup.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_diffmode.vim | 31 | ||||
-rw-r--r-- | src/nvim/testdir/test_functions.vim | 97 | ||||
-rw-r--r-- | src/nvim/testdir/test_match.vim | 14 | ||||
-rw-r--r-- | src/nvim/testdir/test_undo.vim | 132 | ||||
-rw-r--r-- | third-party/CMakeLists.txt | 2 |
15 files changed, 337 insertions, 77 deletions
diff --git a/ci/common/build.sh b/ci/common/build.sh index a3cf64d47a..f4313578c9 100644 --- a/ci/common/build.sh +++ b/ci/common/build.sh @@ -35,7 +35,7 @@ build_deps() { elif test -f "${CACHE_MARKER}" ; then echo "Using third-party dependencies from Travis cache (last update: $(_stat "${CACHE_MARKER}"))." cp -r "${HOME}/.cache/nvim-deps"/. "${DEPS_BUILD_DIR}" - cp -r "${HOME}/.cache/nvim-deps-downloads" "${DEPS_DOWNLOAD_DIR}" + cp -r "${HOME}/.cache/nvim-deps-downloads"/. "${DEPS_DOWNLOAD_DIR}" fi # Even if we're using cached dependencies, run CMake and make to diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index b3ab0a4500..4c0ee6cc66 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2998,8 +2998,8 @@ count({comp}, {expr} [, {ic} [, {start}]]) *count()* When {ic} is given and it's |TRUE| then case is ignored. When {comp} is a string then the number of not overlapping - occurences of {expr} is returned. - + occurrences of {expr} is returned. Zero is returned when + {expr} is an empty string. *cscope_connection()* cscope_connection([{num} , {dbpath} [, {prepend}]]) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 81726ca46b..cdec599a74 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1960,6 +1960,9 @@ A jump table for the options with a short description can be found at |Q_op|. vertical Start diff mode with vertical splits (unless explicitly specified otherwise). + hiddenoff Do not use diff mode for a buffer when it + becomes hidden. + foldcolumn:{n} Set the 'foldcolumn' option to {n} when starting diff mode. Without this 2 is used. diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 71e04ec0fb..3fadcc75bf 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -505,14 +505,20 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) int nwindows = buf->b_nwindows; - /* decrease the link count from windows (unless not in any window) */ - if (buf->b_nwindows > 0) - --buf->b_nwindows; + // decrease the link count from windows (unless not in any window) + if (buf->b_nwindows > 0) { + buf->b_nwindows--; + } + + if (diffopt_hiddenoff() && !unload_buf && buf->b_nwindows == 0) { + diff_buf_delete(buf); // Clear 'diff' for hidden buffer. + } /* Return when a window is displaying the buffer or when it's not * unloaded. */ - if (buf->b_nwindows > 0 || !unload_buf) + if (buf->b_nwindows > 0 || !unload_buf) { return; + } if (buf->terminal) { terminal_close(buf->terminal, NULL); diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 8699c16351..878971a35c 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -44,6 +44,7 @@ static int diff_busy = FALSE; // ex_diffgetput() is busy #define DIFF_IWHITE 4 // ignore change in white space #define DIFF_HORIZONTAL 8 // horizontal splits #define DIFF_VERTICAL 16 // vertical splits +#define DIFF_HIDDEN_OFF 32 // diffoff when hidden static int diff_flags = DIFF_FILLER; #define LBUFLEN 50 // length of line in diff file @@ -1597,6 +1598,34 @@ static bool diff_equal_entry(diff_T *dp, int idx1, int idx2) return true; } +// Compare the characters at "p1" and "p2". If they are equal (possibly +// ignoring case) return true and set "len" to the number of bytes. +static bool diff_equal_char(const char_u *const p1, const char_u *const p2, + int *const len) +{ + const int l = utfc_ptr2len(p1); + + if (l != utfc_ptr2len(p2)) { + return false; + } + if (l > 1) { + if (STRNCMP(p1, p2, l) != 0 + && (!(diff_flags & DIFF_ICASE) + || utf_fold(utf_ptr2char(p1)) != utf_fold(utf_ptr2char(p2)))) { + return false; + } + *len = l; + } else { + if ((*p1 != *p2) + && (!(diff_flags & DIFF_ICASE) + || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2))) { + return false; + } + *len = 1; + } + return true; +} + /// Compare strings "s1" and "s2" according to 'diffopt'. /// Return non-zero when they are different. /// @@ -1623,30 +1652,12 @@ static int diff_cmp(char_u *s1, char_u *s2) p1 = skipwhite(p1); p2 = skipwhite(p2); } else { - int l = (*mb_ptr2len)(p1); - if (l != (*mb_ptr2len)(p2)) { + int l; + if (!diff_equal_char(p1, p2, &l)) { break; } - - if (l > 1) { - if ((STRNCMP(p1, p2, l) != 0) - && (!enc_utf8 - || !(diff_flags & DIFF_ICASE) - || (utf_fold(utf_ptr2char(p1)) - != utf_fold(utf_ptr2char(p2))))) { - break; - } - p1 += l; - p2 += l; - } else { - if ((*p1 != *p2) - && (!(diff_flags & DIFF_ICASE) - || (TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2)))) { - break; - } - ++p1; - ++p2; - } + p1 += l; + p2 += l; } } @@ -1828,6 +1839,9 @@ int diffopt_changed(void) } else if ((STRNCMP(p, "foldcolumn:", 11) == 0) && ascii_isdigit(p[11])) { p += 11; diff_foldcolumn_new = getdigits_int(&p); + } else if (STRNCMP(p, "hiddenoff", 9) == 0) { + p += 9; + diff_flags_new |= DIFF_HIDDEN_OFF; } if ((*p != ',') && (*p != NUL)) { @@ -1870,6 +1884,12 @@ bool diffopt_horizontal(void) return (diff_flags & DIFF_HORIZONTAL) != 0; } +// Return true if 'diffopt' contains "hiddenoff". +bool diffopt_hiddenoff(void) +{ + return (diff_flags & DIFF_HIDDEN_OFF) != 0; +} + /// Find the difference within a changed line. /// /// @param wp window whose current buffer to check @@ -1887,6 +1907,7 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) int ei_org; int ei_new; bool added = true; + int l; // Make a copy of the line, the next ml_get() will invalidate it. char_u *line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE)); @@ -1933,11 +1954,11 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) si_org = (int)(skipwhite(line_org + si_org) - line_org); si_new = (int)(skipwhite(line_new + si_new) - line_new); } else { - if (line_org[si_org] != line_new[si_new]) { + if (!diff_equal_char(line_org + si_org, line_new + si_new, &l)) { break; } - ++si_org; - ++si_new; + si_org += l; + si_new += l; } } @@ -1972,11 +1993,17 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) ei_new--; } } else { - if (line_org[ei_org] != line_new[ei_new]) { + const char_u *p1 = line_org + ei_org; + const char_u *p2 = line_new + ei_new; + + p1 -= utf_head_off(line_org, p1); + p2 -= utf_head_off(line_new, p2); + + if (!diff_equal_char(p1, p2, &l)) { break; } - ei_org--; - ei_new--; + ei_org -= l; + ei_new -= l; } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9765b04922..22cb544f54 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7603,7 +7603,7 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr) const char_u *expr = (char_u *)tv_get_string_chk(&argvars[1]); const char_u *p = argvars[0].vval.v_string; - if (!error && expr != NULL && p != NULL) { + if (!error && expr != NULL && *expr != NUL && p != NULL) { if (ic) { const size_t len = STRLEN(expr); @@ -12227,7 +12227,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, long start = 0; long nth = 1; colnr_T startcol = 0; - int match = 0; + bool match = false; list_T *l = NULL; listitem_T *li = NULL; long idx = 0; @@ -12325,7 +12325,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, for (;; ) { if (l != NULL) { if (li == NULL) { - match = FALSE; + match = false; break; } xfree(tofree); @@ -12351,7 +12351,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, startcol = (colnr_T)(regmatch.startp[0] + (*mb_ptr2len)(regmatch.startp[0]) - str); if (startcol > (colnr_T)len || str + startcol <= regmatch.startp[0]) { - match = FALSE; + match = false; break; } } @@ -12424,13 +12424,13 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, vim_regfree(regmatch.regprog); } - if (type == kSomeMatchStrPos && l == NULL) { +theend: + if (type == kSomeMatchStrPos && l == NULL && rettv->vval.v_list != NULL) { // matchstrpos() without a list: drop the second item list_T *const ret_l = rettv->vval.v_list; tv_list_item_remove(ret_l, TV_LIST_ITEM_NEXT(ret_l, tv_list_first(ret_l))); } -theend: xfree(tofree); p_cpo = save_cpo; } diff --git a/src/nvim/mark.c b/src/nvim/mark.c index b9c91de2a8..3861d9ceb8 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1465,7 +1465,11 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) { if (lp->col > 0 || lp->coladd > 1) { const char_u *const p = ml_get_buf(buf, lp->lnum, false); - lp->col -= (*mb_head_off)(p, p + lp->col); + if (*p == NUL || (int)STRLEN(p) < lp->col) { + lp->col = 0; + } else { + lp->col -= (*mb_head_off)(p, p + lp->col); + } // Reset "coladd" when the cursor would be on the right half of a // double-wide character. if (lp->coladd == 1 diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 7c196831ba..15fe51cad1 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -566,7 +566,9 @@ int utf_off2cells(unsigned off, unsigned max_off) /// Convert a UTF-8 byte sequence to a wide character /// /// If the sequence is illegal or truncated by a NUL then the first byte is -/// returned. Does not include composing characters for obvious reasons. +/// returned. +/// For an overlong sequence this may return zero. +/// Does not include composing characters for obvious reasons. /// /// @param[in] p String to convert. /// diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 3b075f8b70..f24de72743 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -344,14 +344,17 @@ char *strcase_save(const char *const orig, bool upper) char *p = res; while (*p != NUL) { - int l; - int c = utf_ptr2char((const char_u *)p); + int l = utf_ptr2len((const char_u *)p); + if (c == 0) { + // overlong sequence, use only the first byte + c = *p; + l = 1; + } int uc = upper ? mb_toupper(c) : mb_tolower(c); // Reallocate string when byte count changes. This is rare, // thus it's OK to do another malloc()/free(). - l = utf_ptr2len((const char_u *)p); int newl = utf_char2len(uc); if (newl != l) { // TODO(philix): use xrealloc() in strup_save() diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim index 51bf8ce0fc..b38f50b501 100644 --- a/src/nvim/testdir/setup.vim +++ b/src/nvim/testdir/setup.vim @@ -9,6 +9,7 @@ let s:did_load = 1 " Align Nvim defaults to Vim. set sidescroll=0 set directory^=. +set undodir^=. set backspace= set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd set listchars=eol:$ diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index d95b29759e..90fd34d93e 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -279,13 +279,13 @@ func Test_diffopt_icase() set diffopt=icase,foldcolumn:0 e one - call setline(1, ['One', 'Two', 'Three', 'Four']) + call setline(1, ['One', 'Two', 'Three', 'Four', 'Fi#ve']) redraw let normattr = screenattr(1, 1) diffthis botright vert new two - call setline(1, ['one', 'TWO', 'Three ', 'Four']) + call setline(1, ['one', 'TWO', 'Three ', 'Four', 'fI=VE']) diffthis redraw @@ -294,6 +294,10 @@ func Test_diffopt_icase() call assert_notequal(normattr, screenattr(3, 1)) call assert_equal(normattr, screenattr(4, 1)) + let dtextattr = screenattr(5, 3) + call assert_notequal(dtextattr, screenattr(5, 1)) + call assert_notequal(dtextattr, screenattr(5, 5)) + diffoff! %bwipe! set diffopt& @@ -371,6 +375,29 @@ func Test_diffopt_vertical() %bwipe endfunc +func Test_diffopt_hiddenoff() + set diffopt=filler,foldcolumn:0,hiddenoff + e! one + call setline(1, ['Two', 'Three']) + redraw + let normattr = screenattr(1, 1) + diffthis + botright vert new two + call setline(1, ['One', 'Four']) + diffthis + redraw + call assert_notequal(normattr, screenattr(1, 1)) + set hidden + close + redraw + " should not diffing with hidden buffer two while 'hiddenoff' is enabled + call assert_equal(normattr, screenattr(1, 1)) + + bwipe! + bwipe! + set hidden& diffopt& +endfunc + func Test_diffoff_hidden() set diffopt=filler,foldcolumn:0 e! one diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 3b16f2ce9f..6d0a6b9d5e 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -96,6 +96,30 @@ func Test_min() " call assert_fails('call min(v:none)', 'E712:') endfunc +func Test_strwidth() + for aw in ['single', 'double'] + exe 'set ambiwidth=' . aw + call assert_equal(0, strwidth('')) + call assert_equal(1, strwidth("\t")) + call assert_equal(3, strwidth('Vim')) + call assert_equal(4, strwidth(1234)) + call assert_equal(5, strwidth(-1234)) + + if has('multi_byte') + call assert_equal(2, strwidth('😉')) + call assert_equal(17, strwidth('Eĥoŝanĝo ĉiuĵaŭde')) + call assert_equal((aw == 'single') ? 6 : 7, strwidth('Straße')) + endif + + call assert_fails('call strwidth({->0})', 'E729:') + call assert_fails('call strwidth([])', 'E730:') + call assert_fails('call strwidth({})', 'E731:') + call assert_fails('call strwidth(1.2)', 'E806:') + endfor + + set ambiwidth& +endfunc + func Test_str2nr() call assert_equal(0, str2nr('')) call assert_equal(1, str2nr('1')) @@ -215,6 +239,21 @@ func Test_setbufvar_options() bwipe! endfunc +func Test_pathshorten() + call assert_equal('', pathshorten('')) + call assert_equal('foo', pathshorten('foo')) + call assert_equal('/foo', pathshorten('/foo')) + call assert_equal('f/', pathshorten('foo/')) + call assert_equal('f/bar', pathshorten('foo/bar')) + call assert_equal('f/b/foobar', pathshorten('foo/bar/foobar')) + call assert_equal('/f/b/foobar', pathshorten('/foo/bar/foobar')) + call assert_equal('.f/bar', pathshorten('.foo/bar')) + call assert_equal('~f/bar', pathshorten('~foo/bar')) + call assert_equal('~.f/bar', pathshorten('~.foo/bar')) + call assert_equal('.~f/bar', pathshorten('.~foo/bar')) + call assert_equal('~/f/bar', pathshorten('~/foo/bar')) +endfunc + func Test_strpart() call assert_equal('de', strpart('abcdefg', 3, 2)) call assert_equal('ab', strpart('abcdefg', -2, 4)) @@ -299,6 +338,11 @@ func Test_tolower() " Ⱥ (U+023A) and Ⱦ (U+023E) are the *only* code points to increase " in length (2 to 3 bytes) when lowercased. So let's test them. call assert_equal("ⱥ ⱦ", tolower("Ⱥ Ⱦ")) + + " This call to tolower with invalid utf8 sequence used to cause access to + " invalid memory. + call tolower("\xC0\x80\xC0") + call tolower("123\xC0\x80\xC0") endfunc func Test_toupper() @@ -369,6 +413,11 @@ func Test_toupper() call assert_equal("ZŹŻŽƵẐẔ", toupper("ZŹŻŽƵẐẔ")) call assert_equal("Ⱥ Ⱦ", toupper("ⱥ ⱦ")) + + " This call to toupper with invalid utf8 sequence used to cause access to + " invalid memory. + call toupper("\xC0\x80\xC0") + call toupper("123\xC0\x80\xC0") endfunc " Tests for the mode() function @@ -573,10 +622,46 @@ func Test_strridx() call assert_equal(-1, strridx('hello', 'hello world')) endfunc +func Test_match_func() + call assert_equal(4, match('testing', 'ing')) + call assert_equal(4, match('testing', 'ing', 2)) + call assert_equal(-1, match('testing', 'ing', 5)) + call assert_equal(-1, match('testing', 'ing', 8)) + call assert_equal(1, match(['vim', 'testing', 'execute'], 'ing')) + call assert_equal(-1, match(['vim', 'testing', 'execute'], 'img')) +endfunc + func Test_matchend() call assert_equal(7, matchend('testing', 'ing')) call assert_equal(7, matchend('testing', 'ing', 2)) call assert_equal(-1, matchend('testing', 'ing', 5)) + call assert_equal(-1, matchend('testing', 'ing', 8)) + call assert_equal(match(['vim', 'testing', 'execute'], 'ing'), matchend(['vim', 'testing', 'execute'], 'ing')) + call assert_equal(match(['vim', 'testing', 'execute'], 'img'), matchend(['vim', 'testing', 'execute'], 'img')) +endfunc + +func Test_matchlist() + call assert_equal(['acd', 'a', '', 'c', 'd', '', '', '', '', ''], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)')) + call assert_equal(['d', '', '', '', 'd', '', '', '', '', ''], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 2)) + call assert_equal([], matchlist('acd', '\(a\)\?\(b\)\?\(c\)\?\(.*\)', 4)) +endfunc + +func Test_matchstr() + call assert_equal('ing', matchstr('testing', 'ing')) + call assert_equal('ing', matchstr('testing', 'ing', 2)) + call assert_equal('', matchstr('testing', 'ing', 5)) + call assert_equal('', matchstr('testing', 'ing', 8)) + call assert_equal('testing', matchstr(['vim', 'testing', 'execute'], 'ing')) + call assert_equal('', matchstr(['vim', 'testing', 'execute'], 'img')) +endfunc + +func Test_matchstrpos() + call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing')) + call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing', 2)) + call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 5)) + call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 8)) + call assert_equal(['ing', 1, 4, 7], matchstrpos(['vim', 'testing', 'execute'], 'ing')) + call assert_equal(['', -1, -1, -1], matchstrpos(['vim', 'testing', 'execute'], 'img')) endfunc func Test_nextnonblank_prevnonblank() @@ -687,6 +772,7 @@ func Test_count() call assert_equal(0, count("foo", "O")) call assert_equal(2, count("foo", "O", 1)) call assert_equal(2, count("fooooo", "oo")) + call assert_equal(0, count("foo", "")) endfunc func Test_changenr() @@ -770,6 +856,17 @@ func Test_col() bw! endfunc +func Test_inputlist() + call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>1\<cr>", 'tx') + call assert_equal(1, c) + call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>2\<cr>", 'tx') + call assert_equal(2, c) + call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>3\<cr>", 'tx') + call assert_equal(3, c) + + call assert_fails('call inputlist("")', 'E686:') +endfunc + func Test_balloon_show() if has('balloon_eval') " This won't do anything but must not crash either. diff --git a/src/nvim/testdir/test_match.vim b/src/nvim/testdir/test_match.vim index 066bb2f6a1..e608a2e58b 100644 --- a/src/nvim/testdir/test_match.vim +++ b/src/nvim/testdir/test_match.vim @@ -1,5 +1,5 @@ " Test for :match, :2match, :3match, clearmatches(), getmatches(), matchadd(), -" matchaddpos(), matcharg(), matchdelete(), matchstrpos() and setmatches(). +" matchaddpos(), matcharg(), matchdelete(), and setmatches(). function Test_match() highlight MyGroup1 term=bold ctermbg=red guibg=red @@ -150,18 +150,6 @@ function Test_match() highlight MyGroup3 NONE endfunc -func Test_matchstrpos() - call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing')) - - call assert_equal(['ing', 4, 7], matchstrpos('testing', 'ing', 2)) - - call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 5)) - - call assert_equal(['ing', 1, 4, 7], matchstrpos(['vim', 'testing', 'execute'], 'ing')) - - call assert_equal(['', -1, -1, -1], matchstrpos(['vim', 'testing', 'execute'], 'img')) -endfunc - func Test_matchaddpos() syntax on set hlsearch diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim index 2bc6073d52..f31499607b 100644 --- a/src/nvim/testdir/test_undo.vim +++ b/src/nvim/testdir/test_undo.vim @@ -4,28 +4,88 @@ " Also tests :earlier and :later. func Test_undotree() - exe "normal Aabc\<Esc>" + new + + normal! Aabc + set ul=100 + let d = undotree() + call assert_equal(1, d.seq_last) + call assert_equal(1, d.seq_cur) + call assert_equal(0, d.save_last) + call assert_equal(0, d.save_cur) + call assert_equal(1, len(d.entries)) + call assert_equal(1, d.entries[0].newhead) + call assert_equal(1, d.entries[0].seq) + call assert_true(d.entries[0].time <= d.time_cur) + + normal! Adef + set ul=100 + let d = undotree() + call assert_equal(2, d.seq_last) + call assert_equal(2, d.seq_cur) + call assert_equal(0, d.save_last) + call assert_equal(0, d.save_cur) + call assert_equal(2, len(d.entries)) + call assert_equal(1, d.entries[0].seq) + call assert_equal(1, d.entries[1].newhead) + call assert_equal(2, d.entries[1].seq) + call assert_true(d.entries[1].time <= d.time_cur) + + undo set ul=100 - exe "normal Adef\<Esc>" + let d = undotree() + call assert_equal(2, d.seq_last) + call assert_equal(1, d.seq_cur) + call assert_equal(0, d.save_last) + call assert_equal(0, d.save_cur) + call assert_equal(2, len(d.entries)) + call assert_equal(1, d.entries[0].seq) + call assert_equal(1, d.entries[1].curhead) + call assert_equal(1, d.entries[1].newhead) + call assert_equal(2, d.entries[1].seq) + call assert_true(d.entries[1].time == d.time_cur) + + normal! Aghi set ul=100 + let d = undotree() + call assert_equal(3, d.seq_last) + call assert_equal(3, d.seq_cur) + call assert_equal(0, d.save_last) + call assert_equal(0, d.save_cur) + call assert_equal(2, len(d.entries)) + call assert_equal(1, d.entries[0].seq) + call assert_equal(2, d.entries[1].alt[0].seq) + call assert_equal(1, d.entries[1].newhead) + call assert_equal(3, d.entries[1].seq) + call assert_true(d.entries[1].time <= d.time_cur) + undo + set ul=100 let d = undotree() - call assert_true(d.seq_last > 0) - call assert_true(d.seq_cur > 0) - call assert_true(d.seq_cur < d.seq_last) - call assert_true(len(d.entries) > 0) - " TODO: check more members of d + call assert_equal(3, d.seq_last) + call assert_equal(1, d.seq_cur) + call assert_equal(0, d.save_last) + call assert_equal(0, d.save_cur) + call assert_equal(2, len(d.entries)) + call assert_equal(1, d.entries[0].seq) + call assert_equal(2, d.entries[1].alt[0].seq) + call assert_equal(1, d.entries[1].curhead) + call assert_equal(1, d.entries[1].newhead) + call assert_equal(3, d.entries[1].seq) + call assert_true(d.entries[1].time == d.time_cur) w! Xtest - call assert_equal(d.save_last + 1, undotree().save_last) + let d = undotree() + call assert_equal(1, d.save_cur) + call assert_equal(1, d.save_last) call delete('Xtest') - bwipe Xtest + bwipe! Xtest endfunc func FillBuffer() for i in range(1,13) put=i - " Set 'undolevels' to split undo. + " Set 'undolevels' to split undo. exe "setg ul=" . &g:ul endfor endfunc @@ -135,19 +195,19 @@ func Test_undolist() new set ul=100 - let a=execute('undolist') + let a = execute('undolist') call assert_equal("\nNothing to undo", a) " 1 leaf (2 changes). call feedkeys('achange1', 'xt') call feedkeys('achange2', 'xt') - let a=execute('undolist') + let a = execute('undolist') call assert_match("^\nnumber changes when *saved\n *2 *2 .*$", a) " 2 leaves. call feedkeys('u', 'xt') call feedkeys('achange3\<Esc>', 'xt') - let a=execute('undolist') + let a = execute('undolist') call assert_match("^\nnumber changes when *saved\n *2 *2 *.*\n *3 *2 .*$", a) close! endfunc @@ -270,7 +330,7 @@ endfunc " Also test this in an empty buffer. func Test_cmd_in_reg_undo() enew! - let @a="Ox\<Esc>jAy\<Esc>kdd" + let @a = "Ox\<Esc>jAy\<Esc>kdd" edit +/^$ test_undo.vim normal @au call assert_equal(0, &modified) @@ -279,7 +339,7 @@ func Test_cmd_in_reg_undo() normal @au call assert_equal(0, &modified) only! - let @a='' + let @a = '' endfunc func Test_redo_empty_line() @@ -288,3 +348,45 @@ func Test_redo_empty_line() exe "norm." bwipe! endfunc + +" This used to cause an illegal memory access +func Test_undo_append() + new + call feedkeys("axx\<Esc>v", 'xt') + undo + norm o + quit +endfunc + +funct Test_undofile() + " Test undofile() without setting 'undodir'. + if has('persistent_undo') + call assert_equal(fnamemodify('.Xundofoo.un~', ':p'), undofile('Xundofoo')) + else + call assert_equal('', undofile('Xundofoo')) + endif + call assert_equal('', undofile('')) + + " Test undofile() with 'undodir' set to to an existing directory. + call mkdir('Xundodir') + set undodir=Xundodir + let cwd = getcwd() + if has('win32') + " Replace windows drive such as C:... into C%... + let cwd = substitute(cwd, '^\([A-Z]\):', '\1%', 'g') + endif + let pathsep = has('win32') ? '\' : '/' + let cwd = substitute(cwd . pathsep . 'Xundofoo', pathsep, '%', 'g') + if has('persistent_undo') + call assert_equal('Xundodir' . pathsep . cwd, undofile('Xundofoo')) + else + call assert_equal('', undofile('Xundofoo')) + endif + call assert_equal('', undofile('')) + call delete('Xundodir', 'd') + + " Test undofile() with 'undodir' set to a non-existing directory. + " call assert_equal('', undofile('Xundofoo')) + + set undodir& +endfunc diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index cf49a67f60..83d7b69b45 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -147,7 +147,7 @@ set(JEMALLOC_SHA256 9409d85664b4f135b77518b0b118c549009dc10f6cba14557d170476611f set(LUV_URL https://github.com/luvit/luv/archive/1.9.1-1.tar.gz) set(LUV_SHA256 562b9efaad30aa051a40eac9ade0c3df48bb8186763769abe47ec3fb3edb1268) -set(GPERF_URL https://ftp.gnu.org/pub/gnu/gperf/gperf-3.1.tar.gz) +set(GPERF_URL https://github.com/neovim/deps/raw/ff5b4b18a87397a8564016071ae64f64bcd8c635/opt/gperf-3.1.tar.gz) set(GPERF_SHA256 588546b945bba4b70b6a3a616e80b4ab466e3f33024a352fc2198112cdbb3ae2) # 7za.exe cat.exe curl.exe ca-bundle.crt diff.exe tee.exe tidy.exe xxd.exe |