aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/options.txt2
-rw-r--r--src/nvim/ex_docmd.c63
-rw-r--r--src/nvim/normal.c4
-rw-r--r--src/nvim/option_defs.h3
-rw-r--r--src/nvim/spell_defs.h1
-rw-r--r--src/nvim/spellfile.c35
-rw-r--r--src/nvim/testdir/test_cmdline.vim21
-rw-r--r--src/nvim/testdir/test_edit.vim7
-rw-r--r--src/nvim/testdir/test_registers.vim69
-rw-r--r--src/nvim/window.c19
-rw-r--r--test/functional/legacy/cmdline_spec.lua66
-rw-r--r--test/functional/ui/cmdline_spec.lua32
12 files changed, 240 insertions, 82 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 448df31798..9fa152c86b 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2918,6 +2918,8 @@ A jump table for the options with a short description can be found at |Q_op|.
*'go-c'*
'c' Use console dialogs instead of popup dialogs for simple
choices.
+ *'go-d'*
+ 'd' Use dark theme variant if available.
*'go-e'*
'e' Add tab pages when indicated with 'showtabline'.
'guitablabel' can be used to change the text in the labels.
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 211791c19d..ad7db2ae98 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1251,7 +1251,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
char_u *errormsg = NULL; // error message
char_u *after_modifier = NULL;
exarg_T ea;
- int save_msg_scroll = msg_scroll;
+ const int save_msg_scroll = msg_scroll;
cmdmod_T save_cmdmod;
const int save_reg_executing = reg_executing;
char_u *cmd;
@@ -2003,34 +2003,10 @@ doend:
? cmdnames[(int)ea.cmdidx].cmd_name
: (char_u *)NULL);
- if (ea.verbose_save >= 0) {
- p_verbose = ea.verbose_save;
- }
- free_cmdmod();
-
+ undo_cmdmod(&ea, save_msg_scroll);
cmdmod = save_cmdmod;
reg_executing = save_reg_executing;
- if (ea.save_msg_silent != -1) {
- // messages could be enabled for a serious error, need to check if the
- // counters don't become negative
- if (!did_emsg || msg_silent > ea.save_msg_silent) {
- msg_silent = ea.save_msg_silent;
- }
- emsg_silent -= ea.did_esilent;
- if (emsg_silent < 0) {
- emsg_silent = 0;
- }
- // Restore msg_scroll, it's set by file I/O commands, even when no
- // message is actually displayed.
- msg_scroll = save_msg_scroll;
-
- /* "silent reg" or "silent echo x" inside "redir" leaves msg_col
- * somewhere in the line. Put it back in the first column. */
- if (redirecting())
- msg_col = 0;
- }
-
if (ea.did_sandbox) {
sandbox--;
}
@@ -2298,9 +2274,14 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
return OK;
}
-// Free contents of "cmdmod".
-static void free_cmdmod(void)
+// Undo and free contents of "cmdmod".
+static void undo_cmdmod(const exarg_T *eap, int save_msg_scroll)
+ FUNC_ATTR_NONNULL_ALL
{
+ if (eap->verbose_save >= 0) {
+ p_verbose = eap->verbose_save;
+ }
+
if (cmdmod.save_ei != NULL) {
/* Restore 'eventignore' to the value before ":noautocmd". */
set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei,
@@ -2308,8 +2289,27 @@ static void free_cmdmod(void)
free_string_option(cmdmod.save_ei);
}
- if (cmdmod.filter_regmatch.regprog != NULL) {
- vim_regfree(cmdmod.filter_regmatch.regprog);
+ vim_regfree(cmdmod.filter_regmatch.regprog);
+
+ if (eap->save_msg_silent != -1) {
+ // messages could be enabled for a serious error, need to check if the
+ // counters don't become negative
+ if (!did_emsg || msg_silent > eap->save_msg_silent) {
+ msg_silent = eap->save_msg_silent;
+ }
+ emsg_silent -= eap->did_esilent;
+ if (emsg_silent < 0) {
+ emsg_silent = 0;
+ }
+ // Restore msg_scroll, it's set by file I/O commands, even when no
+ // message is actually displayed.
+ msg_scroll = save_msg_scroll;
+
+ // "silent reg" or "silent echo x" inside "redir" leaves msg_col
+ // somewhere in the line. Put it back in the first column.
+ if (redirecting()) {
+ msg_col = 0;
+ }
}
}
@@ -4446,6 +4446,9 @@ void separate_nextcmd(exarg_T *eap)
else if (p[0] == '`' && p[1] == '=' && (eap->argt & XFILE)) {
p += 2;
(void)skip_expr(&p);
+ if (*p == NUL) { // stop at NUL after CTRL-V
+ break;
+ }
}
/* Check for '"': start of comment or '|': next command */
/* :@" does not start a comment!
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 1cc400166c..d364c178b2 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -903,6 +903,10 @@ normal_end:
msg_nowait = false;
+ if (finish_op) {
+ set_reg_var(get_default_register_name());
+ }
+
// Reset finish_op, in case it was set
s->c = finish_op;
finish_op = false;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 4042b79262..af0ea7f4a2 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -188,6 +188,7 @@ enum {
#define GO_ASELML 'A' // autoselect modeless selection
#define GO_BOT 'b' // use bottom scrollbar
#define GO_CONDIALOG 'c' // use console dialog
+#define GO_DARKTHEME 'd' // use dark theme variant
#define GO_TABLINE 'e' // may show tabline
#define GO_FORG 'f' // start GUI in foreground
#define GO_GREY 'g' // use grey menu items
@@ -205,7 +206,7 @@ enum {
#define GO_FOOTER 'F' // add footer
#define GO_VERTICAL 'v' // arrange dialog buttons vertically
#define GO_KEEPWINSIZE 'k' // keep GUI window size
-#define GO_ALL "aAbcefFghilmMprTvk" // all possible flags for 'go'
+#define GO_ALL "aAbcdefFghilmMprTvk" // all possible flags for 'go'
// flags for 'comments' option
#define COM_NEST 'n' // comments strings nest
diff --git a/src/nvim/spell_defs.h b/src/nvim/spell_defs.h
index 034c580b3e..05667f060e 100644
--- a/src/nvim/spell_defs.h
+++ b/src/nvim/spell_defs.h
@@ -119,6 +119,7 @@ struct slang_S {
bool sl_add; // true if it's a .add file.
char_u *sl_fbyts; // case-folded word bytes
+ long sl_fbyts_len; // length of sl_fbyts
idx_T *sl_fidxs; // case-folded word indexes
char_u *sl_kbyts; // keep-case word bytes
idx_T *sl_kidxs; // keep-case word indexes
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 09d8646c6d..b415a4635b 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -764,20 +764,24 @@ truncerr:
}
// <LWORDTREE>
- res = spell_read_tree(fd, &lp->sl_fbyts, &lp->sl_fidxs, false, 0);
- if (res != 0)
+ res = spell_read_tree(fd, &lp->sl_fbyts, &lp->sl_fbyts_len,
+ &lp->sl_fidxs, false, 0);
+ if (res != 0) {
goto someerror;
+ }
// <KWORDTREE>
- res = spell_read_tree(fd, &lp->sl_kbyts, &lp->sl_kidxs, false, 0);
- if (res != 0)
+ res = spell_read_tree(fd, &lp->sl_kbyts, NULL, &lp->sl_kidxs, false, 0);
+ if (res != 0) {
goto someerror;
+ }
// <PREFIXTREE>
- res = spell_read_tree(fd, &lp->sl_pbyts, &lp->sl_pidxs, true,
- lp->sl_prefixcnt);
- if (res != 0)
+ res = spell_read_tree(fd, &lp->sl_pbyts, NULL, &lp->sl_pidxs, true,
+ lp->sl_prefixcnt);
+ if (res != 0) {
goto someerror;
+ }
// For a new file link it in the list of spell files.
if (old_lp == NULL && lang != NULL) {
@@ -920,8 +924,8 @@ void suggest_load_files(void)
// <SUGWORDTREE>: <wordtree>
// Read the trie with the soundfolded words.
- if (spell_read_tree(fd, &slang->sl_sbyts, &slang->sl_sidxs,
- false, 0) != 0) {
+ if (spell_read_tree(fd, &slang->sl_sbyts, NULL, &slang->sl_sidxs,
+ false, 0) != 0) {
someerror:
EMSG2(_("E782: error while reading .sug file: %s"),
slang->sl_fname);
@@ -1630,10 +1634,12 @@ static int
spell_read_tree (
FILE *fd,
char_u **bytsp,
+ long *bytsp_len,
idx_T **idxsp,
bool prefixtree, // true for the prefix tree
int prefixcnt // when "prefixtree" is true: prefix count
)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
int idx;
char_u *bp;
@@ -1653,6 +1659,9 @@ spell_read_tree (
// Allocate the byte array.
bp = xmalloc(len);
*bytsp = bp;
+ if (bytsp_len != NULL) {
+ *bytsp_len = len;
+ }
// Allocate the index array.
ip = xcalloc(len, sizeof(*ip));
@@ -4850,10 +4859,10 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
spin->si_blocks_cnt = 0;
// Skip over any other NUL bytes (same word with different
- // flags).
- while (byts[n + 1] == 0) {
- ++n;
- ++curi[depth];
+ // flags). But don't go over the end.
+ while (n + 1 < slang->sl_fbyts_len && byts[n + 1] == 0) {
+ n++;
+ curi[depth]++;
}
} else {
// Normal char, go one level deeper.
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 871143699a..e3c42a4fe3 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -722,7 +722,7 @@ func Test_verbosefile()
endfunc
func Test_verbose_option()
- " See test/functional/ui/cmdline_spec.lua
+ " See test/functional/legacy/cmdline_spec.lua
CheckScreendump
let lines =<< trim [SCRIPT]
@@ -842,6 +842,25 @@ func Test_buffers_lastused()
bwipeout bufc
endfunc
+func Test_cmdlineclear_tabenter()
+ " See test/functional/legacy/cmdline_spec.lua
+ CheckScreendump
+
+ let lines =<< trim [SCRIPT]
+ call setline(1, range(30))
+ [SCRIPT]
+
+ call writefile(lines, 'XtestCmdlineClearTabenter')
+ let buf = RunVimInTerminal('-S XtestCmdlineClearTabenter', #{rows: 10})
+ call term_wait(buf, 50)
+ " in one tab make the command line higher with CTRL-W -
+ call term_sendkeys(buf, ":tabnew\<cr>\<C-w>-\<C-w>-gtgt")
+ call VerifyScreenDump(buf, 'Test_cmdlineclear_tabenter', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XtestCmdlineClearTabenter')
+endfunc
+
" test that ";" works to find a match at the start of the first line
func Test_zero_line_search()
new
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 15c718b243..abad6983dc 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1587,4 +1587,11 @@ func Test_edit_browse()
bwipe!
endfunc
+func Test_read_invalid()
+ " set encoding=latin1
+ " This was not properly checking for going past the end.
+ call assert_fails('r`=', 'E484')
+ set encoding=utf-8
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index d20f8d1eef..19a7c6c9d0 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -167,6 +167,75 @@ func Test_set_register()
enew!
endfunc
+func Test_v_register()
+ enew
+ call setline(1, 'nothing')
+
+ func s:Put()
+ let s:register = v:register
+ exec 'normal! "' .. v:register .. 'P'
+ endfunc
+ nnoremap <buffer> <plug>(test) :<c-u>call s:Put()<cr>
+ nmap <buffer> S <plug>(test)
+
+ let @z = "testz\n"
+ let @" = "test@\n"
+
+ let s:register = ''
+ call feedkeys('"_ddS', 'mx')
+ call assert_equal('test@', getline('.')) " fails before 8.2.0929
+ call assert_equal('"', s:register) " fails before 8.2.0929
+
+ let s:register = ''
+ call feedkeys('"zS', 'mx')
+ call assert_equal('z', s:register)
+
+ let s:register = ''
+ call feedkeys('"zSS', 'mx')
+ call assert_equal('"', s:register)
+
+ let s:register = ''
+ call feedkeys('"_S', 'mx')
+ call assert_equal('_', s:register)
+
+ let s:register = ''
+ normal "_ddS
+ call assert_equal('"', s:register) " fails before 8.2.0929
+ call assert_equal('test@', getline('.')) " fails before 8.2.0929
+
+ let s:register = ''
+ execute 'normal "z:call' "s:Put()\n"
+ call assert_equal('z', s:register)
+ call assert_equal('testz', getline('.'))
+
+ " Test operator and omap
+ let @b = 'testb'
+ func s:OpFunc(...)
+ let s:register2 = v:register
+ endfunc
+ set opfunc=s:OpFunc
+
+ normal "bg@l
+ normal S
+ call assert_equal('"', s:register) " fails before 8.2.0929
+ call assert_equal('b', s:register2)
+
+ func s:Motion()
+ let s:register1 = v:register
+ normal! l
+ endfunc
+ onoremap <buffer> Q :<c-u>call s:Motion()<cr>
+
+ normal "bg@Q
+ normal S
+ call assert_equal('"', s:register)
+ call assert_equal('b', s:register1)
+ call assert_equal('"', s:register2)
+
+ set opfunc&
+ bwipe!
+endfunc
+
func Test_ve_blockpaste()
new
set ve=all
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 4931221e7a..96409304ab 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -4049,7 +4049,7 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
prevwin = next_prevwin;
last_status(false); // status line may appear or disappear
- (void)win_comp_pos(); // recompute w_winrow for all windows
+ const int row = win_comp_pos(); // recompute w_winrow for all windows
diff_need_scrollbind = true;
/* The tabpage line may have appeared or disappeared, may need to resize
@@ -4060,11 +4060,20 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
clear_cmdline = true;
}
p_ch = curtab->tp_ch_used;
- if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow
- ))
+
+ // When cmdheight is changed in a tab page with '<C-w>-', cmdline_row is
+ // changed but p_ch and tp_ch_used are not changed. Thus we also need to
+ // check cmdline_row.
+ if ((row < cmdline_row) && (cmdline_row <= Rows - p_ch)) {
+ clear_cmdline = true;
+ }
+
+ if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow)) {
shell_new_rows();
- if (curtab->tp_old_Columns != Columns && starting == 0)
- shell_new_columns(); /* update window widths */
+ }
+ if (curtab->tp_old_Columns != Columns && starting == 0) {
+ shell_new_columns(); // update window widths
+ }
lastused_tabpage = old_curtab;
diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
new file mode 100644
index 0000000000..9ebe9aeb91
--- /dev/null
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -0,0 +1,66 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+local source = helpers.source
+
+describe('cmdline', function()
+ before_each(clear)
+
+ it('is cleared when switching tabs', function()
+ local screen = Screen.new(30, 10)
+ screen:attach()
+ feed_command([[call setline(1, range(30))]])
+ screen:expect([[
+ ^0 |
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ 5 |
+ 6 |
+ 7 |
+ 8 |
+ :call setline(1, range(30)) |
+ ]])
+ feed([[:tabnew<cr><C-w>-<C-w>-gtgt]])
+ screen:expect([[
+ + [No Name] [No Name] X|
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ 6 |
+ 7 |
+ |
+ ]])
+ end)
+
+ it('prints every executed Ex command if verbose >= 16', function()
+ local screen = Screen.new(60, 12)
+ screen:attach()
+ source([[
+ command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
+ call feedkeys("\r", 't') " for the hit-enter prompt
+ set verbose=20
+ ]])
+ feed_command('DoSomething')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ |
+ Executing: DoSomething |
+ Executing: echo 'hello' |set ts=4 |let v = '123' |echo v |
+ hello |
+ Executing: set ts=4 |let v = '123' |echo v |
+ Executing: let v = '123' |echo v |
+ Executing: echo v |
+ 123 |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 01f0d8a4d7..21c01b3458 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -3,7 +3,6 @@ local Screen = require('test.functional.ui.screen')
local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
local command = helpers.command
-local feed_command = helpers.feed_command
local function new_screen(opt)
local screen = Screen.new(25, 5)
@@ -843,34 +842,3 @@ describe('cmdline redraw', function()
]], unchanged=true}
end)
end)
-
-describe('cmdline', function()
- before_each(function()
- clear()
- end)
-
- it('prints every executed Ex command if verbose >= 16', function()
- local screen = Screen.new(50, 12)
- screen:attach()
- source([[
- command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
- call feedkeys("\r", 't') " for the hit-enter prompt
- set verbose=20
- ]])
- feed_command('DoSomething')
- screen:expect([[
- |
- ~ |
- |
- Executing: DoSomething |
- Executing: echo 'hello' |set ts=4 |let v = '123' ||
- echo v |
- hello |
- Executing: set ts=4 |let v = '123' |echo v |
- Executing: let v = '123' |echo v |
- Executing: echo v |
- 123 |
- Press ENTER or type command to continue^ |
- ]])
- end)
-end)