aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/ex_cmds.c3
-rw-r--r--src/nvim/lua/spell.c99
-rw-r--r--src/nvim/lua/spell.h12
-rw-r--r--src/nvim/lua/stdlib.c5
-rw-r--r--src/nvim/option.c13
-rw-r--r--src/nvim/popupmnu.c43
-rw-r--r--src/nvim/regexp_nfa.c6
-rw-r--r--src/nvim/screen.c9
-rw-r--r--src/nvim/testdir/setup.vim2
-rw-r--r--src/nvim/testdir/test_autocmd.vim90
-rw-r--r--src/nvim/testdir/test_blob.vim8
-rw-r--r--src/nvim/testdir/test_display.vim25
-rw-r--r--src/nvim/testdir/test_filechanged.vim149
-rw-r--r--src/nvim/testdir/test_filetype.vim3
-rw-r--r--src/nvim/testdir/test_listchars.vim16
-rw-r--r--src/nvim/testdir/test_messages.vim8
-rw-r--r--src/nvim/testdir/test_visual.vim2
18 files changed, 367 insertions, 130 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 2135d0bcd2..5b63ff5648 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1685,7 +1685,7 @@ static void init_prompt(int cmdchar_todo)
// Insert always starts after the prompt, allow editing text after it.
if (Insstart_orig.lnum != curwin->w_cursor.lnum || Insstart_orig.col != (colnr_T)STRLEN(prompt)) {
Insstart.lnum = curwin->w_cursor.lnum;
- Insstart.col = STRLEN(prompt);
+ Insstart.col = (colnr_T)STRLEN(prompt);
Insstart_orig = Insstart;
Insstart_textlen = Insstart.col;
Insstart_blank_vcol = MAXCOL;
@@ -1696,7 +1696,7 @@ static void init_prompt(int cmdchar_todo)
coladvance(MAXCOL);
}
if (curwin->w_cursor.col < (colnr_T)STRLEN(prompt)) {
- curwin->w_cursor.col = STRLEN(prompt);
+ curwin->w_cursor.col = (colnr_T)STRLEN(prompt);
}
// Make sure the cursor is in a valid position.
check_cursor();
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index c0cb17fa61..4965eb9c20 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4584,6 +4584,9 @@ void ex_global(exarg_T *eap)
// a match on this line?
match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL, NULL);
+ if (regmatch.regprog == NULL) {
+ break; // re-compiling regprog failed
+ }
if ((type == 'g' && match) || (type == 'v' && !match)) {
ml_setmarked(lnum);
ndone++;
diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c
new file mode 100644
index 0000000000..b84124bc19
--- /dev/null
+++ b/src/nvim/lua/spell.c
@@ -0,0 +1,99 @@
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "nvim/spell.h"
+#include "nvim/vim.h"
+#include "nvim/lua/spell.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/spell.c.generated.h"
+#endif
+
+int nlua_spell_check(lua_State *lstate)
+{
+ if (lua_gettop(lstate) < 1) {
+ return luaL_error(lstate, "Expected 1 argument");
+ }
+
+ if (lua_type(lstate, 1) != LUA_TSTRING) {
+ luaL_argerror(lstate, 1, "expected string");
+ }
+
+ const char *str = lua_tolstring(lstate, 1, NULL);
+
+ // spell.c requires that 'spell' is enabled, so we need to temporarily enable
+ // it before we can call spell functions.
+ const int wo_spell_save = curwin->w_p_spell;
+
+ if (!curwin->w_p_spell) {
+ did_set_spelllang(curwin);
+ curwin->w_p_spell = true;
+ }
+
+ // Check 'spelllang'
+ if (*curwin->w_s->b_p_spl == NUL) {
+ emsg(_(e_no_spell));
+ curwin->w_p_spell = wo_spell_save;
+ return 0;
+ }
+
+ hlf_T attr = HLF_COUNT;
+ size_t len = 0;
+ size_t pos = 0;
+ int capcol = -1;
+ int no_res = 0;
+ const char * result;
+
+ lua_createtable(lstate, 0, 0);
+
+ while (*str != NUL) {
+ attr = HLF_COUNT;
+ len = spell_check(curwin, (char_u *)str, &attr, &capcol, false);
+ assert(len <= INT_MAX);
+
+ if (attr != HLF_COUNT) {
+ lua_createtable(lstate, 3, 0);
+
+ lua_pushlstring(lstate, str, len);
+ lua_rawseti(lstate, -2, 1);
+
+ result = attr == HLF_SPB ? "bad" :
+ attr == HLF_SPR ? "rare" :
+ attr == HLF_SPL ? "local" :
+ attr == HLF_SPC ? "caps" :
+ NULL;
+
+ assert(result != NULL);
+
+ lua_pushstring(lstate, result);
+ lua_rawseti(lstate, -2, 2);
+
+ // +1 for 1-indexing
+ lua_pushinteger(lstate, (long)pos + 1);
+ lua_rawseti(lstate, -2, 3);
+
+ lua_rawseti(lstate, -2, ++no_res);
+ }
+
+ str += len;
+ pos += len;
+ capcol -= (int)len;
+ }
+
+ // Restore 'spell'
+ curwin->w_p_spell = wo_spell_save;
+ return 1;
+}
+
+static const luaL_Reg spell_functions[] = {
+ { "check", nlua_spell_check },
+ { NULL , NULL }
+};
+
+int luaopen_spell(lua_State *L)
+{
+ lua_newtable(L);
+ luaL_register(L, NULL, spell_functions);
+ return 1;
+}
diff --git a/src/nvim/lua/spell.h b/src/nvim/lua/spell.h
new file mode 100644
index 0000000000..8f798a5191
--- /dev/null
+++ b/src/nvim/lua/spell.h
@@ -0,0 +1,12 @@
+#ifndef NVIM_LUA_SPELL_H
+#define NVIM_LUA_SPELL_H
+
+#include <lauxlib.h>
+#include <lua.h>
+#include <lualib.h>
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/spell.h.generated.h"
+#endif
+
+#endif // NVIM_LUA_SPELL_H
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index 0d6789317c..18a579ed0f 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -30,6 +30,7 @@
#include "nvim/lua/stdlib.h"
#include "nvim/lua/treesitter.h"
#include "nvim/lua/xdiff.h"
+#include "nvim/lua/spell.h"
#include "nvim/macros.h"
#include "nvim/map.h"
#include "nvim/memline.h"
@@ -518,6 +519,10 @@ void nlua_state_add_stdlib(lua_State *const lstate)
lua_pushcfunction(lstate, &nlua_xdl_diff);
lua_setfield(lstate, -2, "diff");
+ // vim.spell
+ luaopen_spell(lstate);
+ lua_setfield(lstate, -2, "spell");
+
lua_cjson_new(lstate);
lua_setfield(lstate, -2, "json");
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 04bd968ac8..65adda3c01 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2991,7 +2991,7 @@ ambw_end:
}
} else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) {
// 'foldcolumn'
- if (check_opt_strings(*varp, p_fdc_values, false) != OK) {
+ if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) {
errmsg = e_invarg;
}
} else if (varp == &p_pt) {
@@ -3370,6 +3370,9 @@ static int int_cmp(const void *a, const void *b)
/// @return OK when the value is valid, FAIL otherwise
int check_signcolumn(char_u *val)
{
+ if (*val == NUL) {
+ return FAIL;
+ }
// check for basic match
if (check_opt_strings(val, p_scl_values, false) == OK) {
return OK;
@@ -3610,7 +3613,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
c2 = c3 = 0;
s = p + len + 1;
c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || utf_char2cells(c1) > 1) {
+ if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg;
}
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
@@ -3618,12 +3621,12 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
return e_invarg;
}
c2 = get_encoded_char_adv(&s);
- if (c2 == 0 || utf_char2cells(c2) > 1) {
+ if (c2 == 0 || char2cells(c2) > 1) {
return e_invarg;
}
if (!(*s == ',' || *s == NUL)) {
c3 = get_encoded_char_adv(&s);
- if (c3 == 0 || utf_char2cells(c3) > 1) {
+ if (c3 == 0 || char2cells(c3) > 1) {
return e_invarg;
}
}
@@ -3657,7 +3660,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
multispace_len = 0;
while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || utf_char2cells(c1) > 1) {
+ if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg;
}
multispace_len++;
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 606c03f838..da2ada791f 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -386,7 +386,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
void pum_redraw(void)
{
int row = 0;
- int col;
+ int grid_col;
int attr_norm = win_hl_attr(curwin, HLF_PNI);
int attr_select = win_hl_attr(curwin, HLF_PSI);
int attr_scroll = win_hl_attr(curwin, HLF_PSB);
@@ -479,7 +479,7 @@ void pum_redraw(void)
// Display each entry, use two spaces for a Tab.
// Do this 3 times: For the main text, kind and extra info
- col = col_off;
+ grid_col = col_off;
totwidth = 0;
for (round = 1; round <= 3; ++round) {
@@ -537,24 +537,15 @@ void pum_redraw(void)
}
}
grid_puts_len(&pum_grid, rt, (int)STRLEN(rt), row,
- col - size + 1, attr);
+ grid_col - size + 1, attr);
xfree(rt_start);
xfree(st);
- col -= width;
+ grid_col -= width;
} else {
- int size = (int)STRLEN(st);
- int cells = (int)mb_string2cells(st);
-
- // only draw the text that fits
- while (size > 0 && col + cells > pum_width + pum_col) {
- size--;
- size -= utf_head_off(st, st + size);
- cells -= utf_ptr2cells(st + size);
- }
-
- grid_puts_len(&pum_grid, st, size, row, col, attr);
+ // use grid_puts_len() to truncate the text
+ grid_puts(&pum_grid, st, row, grid_col, attr);
xfree(st);
- col += width;
+ grid_col += width;
}
if (*p != TAB) {
@@ -563,12 +554,12 @@ void pum_redraw(void)
// Display two spaces for a Tab.
if (pum_rl) {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, col - 1,
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col - 1,
attr);
- col -= 2;
+ grid_col -= 2;
} else {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, col, attr);
- col += 2;
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col, attr);
+ grid_col += 2;
}
totwidth += 2;
// start text at next char
@@ -599,21 +590,21 @@ void pum_redraw(void)
if (pum_rl) {
grid_fill(&pum_grid, row, row + 1, col_off - pum_base_width - n + 1,
- col + 1, ' ', ' ', attr);
- col = col_off - pum_base_width - n + 1;
+ grid_col + 1, ' ', ' ', attr);
+ grid_col = col_off - pum_base_width - n + 1;
} else {
- grid_fill(&pum_grid, row, row + 1, col,
+ grid_fill(&pum_grid, row, row + 1, grid_col,
col_off + pum_base_width + n, ' ', ' ', attr);
- col = col_off + pum_base_width + n;
+ grid_col = col_off + pum_base_width + n;
}
totwidth = pum_base_width + n;
}
if (pum_rl) {
- grid_fill(&pum_grid, row, row + 1, col_off - pum_width + 1, col + 1,
+ grid_fill(&pum_grid, row, row + 1, col_off - pum_width + 1, grid_col + 1,
' ', ' ', attr);
} else {
- grid_fill(&pum_grid, row, row + 1, col, col_off + pum_width, ' ', ' ',
+ grid_fill(&pum_grid, row, row + 1, grid_col, col_off + pum_width, ' ', ' ',
attr);
}
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index eac1b4596e..41c927eaa6 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -2565,20 +2565,20 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent)
ga_concat(indent, (char_u *)"| ");
else
ga_concat(indent, (char_u *)" ");
- ga_append(indent, '\0');
+ ga_append(indent, NUL);
nfa_print_state2(debugf, state->out, indent);
/* replace last part of indent for state->out1 */
indent->ga_len -= 3;
ga_concat(indent, (char_u *)" ");
- ga_append(indent, '\0');
+ ga_append(indent, NUL);
nfa_print_state2(debugf, state->out1, indent);
/* shrink indent */
indent->ga_len -= 3;
- ga_append(indent, '\0');
+ ga_append(indent, NUL);
}
/*
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index a938a3b062..e62e3ca7bc 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -5933,6 +5933,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
// Only 1 cell left, but character requires 2 cells:
// display a '>' in the last column to avoid wrapping. */
c = '>';
+ u8c = '>';
+ u8cc[0] = 0;
mbyte_cells = 1;
}
@@ -5963,6 +5965,13 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
clear_next_cell = true;
}
+ // When at the start of the text and overwriting the right half of a
+ // two-cell character in the same grid, truncate that into a '>'.
+ if (ptr == text && col > 0 && grid->chars[off][0] == 0) {
+ grid->chars[off - 1][0] = '>';
+ grid->chars[off - 1][1] = 0;
+ }
+
schar_copy(grid->chars[off], buf);
grid->attrs[off] = attr;
if (mbyte_cells == 2) {
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index b3df8c63e6..fdae0697c3 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -13,7 +13,7 @@ set fillchars=vert:\|,fold:-
set laststatus=1
set listchars=eol:$
set joinspaces
-set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
+set nohidden nosmarttab noautoindent noautoread complete-=i noruler noshowcmd
set nrformats+=octal
set shortmess-=F
set sidescroll=0
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 4e1a24af61..45285b69a1 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -2380,95 +2380,7 @@ func Test_autocmd_was_using_freed_memory()
pclose
endfunc
-func Test_FileChangedShell_reload()
- if !has('unix')
- return
- endif
- augroup testreload
- au FileChangedShell Xchanged let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
- augroup END
- new Xchanged
- call setline(1, 'reload this')
- write
- " Need to wait until the timestamp would change by at least a second.
- sleep 2
- silent !echo 'extra line' >>Xchanged
- checktime
- call assert_equal('changed', g:reason)
- call assert_equal(2, line('$'))
- call assert_equal('extra line', getline(2))
-
- " Only triggers once
- let g:reason = ''
- checktime
- call assert_equal('', g:reason)
-
- " When deleted buffer is not reloaded
- silent !rm Xchanged
- let g:reason = ''
- checktime
- call assert_equal('deleted', g:reason)
- call assert_equal(2, line('$'))
- call assert_equal('extra line', getline(2))
-
- " When recreated buffer is reloaded
- call setline(1, 'buffer is changed')
- silent !echo 'new line' >>Xchanged
- let g:reason = ''
- checktime
- call assert_equal('conflict', g:reason)
- call assert_equal(1, line('$'))
- call assert_equal('new line', getline(1))
-
- " Only mode changed
- silent !chmod +x Xchanged
- let g:reason = ''
- checktime
- call assert_equal('mode', g:reason)
- call assert_equal(1, line('$'))
- call assert_equal('new line', getline(1))
-
- " Only time changed
- sleep 2
- silent !touch Xchanged
- let g:reason = ''
- checktime
- call assert_equal('time', g:reason)
- call assert_equal(1, line('$'))
- call assert_equal('new line', getline(1))
-
- if has('persistent_undo')
- " With an undo file the reload can be undone and a change before the
- " reload.
- set undofile
- call setline(2, 'before write')
- write
- call setline(2, 'after write')
- sleep 2
- silent !echo 'different line' >>Xchanged
- let g:reason = ''
- checktime
- call assert_equal('conflict', g:reason)
- call assert_equal(3, line('$'))
- call assert_equal('before write', getline(2))
- call assert_equal('different line', getline(3))
- " undo the reload
- undo
- call assert_equal(2, line('$'))
- call assert_equal('after write', getline(2))
- " undo the change before reload
- undo
- call assert_equal(2, line('$'))
- call assert_equal('before write', getline(2))
-
- set noundofile
- endif
-
-
- au! testreload
- bwipe!
- call delete('Xchanged')
-endfunc
+" FileChangedShell tested in test_filechanged.vim
func LogACmd()
call add(g:logged, line('$'))
diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim
index 20758b0c0a..af42b3857d 100644
--- a/src/nvim/testdir/test_blob.vim
+++ b/src/nvim/testdir/test_blob.vim
@@ -346,4 +346,12 @@ func Test_blob_sort()
endif
endfunc
+" The following used to cause an out-of-bounds memory access
+func Test_blob2string()
+ let v = '0z' .. repeat('01010101.', 444)
+ let v ..= '01'
+ exe 'let b = ' .. v
+ call assert_equal(v, string(b))
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index 12327f34d6..c2a9683f7c 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -263,6 +263,31 @@ func Test_display_scroll_at_topline()
call StopVimInTerminal(buf)
endfunc
+" Test for 'eob' (EndOfBuffer) item in 'fillchars'
+func Test_eob_fillchars()
+ " default value (skipped)
+ " call assert_match('eob:\~', &fillchars)
+ " invalid values
+ call assert_fails(':set fillchars=eob:', 'E474:')
+ call assert_fails(':set fillchars=eob:xy', 'E474:')
+ call assert_fails(':set fillchars=eob:\255', 'E474:')
+ call assert_fails(':set fillchars=eob:<ff>', 'E474:')
+ call assert_fails(":set fillchars=eob:\x01", 'E474:')
+ call assert_fails(':set fillchars=eob:\\x01', 'E474:')
+ " default is ~
+ new
+ redraw
+ call assert_equal('~', Screenline(2))
+ set fillchars=eob:+
+ redraw
+ call assert_equal('+', Screenline(2))
+ set fillchars=eob:\
+ redraw
+ call assert_equal(' ', nr2char(screenchar(2, 1)))
+ set fillchars&
+ close
+endfunc
+
func Test_display_linebreak_breakat()
new
vert resize 25
diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim
new file mode 100644
index 0000000000..b95cd5faf8
--- /dev/null
+++ b/src/nvim/testdir/test_filechanged.vim
@@ -0,0 +1,149 @@
+" Tests for when a file was changed outside of Vim.
+
+func Test_FileChangedShell_reload()
+ if !has('unix')
+ return
+ endif
+ augroup testreload
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
+ augroup END
+ new Xchanged_r
+ call setline(1, 'reload this')
+ write
+ " Need to wait until the timestamp would change by at least a second.
+ sleep 2
+ silent !echo 'extra line' >>Xchanged_r
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+
+ " Only triggers once
+ let g:reason = ''
+ checktime
+ call assert_equal('', g:reason)
+
+ " When deleted buffer is not reloaded
+ silent !rm Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('deleted', g:reason)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+
+ " When recreated buffer is reloaded
+ call setline(1, 'buffer is changed')
+ silent !echo 'new line' >>Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('conflict', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only mode changed
+ silent !chmod +x Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('mode', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only time changed
+ sleep 2
+ silent !touch Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('time', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ if has('persistent_undo')
+ " With an undo file the reload can be undone and a change before the
+ " reload.
+ set undofile
+ call setline(2, 'before write')
+ write
+ call setline(2, 'after write')
+ sleep 2
+ silent !echo 'different line' >>Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('conflict', g:reason)
+ call assert_equal(3, line('$'))
+ call assert_equal('before write', getline(2))
+ call assert_equal('different line', getline(3))
+ " undo the reload
+ undo
+ call assert_equal(2, line('$'))
+ call assert_equal('after write', getline(2))
+ " undo the change before reload
+ undo
+ call assert_equal(2, line('$'))
+ call assert_equal('before write', getline(2))
+
+ set noundofile
+ endif
+
+ au! testreload
+ bwipe!
+ call delete(undofile('Xchanged_r'))
+ call delete('Xchanged_r')
+endfunc
+
+func Test_file_changed_dialog()
+ throw 'skipped: TODO: '
+ if !has('unix') || has('gui_running')
+ return
+ endif
+ au! FileChangedShell
+
+ new Xchanged_d
+ call setline(1, 'reload this')
+ write
+ " Need to wait until the timestamp would change by at least a second.
+ sleep 2
+ silent !echo 'extra line' >>Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W11:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('reload this', getline(1))
+ call assert_equal('extra line', getline(2))
+
+ " delete buffer, only shows an error, no prompt
+ silent !rm Xchanged_d
+ checktime
+ call assert_match('E211:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+ let v:warningmsg = 'empty'
+
+ " change buffer, recreate the file and reload
+ call setline(1, 'buffer is changed')
+ silent !echo 'new line' >Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W12:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only mode changed, reload
+ silent !chmod +x Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W16:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only time changed, no prompt
+ sleep 2
+ silent !touch Xchanged_d
+ let v:warningmsg = ''
+ checktime
+ call assert_equal('', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ bwipe!
+ call delete('Xchanged_d')
+endfunc
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index dbe0cd8388..1ee23bb646 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -204,6 +204,7 @@ let s:filename_checks = {
\ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'],
\ 'gnuplot': ['file.gpi'],
\ 'go': ['file.go'],
+ \ 'gomod': ['go.mod'],
\ 'gp': ['file.gp', '.gprc'],
\ 'gpg': ['/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel', 'any/.gnupg/gpg.conf', 'any/.gnupg/options', 'any/usr/any/gnupg/options.skel'],
\ 'grads': ['file.gs'],
@@ -262,7 +263,7 @@ let s:filename_checks = {
\ 'jgraph': ['file.jgr'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'],
- \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc', 'file.slnf'],
\ 'jsonc': ['file.jsonc'],
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim
index f4ee539803..0bcbd9c4a5 100644
--- a/src/nvim/testdir/test_listchars.vim
+++ b/src/nvim/testdir/test_listchars.vim
@@ -331,7 +331,7 @@ func Test_listchars_invalid()
call assert_fails('set listchars=space:xx', 'E474:')
call assert_fails('set listchars=tab:xxxx', 'E474:')
- " Has non-single width character
+ " Has double-width character
call assert_fails('set listchars=space:·', 'E474:')
call assert_fails('set listchars=tab:·x', 'E474:')
call assert_fails('set listchars=tab:x·', 'E474:')
@@ -339,6 +339,20 @@ func Test_listchars_invalid()
call assert_fails('set listchars=multispace:·', 'E474:')
call assert_fails('set listchars=multispace:xxx·', 'E474:')
+ " Has control character
+ call assert_fails("set listchars=space:\x01", 'E474:')
+ call assert_fails("set listchars=tab:\x01x", 'E474:')
+ call assert_fails("set listchars=tab:x\x01", 'E474:')
+ call assert_fails("set listchars=tab:xx\x01", 'E474:')
+ call assert_fails("set listchars=multispace:\x01", 'E474:')
+ call assert_fails("set listchars=multispace:xxx\x01", 'E474:')
+ call assert_fails('set listchars=space:\\x01', 'E474:')
+ call assert_fails('set listchars=tab:\\x01x', 'E474:')
+ call assert_fails('set listchars=tab:x\\x01', 'E474:')
+ call assert_fails('set listchars=tab:xx\\x01', 'E474:')
+ call assert_fails('set listchars=multispace:\\x01', 'E474:')
+ call assert_fails('set listchars=multispace:xxx\\x01', 'E474:')
+
enew!
set ambiwidth& listchars& ff&
endfunction
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 2140fe21ea..e0286548d9 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -108,3 +108,11 @@ func Test_echospace()
set ruler& showcmd&
endfunc
+
+" this was missing a terminating NUL
+func Test_echo_string_partial()
+ function CountSpaces()
+ endfunction
+ call assert_equal("function('CountSpaces', [{'ccccccccccc': ['ab', 'cd'], 'aaaaaaaaaaa': v:false, 'bbbbbbbbbbbb': ''}])", string(function('CountSpaces', [#{aaaaaaaaaaa: v:false, bbbbbbbbbbbb: '', ccccccccccc: ['ab', 'cd']}])))
+endfunc
+
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index dbabdcf427..8344598486 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -144,7 +144,6 @@ endfun
" Test Virtual replace mode.
func Test_virtual_replace()
- throw 'skipped: TODO: '
if exists('&t_kD')
let save_t_kD = &t_kD
endif
@@ -166,7 +165,6 @@ func Test_virtual_replace()
\ ], getline(1, 6))
normal G
mark a
- inoremap <C-D> <Del>
exe "normal o0\<C-D>\nabcdefghi\njk\tlmn\n opq\trst\n\<C-D>uvwxyz\n"
exe "normal 'ajgR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR" . repeat("\<BS>", 29)
call assert_equal([' 1',