diff options
-rw-r--r-- | .github/workflows/release.yml | 4 | ||||
-rw-r--r-- | contrib/flake.nix | 95 | ||||
-rw-r--r-- | runtime/doc/lsp.txt | 69 | ||||
-rw-r--r-- | runtime/filetype.vim | 3 | ||||
-rw-r--r-- | runtime/lua/vim/lsp.lua | 21 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 10 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 14 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 5 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/language.lua | 16 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/languagetree.lua | 31 | ||||
-rw-r--r-- | src/nvim/main.c | 5 | ||||
-rw-r--r-- | src/nvim/popupmnu.c | 1 | ||||
-rw-r--r-- | src/nvim/regexp.c | 16 | ||||
-rw-r--r-- | src/nvim/regexp_nfa.c | 16 | ||||
-rw-r--r-- | src/nvim/testdir/test_filetype.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_regexp_latin.vim | 7 | ||||
-rw-r--r-- | test/functional/lua/treesitter_spec.lua | 4 |
17 files changed, 268 insertions, 50 deletions
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2acd615da1..d7f9556028 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,9 +12,10 @@ on: tags: - v[0-9]+.[0-9]+.[0-9]+ +# Build on the oldest supported images, so we have broader compatibility jobs: linux: - runs-on: ubuntu-20.04 + runs-on: ubuntu-16.04 outputs: version: ${{ steps.build.outputs.version }} release: ${{ steps.build.outputs.release }} @@ -42,7 +43,6 @@ jobs: retention-days: 1 appimage: - # Build on the oldest supported image, so we have broader compatibility runs-on: ubuntu-16.04 steps: - uses: actions/checkout@v2 diff --git a/contrib/flake.nix b/contrib/flake.nix new file mode 100644 index 0000000000..a75e584075 --- /dev/null +++ b/contrib/flake.nix @@ -0,0 +1,95 @@ +{ + description = "Neovim flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + }; + + outputs = { self, nixpkgs }: let + system = "x86_64-linux"; + legacyPkgs = nixpkgs.legacyPackages."${system}".pkgs; + pkgs = legacyPkgs; + in { + + packages."${system}" = rec { + + neovim = legacyPkgs.neovim-unwrapped.overrideAttrs(oa: { + version = "master"; + src = ../.; + + buildInputs = oa.buildInputs ++ ([ + pkgs.tree-sitter + ]); + + cmakeFlags = oa.cmakeFlags ++ [ + "-DUSE_BUNDLED=OFF" + ]; + }); + + # a development binary to help debug issues + neovim-debug = (neovim.override { + stdenv = pkgs.llvmPackages_latest.stdenv; + lua = pkgs.enableDebugging legacyPkgs.luajit; + }).overrideAttrs(oa:{ + cmakeBuildType="Debug"; + cmakeFlags = oa.cmakeFlags ++ [ + "-DMIN_LOG_LEVEL=0" + ]; + }); + + # for neovim developers, very slow + # brings development tools as well + neovim-developer = let + lib = nixpkgs.lib; + pythonEnv = legacyPkgs.python3; + luacheck = legacyPkgs.luaPackages.luacheck; + in + neovim-debug.overrideAttrs(oa: { + cmakeFlags = oa.cmakeFlags ++ [ + "-DLUACHECK_PRG=${luacheck}/bin/luacheck" + "-DMIN_LOG_LEVEL=0" + "-DENABLE_LTO=OFF" + "-DUSE_BUNDLED=OFF" + # https://github.com/google/sanitizers/wiki/AddressSanitizerFlags + # https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports + "-DCLANG_ASAN_UBSAN=ON" + ]; + + nativeBuildInputs = oa.nativeBuildInputs ++ (with pkgs; [ + pythonEnv + include-what-you-use # for scripts/check-includes.py + jq # jq for scripts/vim-patch.sh -r + doxygen + ]); + + shellHook = oa.shellHook + '' + export NVIM_PYTHON_LOG_LEVEL=DEBUG + export NVIM_LOG_FILE=/tmp/nvim.log + + export ASAN_OPTIONS="log_path=./test.log:abort_on_error=1" + export UBSAN_OPTIONS=print_stacktrace=1 + ''; + }); + }; + + defaultPackage."${system}" = self.packages."${system}".neovim; + + overlay = final: prev: { + inherit (self.packages."${system}") neovim neovim-debug; + }; + + apps."${system}" = let + mkApp = pkg: { + type = "app"; + program = pkg + "/bin/nvim"; + }; + in { + nvim = mkApp self.packages."${system}".neovim; + nvim-debug = mkApp self.packages."${system}".neovim-debug; + }; + + defaultApp."${system}" = self.apps."${system}".nvim; + + devShell."${system}" = self.packages."${system}".neovim-developer; + }; +} diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index c8a44dfb75..ea9072841c 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -247,7 +247,7 @@ For |lsp-notification|, each |lsp-handler| has this signature: > of a particular handler. For an example, see: - |vim.lsp.diagnostics.on_publish_diagnostics()| + |vim.lsp.diagnostic.on_publish_diagnostics()| To configure a particular |lsp-handler|, see: |lsp-handler-configuration| @@ -715,6 +715,15 @@ start_client({config}) *vim.lsp.start_client()* The following parameters describe fields in the {config} table. +> + + -- In attach function for the client, you can do: + local custom_attach = function(client) + if client.config.flags then + client.config.flags.allow_incremental_sync = true + end + end +< Parameters: ~ {root_dir} (required, string) Directory where the @@ -796,6 +805,11 @@ start_client({config}) *vim.lsp.start_client()* in the initialize request. Invalid/empty values will default to "off" + {flags} A table with flags for the client. The + current (experimental) flags are: + • allow_incremental_sync (bool, default + false): Allow using on_line callbacks + for lsp Return: ~ Client id. |vim.lsp.get_client_by_id()| Note: client may @@ -833,6 +847,12 @@ with({handler}, {override_config}) *vim.lsp.with()* ============================================================================== Lua module: vim.lsp.buf *lsp-buf* + *vim.lsp.buf.add_workspace_folder()* +add_workspace_folder({workspace_folder}) + Add the folder at path to the workspace folders. If {path} is + not provided, the user will be prompted for a path using + |input()|. + clear_references() *vim.lsp.buf.clear_references()* Removes document highlights from current buffer. @@ -935,6 +955,9 @@ incoming_calls() *vim.lsp.buf.incoming_calls()* |quickfix| window. If the symbol can resolve to multiple items, the user can pick one in the |inputlist|. +list_workspace_folders() *vim.lsp.buf.list_workspace_folders()* + List workspace folders. + outgoing_calls() *vim.lsp.buf.outgoing_calls()* Lists all the items that are called by the symbol under the cursor in the |quickfix| window. If the symbol can resolve to @@ -961,6 +984,9 @@ range_formatting({options}, {start_pos}, {end_pos}) Parameters: ~ {options} Table with valid `FormattingOptions` entries. {start_pos} ({number, number}, optional) mark-indexed + position. Defaults to the start of the last + visual selection. + {end_pos} ({number, number}, optional) mark-indexed position. Defaults to the end of the last visual selection. @@ -974,6 +1000,12 @@ references({context}) *vim.lsp.buf.references()* See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references + *vim.lsp.buf.remove_workspace_folder()* +remove_workspace_folder({workspace_folder}) + Remove the folder at path from the workspace folders. If + {path} is not provided, the user will be prompted for a path + using |input()|. + rename({new_name}) *vim.lsp.buf.rename()* Renames all references to the symbol under the cursor. @@ -996,19 +1028,6 @@ type_definition() *vim.lsp.buf.type_definition()* Jumps to the definition of the type of the symbol under the cursor. -add_workspace_folder({path}) *vim.lsp.buf.add_workspace_folder()* - Add the folder at path to the workspace folders. If {path} is - not provided, the user will be prompted for a path using - |input()|. - -remove_workspace_folder({path}) *vim.lsp.buf.remove_workspace_folder()* - Remove the folder at path from the workspace folders. If - {path} is not provided, the user will be prompted for - a path using |input()|. - -list_workspace_folders() *vim.lsp.buf.list_workspace_folders()* - List all folders in the workspace. - workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()* Lists all symbols in the current workspace in the quickfix window. @@ -1062,9 +1081,9 @@ get_count({bufnr}, {severity}, {client_id}) let sl = '' if luaeval('not vim.tbl_isempty(vim.lsp.buf_get_clients(0))') let sl.='%#MyStatuslineLSP#E:' - let sl.='%#MyStatuslineLSPErrors#%{luaeval("vim.lsp.diagnostic.get_count(vim.fn.bufnr('%'), [[Error]])")}' + let sl.='%#MyStatuslineLSPErrors#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Error]])")}' let sl.='%#MyStatuslineLSP# W:' - let sl.='%#MyStatuslineLSPWarnings#%{luaeval("vim.lsp.diagnostic.get_count(vim.fn.bufnr('%'), [[Warning]])")}' + let sl.='%#MyStatuslineLSPWarnings#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Warning]])")}' else let sl.='%#MyStatuslineLSPErrors#off' endif @@ -1104,7 +1123,7 @@ get_next({opts}) *vim.lsp.diagnostic.get_next()* Get the previous diagnostic closest to the cursor_position Parameters: ~ - {opts} table See |vim.lsp.diagnostics.goto_next()| + {opts} table See |vim.lsp.diagnostic.goto_next()| Return: ~ table Next diagnostic @@ -1114,7 +1133,7 @@ get_next_pos({opts}) *vim.lsp.diagnostic.get_next_pos()* current buffer. Parameters: ~ - {opts} table See |vim.lsp.diagnostics.goto_next()| + {opts} table See |vim.lsp.diagnostic.goto_next()| Return: ~ table Next diagnostic position @@ -1123,7 +1142,7 @@ get_prev({opts}) *vim.lsp.diagnostic.get_prev()* Get the previous diagnostic closest to the cursor_position Parameters: ~ - {opts} table See |vim.lsp.diagnostics.goto_next()| + {opts} table See |vim.lsp.diagnostic.goto_next()| Return: ~ table Previous diagnostic @@ -1133,7 +1152,7 @@ get_prev_pos({opts}) *vim.lsp.diagnostic.get_prev_pos()* current buffer. Parameters: ~ - {opts} table See |vim.lsp.diagnostics.goto_next()| + {opts} table See |vim.lsp.diagnostic.goto_next()| Return: ~ table Previous diagnostic position @@ -1196,7 +1215,7 @@ goto_prev({opts}) *vim.lsp.diagnostic.goto_prev()* Move to the previous diagnostic Parameters: ~ - {opts} table See |vim.lsp.diagnostics.goto_next()| + {opts} table See |vim.lsp.diagnostic.goto_next()| *vim.lsp.diagnostic.on_publish_diagnostics()* on_publish_diagnostics({_}, {_}, {params}, {client_id}, {_}, {config}) @@ -1654,6 +1673,14 @@ make_text_document_params() *vim.lsp.util.make_text_document_params()* See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier + *vim.lsp.util.make_workspace_params()* +make_workspace_params({added}, {removed}) + Create the workspace params + + Parameters: ~ + {added} + {removed} + *vim.lsp.util.open_floating_preview()* open_floating_preview({contents}, {filetype}, {opts}) Shows contents in a floating window. diff --git a/runtime/filetype.vim b/runtime/filetype.vim index ed19fa1a43..ed3204c537 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1744,6 +1744,9 @@ au BufNewFile,BufRead *.tf,.tfrc,tfrc setf tf " tmux configuration au BufNewFile,BufRead {.,}tmux*.conf setf tmux +" TOML +au BufNewFile,BufRead *.toml setf toml + " TPP - Text Presentation Program au BufNewFile,BufReadPost *.tpp setf tpp diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index f082fe29f2..ed31572abb 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1,3 +1,5 @@ +local if_nil = vim.F.if_nil + local default_handlers = require 'vim.lsp.handlers' local log = require 'vim.lsp.log' local lsp_rpc = require 'vim.lsp.rpc' @@ -226,6 +228,7 @@ local function validate_client_config(config) on_init = { config.on_init, "f", true }; before_init = { config.before_init, "f", true }; offset_encoding = { config.offset_encoding, "s", true }; + flags = { config.flags, "t", true }; } -- TODO(remove-callbacks) @@ -434,6 +437,17 @@ end --- --@param trace: "off" | "messages" | "verbose" | nil passed directly to the language --- server in the initialize request. Invalid/empty values will default to "off" +--@param flags: A table with flags for the client. The current (experimental) flags are: +--- - allow_incremental_sync (bool, default false): Allow using on_line callbacks for lsp +--- +--- <pre> +--- -- In attach function for the client, you can do: +--- local custom_attach = function(client) +--- if client.config.flags then +--- client.config.flags.allow_incremental_sync = true +--- end +--- end +--- </pre> --- --@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be --- fully initialized. Use `on_init` to do any actions once @@ -442,6 +456,8 @@ function lsp.start_client(config) local cleaned_config = validate_client_config(config) local cmd, cmd_args, offset_encoding = cleaned_config.cmd, cleaned_config.cmd_args, cleaned_config.offset_encoding + config.flags = config.flags or {} + local client_id = next_client_id() -- TODO(remove-callbacks) @@ -799,6 +815,7 @@ do local size_index = encoding_index[client.offset_encoding] local length = select(size_index, old_byte_size, old_utf16_size, old_utf32_size) local lines = nvim_buf_get_lines(bufnr, firstline, new_lastline, true) + -- This is necessary because we are specifying the full line including the -- newline in range. Therefore, we must replace the newline as well. if #lines > 0 then @@ -820,6 +837,8 @@ do end) local uri = vim.uri_from_bufnr(bufnr) for_each_buffer_client(bufnr, function(client, _client_id) + local allow_incremental_sync = if_nil(client.config.flags.allow_incremental_sync, false) + local text_document_did_change = client.resolved_capabilities.text_document_did_change local changes if text_document_did_change == protocol.TextDocumentSyncKind.None then @@ -830,7 +849,7 @@ do -- is no way to specify the sync capability by the client. -- See https://github.com/palantir/python-language-server/commit/cfd6675bc10d5e8dbc50fc50f90e4a37b7178821#diff-f68667852a14e9f761f6ebf07ba02fc8 for an example of pyls handling both. --]=] - elseif true or text_document_did_change == protocol.TextDocumentSyncKind.Full then + elseif not allow_incremental_sync or text_document_did_change == protocol.TextDocumentSyncKind.Full then changes = full_changes(client) elseif text_document_did_change == protocol.TextDocumentSyncKind.Incremental then changes = incremental_changes(client) diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index a70581478b..00219b6d98 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -149,7 +149,7 @@ end --@param options Table with valid `FormattingOptions` entries. --@param start_pos ({number, number}, optional) mark-indexed position. ---Defaults to the start of the last visual selection. ---@param start_pos ({number, number}, optional) mark-indexed position. +--@param end_pos ({number, number}, optional) mark-indexed position. ---Defaults to the end of the last visual selection. function M.range_formatting(options, start_pos, end_pos) validate { options = {options, 't', true} } @@ -239,6 +239,7 @@ function M.outgoing_calls() end --- List workspace folders. +--- function M.list_workspace_folders() local workspace_folders = {} for _, client in ipairs(vim.lsp.buf_get_clients()) do @@ -249,7 +250,8 @@ function M.list_workspace_folders() return workspace_folders end ---- Add a workspace folder. +--- Add the folder at path to the workspace folders. If {path} is +--- not provided, the user will be prompted for a path using |input()|. function M.add_workspace_folder(workspace_folder) workspace_folder = workspace_folder or npcall(vfn.input, "Workspace Folder: ", vfn.expand('%:p:h')) vim.api.nvim_command("redraw") @@ -275,7 +277,9 @@ function M.add_workspace_folder(workspace_folder) end end ---- Remove a workspace folder. +--- Remove the folder at path from the workspace folders. If +--- {path} is not provided, the user will be prompted for +--- a path using |input()|. function M.remove_workspace_folder(workspace_folder) workspace_folder = workspace_folder or npcall(vfn.input, "Workspace Folder: ", vfn.expand('%:p:h')) vim.api.nvim_command("redraw") diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 27a1f53f89..efca5b53af 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -400,9 +400,9 @@ end --- let sl = '' --- if luaeval('not vim.tbl_isempty(vim.lsp.buf_get_clients(0))') --- let sl.='%#MyStatuslineLSP#E:' ---- let sl.='%#MyStatuslineLSPErrors#%{luaeval("vim.lsp.diagnostic.get_count([[Error]])")}' +--- let sl.='%#MyStatuslineLSPErrors#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Error]])")}' --- let sl.='%#MyStatuslineLSP# W:' ---- let sl.='%#MyStatuslineLSPWarnings#%{luaeval("vim.lsp.diagnostic.get_count([[Warning]])")}' +--- let sl.='%#MyStatuslineLSPWarnings#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Warning]])")}' --- else --- let sl.='%#MyStatuslineLSPErrors#off' --- endif @@ -510,7 +510,7 @@ end --- Get the previous diagnostic closest to the cursor_position --- ----@param opts table See |vim.lsp.diagnostics.goto_next()| +---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic function M.get_prev(opts) opts = opts or {} @@ -523,7 +523,7 @@ function M.get_prev(opts) end --- Return the pos, {row, col}, for the prev diagnostic in the current buffer. ----@param opts table See |vim.lsp.diagnostics.goto_next()| +---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic position function M.get_prev_pos(opts) return _iter_diagnostic_lines_pos( @@ -533,7 +533,7 @@ function M.get_prev_pos(opts) end --- Move to the previous diagnostic ----@param opts table See |vim.lsp.diagnostics.goto_next()| +---@param opts table See |vim.lsp.diagnostic.goto_next()| function M.goto_prev(opts) return _iter_diagnostic_move_pos( "DiagnosticPrevious", @@ -543,7 +543,7 @@ function M.goto_prev(opts) end --- Get the previous diagnostic closest to the cursor_position ----@param opts table See |vim.lsp.diagnostics.goto_next()| +---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic function M.get_next(opts) opts = opts or {} @@ -556,7 +556,7 @@ function M.get_next(opts) end --- Return the pos, {row, col}, for the next diagnostic in the current buffer. ----@param opts table See |vim.lsp.diagnostics.goto_next()| +---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic position function M.get_next_pos(opts) return _iter_diagnostic_lines_pos( diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 5804ac6656..3da4dd6219 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1022,7 +1022,7 @@ do --@deprecated function M.buf_diagnostics_signs(bufnr, diagnostics, client_id) - warn_once("buf_diagnostics_signs is deprecated. Use 'vim.lsp.diagnostics.set_signs'") + warn_once("buf_diagnostics_signs is deprecated. Use 'vim.lsp.diagnostic.set_signs'") return vim.lsp.diagnostic.set_signs(diagnostics, bufnr, client_id) end @@ -1315,6 +1315,9 @@ function M.make_text_document_params() return { uri = vim.uri_from_bufnr(0) } end +--- Create the workspace params +--@param added +--@param removed function M.make_workspace_params(added, removed) return { event = { added = added; removed = removed; } } end diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index a7e36a0b89..d60cd2d0c7 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -8,7 +8,8 @@ local M = {} -- -- @param lang The language the parser should parse -- @param path Optionnal path the parser is located at -function M.require_language(lang, path) +-- @param silent Don't throw an error if language not found +function M.require_language(lang, path, silent) if vim._ts_has_language(lang) then return true end @@ -16,12 +17,23 @@ function M.require_language(lang, path) local fname = 'parser/' .. lang .. '.*' local paths = a.nvim_get_runtime_file(fname, false) if #paths == 0 then + if silent then + return false + end + -- TODO(bfredl): help tag? error("no parser for '"..lang.."' language, see :help treesitter-parsers") end path = paths[1] end - vim._ts_add_language(path, lang) + + if silent then + return pcall(function() vim._ts_add_language(path, lang) end) + else + vim._ts_add_language(path, lang) + end + + return true end --- Inspects the provided language. diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 885460c9fd..04b5fee256 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -121,23 +121,30 @@ function LanguageTree:parse() local seen_langs = {} for lang, injection_ranges in pairs(injections_by_lang) do - local child = self._children[lang] + local has_lang = language.require_language(lang, nil, true) - if not child then - child = self:add_child(lang) - end + -- Child language trees should just be ignored if not found, since + -- they can depend on the text of a node. Intermediate strings + -- would cause errors for unknown parsers. + if has_lang then + local child = self._children[lang] - child:set_included_regions(injection_ranges) + if not child then + child = self:add_child(lang) + end - local _, child_changes = child:parse() + child:set_included_regions(injection_ranges) - -- Propagate any child changes so they are included in the - -- the change list for the callback. - if child_changes then - vim.list_extend(changes, child_changes) - end + local _, child_changes = child:parse() - seen_langs[lang] = true + -- Propagate any child changes so they are included in the + -- the change list for the callback. + if child_changes then + vim.list_extend(changes, child_changes) + end + + seen_langs[lang] = true + end end for lang, _ in pairs(self._children) do diff --git a/src/nvim/main.c b/src/nvim/main.c index 79c165419e..025312a6e1 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1414,7 +1414,10 @@ static void read_stdin(void) no_wait_return = true; int save_msg_didany = msg_didany; set_buflisted(true); - (void)open_buffer(true, NULL, 0); // create memfile and read file + + // Create memfile and read from stdin. + (void)open_buffer(true, NULL, 0); + if (BUFEMPTY() && curbuf->b_next != NULL) { // stdin was empty, go to buffer 2 (e.g. "echo file1 | xargs nvim"). #8561 do_cmdline_cmd("silent! bnext"); diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index f242b7d71a..551a650045 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -742,6 +742,7 @@ static int pum_set_selected(int n, int repeat) // Edit a new, empty buffer. Set options for a "wipeout" // buffer. set_option_value("swf", 0L, NULL, OPT_LOCAL); + set_option_value("bl", 0L, NULL, OPT_LOCAL); set_option_value("bt", 0L, "nofile", OPT_LOCAL); set_option_value("bh", 0L, "wipe", OPT_LOCAL); set_option_value("diff", 0L, NULL, OPT_LOCAL); diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 1c88bd4ba4..2878e73573 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -3605,6 +3605,22 @@ theend: if (backpos.ga_maxlen > BACKPOS_INITIAL) ga_clear(&backpos); + // Make sure the end is never before the start. Can happen when \zs and + // \ze are used. + if (REG_MULTI) { + const lpos_T *const start = &rex.reg_mmatch->startpos[0]; + const lpos_T *const end = &rex.reg_mmatch->endpos[0]; + + if (end->lnum < start->lnum + || (end->lnum == start->lnum && end->col < start->col)) { + rex.reg_mmatch->endpos[0] = rex.reg_mmatch->startpos[0]; + } + } else { + if (rex.reg_match->endp[0] < rex.reg_match->startp[0]) { + rex.reg_match->endp[0] = rex.reg_match->startp[0]; + } + } + return retval; } diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 7dfd16fb4f..137b2304c0 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -6591,6 +6591,22 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, #endif theend: + // Make sure the end is never before the start. Can happen when \zs and + // \ze are used. + if (REG_MULTI) { + const lpos_T *const start = &rex.reg_mmatch->startpos[0]; + const lpos_T *const end = &rex.reg_mmatch->endpos[0]; + + if (end->lnum < start->lnum + || (end->lnum == start->lnum && end->col < start->col)) { + rex.reg_mmatch->endpos[0] = rex.reg_mmatch->startpos[0]; + } + } else { + if (rex.reg_match->endp[0] < rex.reg_match->startp[0]) { + rex.reg_match->endp[0] = rex.reg_match->startp[0]; + } + } + return retval; } diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index f3c3e085f6..356a7ce135 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -463,6 +463,7 @@ let s:filename_checks = { \ 'tilde': ['file.t.html'], \ 'tli': ['file.tli'], \ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf'], + \ 'toml': ['file.toml'], \ 'tpp': ['file.tpp'], \ 'treetop': ['file.treetop'], \ 'trustees': ['trustees.conf'], diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim index 2ee0ee1c0c..1bb2ee53de 100644 --- a/src/nvim/testdir/test_regexp_latin.vim +++ b/src/nvim/testdir/test_regexp_latin.vim @@ -755,6 +755,13 @@ func Test_start_end_of_buffer_match() bwipe! endfunc +func Test_ze_before_zs() + call assert_equal('', matchstr(' ', '\%#=1\ze \zs')) + call assert_equal('', matchstr(' ', '\%#=2\ze \zs')) + call assert_equal(repeat([''], 10), matchlist(' ', '\%#=1\ze \zs')) + call assert_equal(repeat([''], 10), matchlist(' ', '\%#=2\ze \zs')) +endfunc + " Check for detecting error func Test_regexp_error() set regexpengine=2 diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua index 0e823426ae..f34cbbb65b 100644 --- a/test/functional/lua/treesitter_spec.lua +++ b/test/functional/lua/treesitter_spec.lua @@ -22,6 +22,10 @@ describe('treesitter API', function() matches("Error executing lua: Failed to load parser: uv_dlopen: .+", pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')")) + -- Should not throw an error when silent + eq(false, exec_lua("return vim.treesitter.require_language('borklang', nil, true)")) + eq(false, exec_lua("return vim.treesitter.require_language('borklang', 'borkbork.so', true)")) + eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) end) |