diff options
-rw-r--r-- | .github/workflows/ci.yml | 3 | ||||
-rw-r--r-- | .github/workflows/coverity-scan.yml | 2 | ||||
-rw-r--r-- | .github/workflows/vim-patches.yml | 2 | ||||
-rw-r--r-- | runtime/doc/treesitter.txt | 62 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/languagetree.lua | 21 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/query.lua | 27 | ||||
-rwxr-xr-x | scripts/vim-patch.sh | 4 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 25 | ||||
-rw-r--r-- | src/nvim/testdir/test_excmd.vim | 8 | ||||
-rw-r--r-- | src/nvim/window.c | 1 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/legacy/fixeol_spec.lua | 11 | ||||
-rw-r--r-- | test/functional/ui/inccommand_spec.lua | 102 | ||||
-rw-r--r-- | test/functional/ui/winbar_spec.lua | 19 |
14 files changed, 231 insertions, 57 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/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml index 064da54456..ce7822b5c1 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan.yml @@ -6,7 +6,7 @@ on: jobs: scan: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/vim-patches.yml b/.github/workflows/vim-patches.yml index 45e6b81aed..df8c8116b5 100644 --- a/.github/workflows/vim-patches.yml +++ b/.github/workflows/vim-patches.yml @@ -5,7 +5,7 @@ on: jobs: update-vim-patches: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest permissions: contents: write pull-requests: write diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 339ae0c2ed..52b415bbd1 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -261,36 +261,37 @@ for a node or match and perform side effects. For example, the |set!| predicate sets metadata on the match or node : > ((identifier) @foo (#set! "type" "parameter")) -Here is a list of built-in directives: +Built-in directives: - `set!` *ts-directive-set!* - Sets key/value metadata for a specific node or match : > - ((identifier) @foo (#set! @foo "kind" "parameter")) - ((node1) @left (node2) @right (#set! "type" "pair")) + `set!` *ts-directive-set!* + Sets key/value metadata for a specific match or capture. + Value is accessible as either `metadata[key]` (match + specific) or `metadata[capture_id][key]` (capture specific). + + Parameters: ~ + {capture_id} (optional) + {key} + {value} + + Examples: > + ((identifier) @foo (#set! @foo "kind" "parameter")) + ((node1) @left (node2) @right (#set! "type" "pair")) < - `offset!` *ts-directive-offset!* - Takes the range of the captured node and applies the offsets - to it's range : > - ((identifier) @constant (#offset! @constant 0 1 0 -1)) -< This will generate a range object for the captured node with - the offsets applied. The arguments are - `({capture_id}, {start_row}, {start_col}, {end_row}, {end_col}, {key?})` - The default key is "offset". - - *vim.treesitter.query.add_directive()* -vim.treesitter.query.add_directive({name}, {handler}) - -This adds a directive with the name {name} to be used in queries. -{handler} should be a function whose signature will be : > - handler(match, pattern, bufnr, predicate, metadata) -Handlers can set match level data by setting directly on the metadata object -`metadata.key = value` Handlers can set node level data by using the capture -id on the metadata table `metadata[capture_id].key = value` + `offset!` *ts-directive-offset!* + Takes the range of the captured node and applies an offset. + This will generate a new range object for the captured node + as `metadata[capture_id].range`. - *vim.treesitter.query.list_directives()* -vim.treesitter.query.list_directives() + Parameters: ~ + {capture_id} + {start_row} + {start_col} + {end_row} + {end_col} -This lists the currently available directives to use in queries. + Example: > + ((identifier) @constant (#offset! @constant 0 1 0 -1)) +< Treesitter syntax highlighting (WIP) *lua-treesitter-highlight* @@ -409,10 +410,15 @@ Lua module: vim.treesitter.query *treesitter-query* add_directive({name}, {handler}, {force}) *add_directive()* Adds a new directive to be used in queries + Handlers can set match level data by setting directly on the + metadata object `metadata.key = value`, additionally, handlers + can set node level data by using the capture id on the + metadata table `metadata[capture_id].key = value` + Parameters: ~ {name} the name of the directive, without leading # {handler} the handler function to be used signature will - be (match, pattern, bufnr, predicate) + be (match, pattern, bufnr, predicate, metadata) add_predicate({name}, {handler}, {force}) *add_predicate()* Adds a new predicate to be used in queries @@ -451,6 +457,8 @@ get_query_files({lang}, {query_name}, {is_included}) as `nil` list_directives() *list_directives()* + Lists the currently available directives to use in queries. + Return: ~ The list of supported directives. diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 57d8c5fd21..5a05a29da8 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -295,6 +295,14 @@ function LanguageTree:included_regions() return self._regions end +---@private +local function get_node_range(node, id, metadata) + if metadata[id] and metadata[id].range then + return metadata[id].range + end + return { node:range() } +end + --- Gets language injection points by language. --- --- This is where most of the injection processing occurs. @@ -327,10 +335,10 @@ function LanguageTree:_get_injections() -- Allow for captured nodes to be used if type(content) == 'number' then - content = { match[content] } + content = { match[content]:range() } end - if content then + if type(content) == 'table' and #content >= 4 then vim.list_extend(ranges, content) end end @@ -351,7 +359,7 @@ function LanguageTree:_get_injections() elseif name == 'combined' then combined = true elseif name == 'content' and #ranges == 0 then - table.insert(ranges, node) + table.insert(ranges, get_node_range(node, id, metadata)) -- Ignore any tags that start with "_" -- Allows for other tags to be used in matches elseif string.sub(name, 1, 1) ~= '_' then @@ -360,7 +368,7 @@ function LanguageTree:_get_injections() end if #ranges == 0 then - table.insert(ranges, node) + table.insert(ranges, get_node_range(node, id, metadata)) end end end @@ -397,7 +405,10 @@ function LanguageTree:_get_injections() for _, entry in pairs(patterns) do if entry.combined then - table.insert(result[lang], vim.tbl_flatten(entry.regions)) + local regions = vim.tbl_map(function(e) + return vim.tbl_flatten(e) + end, entry.regions) + table.insert(result[lang], regions) else for _, ranges in ipairs(entry.regions) do table.insert(result[lang], ranges) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 3c4c8fdb96..0cc2b6d2a4 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -313,20 +313,22 @@ local directive_handlers = { ['set!'] = function(_, _, _, pred, metadata) if #pred == 4 then -- (#set! @capture "key" "value") - local capture = pred[2] - if not metadata[capture] then - metadata[capture] = {} + local _, capture_id, key, value = unpack(pred) + if not metadata[capture_id] then + metadata[capture_id] = {} end - metadata[capture][pred[3]] = pred[4] + metadata[capture_id][key] = value else + local _, key, value = unpack(pred) -- (#set! "key" "value") - metadata[pred[2]] = pred[3] + metadata[key] = value end end, -- Shifts the range of a node. -- Example: (#offset! @_node 0 1 0 -1) ['offset!'] = function(match, _, _, pred, metadata) - local offset_node = match[pred[2]] + local capture_id = pred[2] + local offset_node = match[capture_id] local range = { offset_node:range() } local start_row_offset = pred[3] or 0 local start_col_offset = pred[4] or 0 @@ -340,7 +342,10 @@ local directive_handlers = { -- If this produces an invalid range, we just skip it. if range[1] < range[3] or (range[1] == range[3] and range[2] <= range[4]) then - metadata.content = { range } + if not metadata[capture_id] then + metadata[capture_id] = {} + end + metadata[capture_id].range = range end end, } @@ -360,9 +365,14 @@ end --- Adds a new directive to be used in queries --- +--- Handlers can set match level data by setting directly on the +--- metadata object `metadata.key = value`, additionally, handlers +--- can set node level data by using the capture id on the +--- metadata table `metadata[capture_id].key = value` +--- ---@param name the name of the directive, without leading # ---@param handler the handler function to be used ---- signature will be (match, pattern, bufnr, predicate) +--- signature will be (match, pattern, bufnr, predicate, metadata) function M.add_directive(name, handler, force) if directive_handlers[name] and not force then error(string.format('Overriding %s', name)) @@ -371,6 +381,7 @@ function M.add_directive(name, handler, force) directive_handlers[name] = handler end +--- Lists the currently available directives to use in queries. ---@return The list of supported directives. function M.list_directives() return vim.tbl_keys(directive_handlers) diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index 8235949156..472b79cbf4 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -4,6 +4,8 @@ set -e set -u # Use privileged mode, which e.g. skips using CDPATH. set -p +# https://www.shellcheck.net/wiki/SC2031 +shopt -s lastpipe # Ensure that the user has a bash that supports -A if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then @@ -345,7 +347,7 @@ stage_patch() { See the wiki for more information: * https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim -' "${vim_version}" "${BASENAME}" "${BASENAME}" +' "${vim_version}" "${BASENAME}" "${BASENAME}" "${BASENAME}" return $ret } 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/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/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/legacy/fixeol_spec.lua b/test/functional/legacy/fixeol_spec.lua index d3ff86d349..3cc9d54e2b 100644 --- a/test/functional/legacy/fixeol_spec.lua +++ b/test/functional/legacy/fixeol_spec.lua @@ -6,12 +6,11 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers describe('fixeol', function() local function rmtestfiles() - feed_command('%bwipeout!') - feed_command('call delete("test.out")') - feed_command('call delete("XXEol")') - feed_command('call delete("XXNoEol")') - feed_command('call delete("XXTestEol")') - feed_command('call delete("XXTestNoEol")') + os.remove("test.out") + os.remove("XXEol") + os.remove("XXNoEol") + os.remove("XXTestEol") + os.remove("XXTestNoEol") end setup(function() clear() 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() |