diff options
-rw-r--r-- | .github/workflows/ci.yml | 3 | ||||
-rw-r--r-- | runtime/doc/api.txt | 3 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 25 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 56 | ||||
-rw-r--r-- | src/nvim/testdir/test_excmd.vim | 8 | ||||
-rw-r--r-- | src/nvim/window.c | 1 | ||||
-rw-r--r-- | test/functional/api/command_spec.lua | 133 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/ui/inccommand_spec.lua | 102 | ||||
-rw-r--r-- | test/functional/ui/winbar_spec.lua | 19 |
11 files changed, 345 insertions, 8 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4657053167..16464426ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,7 +120,8 @@ jobs: - if: "!cancelled()" name: uncrustify run: | - ${{ env.CACHE_UNCRUSTIFY }} -c ./src/uncrustify.cfg -q --check $(find ./src/nvim -name "*.[ch]") >/dev/null + ${{ env.CACHE_UNCRUSTIFY }} -c ./src/uncrustify.cfg -q --replace --no-backup $(find ./src/nvim -name "*.[ch]") + git diff --color --exit-code - if: "!cancelled()" name: lualint diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 3ab7c77056..965b8e6492 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -743,6 +743,9 @@ nvim_create_user_command({name}, {command}, {*opts}) specified |<reg>| • mods: (string) Command modifiers, if any |<mods>| + • smods: (table) Command modifiers in a + structured format. Has the same structure as + the "mods" key of |nvim_parse_cmd()|. {opts} Optional command attributes. See |command-attributes| for more details. To use boolean attributes (such as |:command-bang| or diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index dd0b75bbfb..5c3c16d6b0 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2501,6 +2501,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error * /// - count: (number) Any count supplied |<count>| /// - reg: (string) The optional register, if specified |<reg>| /// - mods: (string) Command modifiers, if any |<mods>| +/// - smods: (table) Command modifiers in a structured format. Has the same +/// structure as the "mods" key of |nvim_parse_cmd()|. /// @param opts Optional command attributes. See |command-attributes| for more details. To use /// boolean attributes (such as |:command-bang| or |:command-bar|) set the value to /// "true". In addition to the string options listed in |:command-complete|, the diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 4b7958efa5..e6ee0046af 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2751,6 +2751,8 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) { int address_count = 1; linenr_T lnum; + bool need_check_cursor = false; + int ret = FAIL; // Repeat for all ',' or ';' separated addresses. for (;;) { @@ -2760,7 +2762,7 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent, eap->addr_count == 0, address_count++); if (eap->cmd == NULL) { // error detected - return FAIL; + goto theend; } if (lnum == MAXLNUM) { if (*eap->cmd == '%') { // '%' - all lines @@ -2799,14 +2801,14 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) // there is no Vim command which uses '%' and // ADDR_WINDOWS or ADDR_TABS *errormsg = _(e_invrange); - return FAIL; + goto theend; } break; case ADDR_TABS_RELATIVE: case ADDR_UNSIGNED: case ADDR_QUICKFIX: *errormsg = _(e_invrange); - return FAIL; + goto theend; case ADDR_ARGUMENTS: if (ARGCOUNT == 0) { eap->line1 = eap->line2 = 0; @@ -2831,19 +2833,19 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) // '*' - visual area if (eap->addr_type != ADDR_LINES) { *errormsg = _(e_invrange); - return FAIL; + goto theend; } eap->cmd++; if (!eap->skip) { pos_T *fp = getmark('<', false); if (check_mark(fp) == FAIL) { - return FAIL; + goto theend; } eap->line1 = fp->lnum; fp = getmark('>', false); if (check_mark(fp) == FAIL) { - return FAIL; + goto theend; } eap->line2 = fp->lnum; eap->addr_count++; @@ -2857,11 +2859,14 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) if (*eap->cmd == ';') { if (!eap->skip) { curwin->w_cursor.lnum = eap->line2; + // Don't leave the cursor on an illegal line or column, but do // accept zero as address, so 0;/PATTERN/ works correctly. + // Check the cursor position before returning. if (eap->line2 > 0) { check_cursor(); } + need_check_cursor = true; } } else if (*eap->cmd != ',') { break; @@ -2877,7 +2882,13 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) eap->addr_count = 0; } } - return OK; + ret = OK; + +theend: + if (need_check_cursor) { + check_cursor(); + } + return ret; } /// Check for an Ex command with optional tail. diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 0009420281..a826dd07d3 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -40,6 +40,7 @@ #include "nvim/undo.h" #include "nvim/version.h" #include "nvim/vim.h" +#include "nvim/window.h" static int in_fast_callback = 0; @@ -1913,6 +1914,61 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) lua_pushstring(lstate, buf); lua_setfield(lstate, -2, "mods"); + lua_newtable(lstate); // smods table + + lua_pushinteger(lstate, cmdmod.tab); + lua_setfield(lstate, -2, "tab"); + lua_pushinteger(lstate, p_verbose); + lua_setfield(lstate, -2, "verbose"); + + if (cmdmod.split & WSP_ABOVE) { + lua_pushstring(lstate, "aboveleft"); + } else if (cmdmod.split & WSP_BELOW) { + lua_pushstring(lstate, "belowright"); + } else if (cmdmod.split & WSP_TOP) { + lua_pushstring(lstate, "topleft"); + } else if (cmdmod.split & WSP_BOT) { + lua_pushstring(lstate, "botright"); + } else { + lua_pushstring(lstate, ""); + } + lua_setfield(lstate, -2, "split"); + + lua_pushboolean(lstate, cmdmod.split & WSP_VERT); + lua_setfield(lstate, -2, "vertical"); + lua_pushboolean(lstate, msg_silent != 0); + lua_setfield(lstate, -2, "silent"); + lua_pushboolean(lstate, emsg_silent != 0); + lua_setfield(lstate, -2, "emsg_silent"); + lua_pushboolean(lstate, eap->did_sandbox); + lua_setfield(lstate, -2, "sandbox"); + lua_pushboolean(lstate, cmdmod.save_ei != NULL); + lua_setfield(lstate, -2, "noautocmd"); + + typedef struct { + bool *set; + char *name; + } mod_entry_T; + static mod_entry_T mod_entries[] = { + { &cmdmod.browse, "browse" }, + { &cmdmod.confirm, "confirm" }, + { &cmdmod.hide, "hide" }, + { &cmdmod.keepalt, "keepalt" }, + { &cmdmod.keepjumps, "keepjumps" }, + { &cmdmod.keepmarks, "keepmarks" }, + { &cmdmod.keeppatterns, "keeppatterns" }, + { &cmdmod.lockmarks, "lockmarks" }, + { &cmdmod.noswapfile, "noswapfile" } + }; + + // The modifiers that are simple flags + for (size_t i = 0; i < ARRAY_SIZE(mod_entries); i++) { + lua_pushboolean(lstate, *mod_entries[i].set); + lua_setfield(lstate, -2, mod_entries[i].name); + } + + lua_setfield(lstate, -2, "smods"); + if (nlua_pcall(lstate, 1, 0)) { nlua_error(lstate, _("Error executing Lua callback: %.*s")); } diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim index 8055a51a11..7dde8a0439 100644 --- a/src/nvim/testdir/test_excmd.vim +++ b/src/nvim/testdir/test_excmd.vim @@ -422,5 +422,13 @@ func Test_address_line_overflow() bwipe! endfunc +" This was leaving the cursor in line zero +func Test_using_zero_in_range() + new + norm o00 + silent! 0;s/\%') + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/window.c b/src/nvim/window.c index 060f498f07..a41f3362d2 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3993,6 +3993,7 @@ void win_init_size(void) firstwin->w_height = ROWS_AVAIL; firstwin->w_height_inner = firstwin->w_height - firstwin->w_winbar_height; firstwin->w_height_outer = firstwin->w_height; + firstwin->w_winrow_off = firstwin->w_winbar_height; topframe->fr_height = ROWS_AVAIL; firstwin->w_width = Columns; firstwin->w_width_inner = firstwin->w_width; diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index e4963e8a65..d6d75e93e4 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -120,6 +120,25 @@ describe('nvim_create_user_command', function() line1 = 1, line2 = 1, mods = "", + smods = { + browse = false, + confirm = false, + emsg_silent = false, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "", + tab = 0, + verbose = 0, + vertical = false, + }, range = 0, count = 2, reg = "", @@ -135,6 +154,25 @@ describe('nvim_create_user_command', function() line1 = 1, line2 = 1, mods = "", + smods = { + browse = false, + confirm = false, + emsg_silent = false, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "", + tab = 0, + verbose = 0, + vertical = false, + }, range = 0, count = 2, reg = "", @@ -150,6 +188,25 @@ describe('nvim_create_user_command', function() line1 = 1, line2 = 1, mods = "", + smods = { + browse = false, + confirm = false, + emsg_silent = false, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "", + tab = 0, + verbose = 0, + vertical = false, + }, range = 0, count = 2, reg = "", @@ -165,6 +222,25 @@ describe('nvim_create_user_command', function() line1 = 10, line2 = 10, mods = "botright", + smods = { + browse = false, + confirm = false, + emsg_silent = false, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "botright", + tab = 0, + verbose = 0, + vertical = false, + }, range = 1, count = 10, reg = "", @@ -180,6 +256,25 @@ describe('nvim_create_user_command', function() line1 = 1, line2 = 42, mods = "", + smods = { + browse = false, + confirm = false, + emsg_silent = false, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "", + tab = 0, + verbose = 0, + vertical = false, + }, range = 1, count = 42, reg = "", @@ -195,6 +290,25 @@ describe('nvim_create_user_command', function() line1 = 1, line2 = 1, mods = "", + smods = { + browse = false, + confirm = false, + emsg_silent = false, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "", + tab = 0, + verbose = 0, + vertical = false, + }, range = 0, count = 2, reg = "", @@ -222,6 +336,25 @@ describe('nvim_create_user_command', function() line1 = 1, line2 = 1, mods = "", + smods = { + browse = false, + confirm = false, + emsg_silent = false, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "", + tab = 0, + verbose = 0, + vertical = false, + }, range = 0, count = 2, reg = "", diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index cf24e570cb..461a69f357 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -682,6 +682,7 @@ describe('jobs', function() -- User can explicitly set $NVIM_LOG_FILE, $VIM, $VIMRUNTIME. eq('NVIM_LOG_FILE=Xtest_jobstart_env', get_env_in_child_job('NVIM_LOG_FILE', { NVIM_LOG_FILE='Xtest_jobstart_env' })) + os.remove('Xtest_jobstart_env') end) describe('jobwait', function() diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index fb80444430..a1ff778da1 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -1343,6 +1343,108 @@ describe(":substitute, inccommand=split", function() ]]) end) + it([[preview changes correctly with c_CTRL-R_= and c_CTRL-\_e]], function() + feed('gg') + feed(":1,2s/t/X") + screen:expect([[ + Inc subs{12:X}itution on | + {12:X}wo lines | + Inc substitution on | + two lines | + | + {11:[No Name] [+] }| + |1| Inc subs{12:X}itution on | + |2| {12:X}wo lines | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + :1,2s/t/X^ | + ]]) + + feed([[<C-R>='Y']]) + -- preview should be unchanged during c_CTRL-R_= editing + screen:expect([[ + Inc subs{12:X}itution on | + {12:X}wo lines | + Inc substitution on | + two lines | + | + {11:[No Name] [+] }| + |1| Inc subs{12:X}itution on | + |2| {12:X}wo lines | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + ={1:'Y'}^ | + ]]) + + feed('<CR>') + -- preview should be changed by the result of the expression + screen:expect([[ + Inc subs{12:XY}itution on | + {12:XY}wo lines | + Inc substitution on | + two lines | + | + {11:[No Name] [+] }| + |1| Inc subs{12:XY}itution on | + |2| {12:XY}wo lines | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + :1,2s/t/XY^ | + ]]) + + feed([[<C-\>e'echo']]) + -- preview should be unchanged during c_CTRL-\_e editing + screen:expect([[ + Inc subs{12:XY}itution on | + {12:XY}wo lines | + Inc substitution on | + two lines | + | + {11:[No Name] [+] }| + |1| Inc subs{12:XY}itution on | + |2| {12:XY}wo lines | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {10:[Preview] }| + ={1:'echo'}^ | + ]]) + + feed('<CR>') + -- preview should be cleared if command is changed to a non-previewable one + screen:expect([[ + Inc substitution on | + two lines | + Inc substitution on | + two lines | + | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + :echo^ | + ]]) + end) + end) describe("inccommand=nosplit", function() diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua index 982d2d67fd..92a6ab2e84 100644 --- a/test/functional/ui/winbar_spec.lua +++ b/test/functional/ui/winbar_spec.lua @@ -26,6 +26,8 @@ describe('winbar', function() [7] = {background = Screen.colors.LightGrey}, [8] = {background = Screen.colors.LightMagenta}, [9] = {bold = true, foreground = Screen.colors.Blue, background = Screen.colors.LightMagenta}, + [10] = {background = Screen.colors.LightGrey, underline = true}, + [11] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta}, }) meths.set_option('winbar', 'Set Up The Bars') end) @@ -245,6 +247,23 @@ describe('winbar', function() {4:[No Name] }| | ]]) + -- Test for issue #18791 + command('tabnew') + screen:expect([[ + {10: }{11:4}{10: [No Name] }{1: [No Name] }{2: }{10:X}| + {1:Set Up The Bars }| + ^ | + {3:~ }| + {3:~ }| + {3:~ }| + {3:~ }| + {3:~ }| + {3:~ }| + {3:~ }| + {3:~ }| + {4:[No Name] }| + | + ]]) end) it('mouse click and drag work correctly in buffer', function() |