diff options
130 files changed, 5061 insertions, 2860 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3653f04d5d..44a911b21b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,10 +56,12 @@ jobs: - name: Install brew packages if: matrix.os == 'osx' run: | + # Workaround brew issues rm -f /usr/local/bin/2to3 + brew unlink gcc@8 gcc@9 brew update >/dev/null - brew install automake ccache cpanminus ninja brew upgrade + brew install automake ccache perl cpanminus ninja - name: Setup interpreter packages run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7587f62e59..753142e555 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: - name: Build release id: build run: | - make CMAKE_BUILD_TYPE=RelWithDebinfo CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH=" + make CMAKE_BUILD_TYPE=RelWithDebInfo CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH=" printf '::set-output name=version::%s\n' "$(./build/bin/nvim --version | head -n 3 | sed -z 's/\n/%0A/g')" printf '::set-output name=release::%s\n' "$(./build/bin/nvim --version | head -n 1)" make DESTDIR="$GITHUB_WORKSPACE/build/release/nvim-linux64" install @@ -76,7 +76,9 @@ jobs: - name: Install brew packages run: | rm -f /usr/local/bin/2to3 + brew unlink gcc@8 gcc@9 brew update >/dev/null + brew upgrade brew install automake ninja - name: Build release run: | @@ -154,7 +156,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - delete_release: false + delete_release: '' tag_name: nightly - uses: meeDamian/github-release@2.0 with: @@ -46,7 +46,7 @@ Install from package Pre-built packages for Windows, macOS, and Linux are found on the [Releases](https://github.com/neovim/neovim/releases/) page. -[Managed packages] are in Homebrew, [Debian], [Ubuntu], [Fedora], [Arch Linux], +[Managed packages] are in [Homebrew], [Debian], [Ubuntu], [Fedora], [Arch Linux], [Gentoo], and more! Install from source @@ -137,5 +137,6 @@ Apache 2.0 license, except for contributions copied from Vim (identified by the [Fedora]: https://apps.fedoraproject.org/packages/neovim [Arch Linux]: https://www.archlinux.org/packages/?q=neovim [Gentoo]: https://packages.gentoo.org/packages/app-editors/neovim +[Homebrew]: https://formulae.brew.sh/formula/neovim <!-- vim: set tw=80: --> diff --git a/contrib/flake.nix b/contrib/flake.nix index 86e4b37cfa..d18534215c 100644 --- a/contrib/flake.nix +++ b/contrib/flake.nix @@ -3,93 +3,100 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; }; - 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; + outputs = { self, nixpkgs, flake-utils }: + { + overlay = final: prev: + let + pkgs = nixpkgs.legacyPackages.${prev.system}; + in + rec { + neovim = pkgs.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 = if pkgs.stdenv.isLinux then pkgs.llvmPackages_latest.stdenv else pkgs.stdenv; + lua = pkgs.enableDebugging pkgs.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 = pkgs.python3; + luacheck = pkgs.luaPackages.luacheck; + in + (neovim-debug.override ({ doCheck = pkgs.stdenv.isLinux; })).overrideAttrs (oa: { + cmakeFlags = oa.cmakeFlags ++ [ + "-DLUACHECK_PRG=${luacheck}/bin/luacheck" + "-DMIN_LOG_LEVEL=0" + "-DENABLE_LTO=OFF" + "-DUSE_BUNDLED=OFF" + ] ++ pkgs.stdenv.lib.optionals pkgs.stdenv.isLinux [ + # 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 + ''; + }); + }; + } // + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + overlays = [ self.overlay ]; + inherit system; + }; in - (neovim-debug.override({doCheck = true;})).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 + rec { - export ASAN_OPTIONS="log_path=./test.log:abort_on_error=1" - export UBSAN_OPTIONS=print_stacktrace=1 - ''; - }); - }; + packages = with pkgs; { + inherit neovim neovim-debug neovim-developer; + }; - defaultPackage."${system}" = self.packages."${system}".neovim; + defaultPackage = pkgs.neovim; - overlay = final: prev: { - inherit (self.packages."${system}") neovim neovim-debug; - }; + apps = { + nvim = flake-utils.lib.mkApp { drv = pkgs.neovim; name = "nvim"; }; + nvim-debug = flake-utils.lib.mkApp { drv = pkgs.neovim-debug; name = "nvim"; }; + }; - 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 = apps.nvim; - defaultApp."${system}" = self.apps."${system}".nvim; - - devShell."${system}" = self.packages."${system}".neovim-developer; - }; + devShell = pkgs.neovim-developer; + } + ); } diff --git a/man/nvim.1 b/man/nvim.1 index 305551c7d4..ca0f41d489 100644 --- a/man/nvim.1 +++ b/man/nvim.1 @@ -327,7 +327,7 @@ Print version information and exit. .Sh ENVIRONMENT .Bl -tag -width Fl .It Ev NVIM_LOG_FILE -Low-level log file, usually found at ~/.local/share/nvim/log. +Low-level log file, usually found at ~/.cache/nvim/log. :help $NVIM_LOG_FILE .It Ev VIM Used to locate user files, such as init.vim. diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index b6297472c3..cf26bc3172 100644 --- a/runtime/autoload/dist/ft.vim +++ b/runtime/autoload/dist/ft.vim @@ -362,6 +362,10 @@ func dist#ft#FTinc() setf aspvbs elseif lines =~ "<?" setf php + " Pascal supports // comments but they're vary rarely used for file + " headers so assume POV-Ray + elseif lines =~ '^\s*\%({\|(\*\)' || lines =~? s:ft_pascal_keywords + setf pascal else call dist#ft#FTasmsyntax() if exists("b:asmsyntax") @@ -408,6 +412,9 @@ func dist#ft#FTprogress_asm() setf progress endfunc +let s:ft_pascal_comments = '^\s*\%({\|(\*\|//\)' +let s:ft_pascal_keywords = '^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>' + func dist#ft#FTprogress_pascal() if exists("g:filetype_p") exe "setf " . g:filetype_p @@ -419,8 +426,7 @@ func dist#ft#FTprogress_pascal() let lnum = 1 while lnum <= 10 && lnum < line('$') let line = getline(lnum) - if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>' - \ || line =~ '^\s*{' || line =~ '^\s*(\*' + if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords setf pascal return elseif line !~ '^\s*$' || line =~ '^/\*' @@ -433,6 +439,19 @@ func dist#ft#FTprogress_pascal() setf progress endfunc +func dist#ft#FTpp() + if exists("g:filetype_pp") + exe "setf " . g:filetype_pp + else + let line = getline(nextnonblank(1)) + if line =~ s:ft_pascal_comments || line =~? s:ft_pascal_keywords + setf pascal + else + setf puppet + endif + endif +endfunc + func dist#ft#FTr() let max = line("$") > 50 ? 50 : line("$") diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim index 99d8c41dba..78a86315a3 100644 --- a/runtime/autoload/man.vim +++ b/runtime/autoload/man.vim @@ -137,8 +137,6 @@ function! s:put_page(page) abort setlocal modifiable setlocal noreadonly setlocal noswapfile - " git-ls-files(1) is all one keyword/tag-target - setlocal iskeyword+=(,) silent keepjumps %delete _ silent put =a:page while getline(1) =~# '^\s*$' diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 485c93b0dd..a810bef8f6 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -663,6 +663,17 @@ nvim_del_var({name}) *nvim_del_var()* Parameters: ~ {name} Variable name +nvim_echo({chunks}, {history}, {opts}) *nvim_echo()* + Echo a message. + + Parameters: ~ + {chunks} A list of [text, hl_group] arrays, each + representing a text chunk with specified + highlight. `hl_group` element can be omitted + for no highlight. + {history} if true, add to |message-history|. + {opts} Optional parameters. Reserved for future use. + nvim_err_write({str}) *nvim_err_write()* Writes a message to the Vim error buffer. Does not append "\n", the message is buffered (won't display) until a linefeed diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index d04f52de0b..384bdd63a4 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1600,7 +1600,7 @@ v:event Dictionary of event data for the current |autocommand|. Valid regtype Type of register as returned by |getregtype()|. visual Selection is visual (as opposed to, - e.g., via motion). + e.g., via motion). completed_item Current selected complete item on |CompleteChanged|, Is `{}` when no complete item selected. @@ -1783,7 +1783,7 @@ v:msgpack_types Dictionary containing msgpack types used by |msgpackparse()| of msgpack types, use |is| operator. *v:null* *null-variable* -v:null Special value used to put "null" in JSON and NIL in msgpack. +v:null Special value used to put "null" in JSON and NIL in msgpack. See |json_encode()|. This value is converted to "v:null" when used as a String (e.g. in |expr5| with string concatenation operator) and to zero when used as a Number (e.g. in |expr5| @@ -2184,6 +2184,7 @@ getjumplist([{winnr} [, {tabnr}]]) getline({lnum}) String line {lnum} of current buffer getline({lnum}, {end}) List lines {lnum} to {end} of current buffer getloclist({nr} [, {what}]) List list of location list items +getmarklist([{expr}]) List list of global/local marks getmatches([{win}]) List list of current matches getpid() Number process ID of Vim getpos({expr}) List position of cursor, mark, etc. @@ -4149,7 +4150,7 @@ function({name} [, {arglist}] [, {dict}]) garbagecollect([{atexit}]) *garbagecollect()* Cleanup unused |Lists| and |Dictionaries| that have circular references. - + There is hardly ever a need to invoke this function, as it is automatically done when Vim runs out of memory or is waiting for the user to press a key after 'updatetime'. Items without @@ -4649,6 +4650,24 @@ getloclist({nr},[, {what}]) *getloclist()* field is applicable only when called from a location list window. See |location-list-file-window| for more details. +getmarklist([{expr}] *getmarklist()* + Without the {expr} argument returns a |List| with information + about all the global marks. |mark| + + If the optional {expr} argument is specified, returns the + local marks defined in buffer {expr}. For the use of {expr}, + see |bufname()|. + + Each item in the retuned List is a |Dict| with the following: + name - name of the mark prefixed by "'" + pos - a |List| with the position of the mark: + [bufnum, lnum, col, off] + Refer to |getpos()| for more information. + file - file name + + Refer to |getpos()| for getting information about a specific + mark. + getmatches([{win}]) *getmatches()* Returns a |List| with all matches previously defined for the current window by |matchadd()| and the |:match| commands. @@ -4915,7 +4934,7 @@ getwininfo([{winid}]) *getwininfo()* quickfix 1 if quickfix or location list window terminal 1 if a terminal window tabnr tab page number - topline first displayed buffer line + topline first displayed buffer line variables a reference to the dictionary with window-local variables width window width @@ -5055,7 +5074,7 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The Vim's compile-time feature-names (prefixed with "+") are not recognized because Nvim is always compiled with all possible - features. |feature-compile| + features. |feature-compile| Feature names can be: 1. Nvim version. For example the "nvim-0.2.1" feature means @@ -5080,7 +5099,7 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The ttyin input is a terminal (tty) ttyout output is a terminal (tty) unix Unix system. - *vim_starting* True during |startup|. + *vim_starting* True during |startup|. win32 Windows system (32 or 64 bit). win64 Windows system (64 bit). wsl WSL (Windows Subsystem for Linux) system @@ -5665,7 +5684,7 @@ json_encode({expr}) *json_encode()* |msgpack-special-dict|), values with self-referencing containers, strings which contain non-UTF-8 characters, pseudo-UTF-8 strings which contain codepoints reserved for - surrogate pairs (such strings are not valid UTF-8 strings). + surrogate pairs (such strings are not valid UTF-8 strings). Non-printable characters are converted into "\u1234" escapes or special escapes like "\t", other are dumped as-is. @@ -5828,7 +5847,7 @@ map({expr1}, {expr2}) *map()* {expr1} must be a |List| or a |Dictionary|. Replace each item in {expr1} with the result of evaluating {expr2}. {expr2} must be a |string| or |Funcref|. - + If {expr2} is a |string|, inside {expr2} |v:val| has the value of the current item. For a |Dictionary| |v:key| has the key of the current item and for a |List| |v:key| has the index of @@ -6095,8 +6114,8 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]]) - A list with three numbers, e.g., [23, 11, 3]. As above, but the third number gives the length of the highlight in bytes. - Entries with zero and negative line numbers are silently - ignored, as well as entries with negative column numbers and + Entries with zero and negative line numbers are silently + ignored, as well as entries with negative column numbers and lengths. The maximum number of positions is 8. @@ -7589,7 +7608,7 @@ setpos({expr}, {list}) setqflist({list} [, {action}[, {what}]]) *setqflist()* Create or replace or add to the quickfix list. - + When {what} is not present, use the items in {list}. Each item must be a dictionary. Non-dictionary items in {list} are ignored. Each dictionary item can contain the following @@ -7630,12 +7649,12 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()* 'a' The items from {list} are added to the existing quickfix list. If there is no existing list, then a new list is created. - + 'r' The items from the current quickfix list are replaced with the items from {list}. This can also be used to clear the list: > :call setqflist([], 'r') -< +< 'f' All the quickfix lists in the quickfix stack are freed. @@ -8004,7 +8023,7 @@ sign_place({id}, {group}, {name}, {expr} [, {dict}]) empty string. {group} functions as a namespace for {id}, thus two groups can use the same IDs. Refer to |sign-identifier| for more information. - + {name} refers to a defined sign. {expr} refers to a buffer name or number. For the accepted values, see |bufname()|. @@ -8784,7 +8803,7 @@ system({cmd} [, {input}]) *system()* *E677* Note: Use |shellescape()| or |::S| with |expand()| or |fnamemodify()| to escape special characters in a command - argument. Newlines in {cmd} may cause the command to fail. + argument. Newlines in {cmd} may cause the command to fail. The characters in 'shellquote' and 'shellxquote' may also cause trouble. diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index afcacad460..172821ac28 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1173,9 +1173,11 @@ tag command action ~ |:caddbuffer| :cad[dbuffer] add errors from buffer |:caddexpr| :cadde[xpr] add errors from expr |:caddfile| :caddf[ile] add error message to current quickfix list +|:cafter| :caf[ter] go to error after current cursor |:call| :cal[l] call a function |:catch| :cat[ch] part of a :try command -|:cbelow| :cbe[low] go to error below current line +|:cbefore| :cbef[ore] go to error before current cursor +|:cbelow| :cbel[ow] go to error below current line |:cbottom| :cbo[ttom] scroll to the bottom of the quickfix window |:cbuffer| :cb[uffer] parse error messages and jump to first error |:cc| :cc go to specific error @@ -1336,10 +1338,12 @@ tag command action ~ |:laddexpr| :lad[dexpr] add locations from expr |:laddbuffer| :laddb[uffer] add locations from buffer |:laddfile| :laddf[ile] add locations to current location list +|:lafter| :laf[ter] go to location after current cursor |:last| :la[st] go to the last file in the argument list |:language| :lan[guage] set the language (locale) |:later| :lat[er] go to newer change, redo -|:lbelow| :lbe[low] go to location below current line +|:lbefore| :lbef[ore] go to location before current cursor +|:lbelow| :lbel[ow] go to location below current line |:lbottom| :lbo[ttom] scroll to the bottom of the location window |:lbuffer| :lb[uffer] parse locations and jump to first location |:lcd| :lc[d] change directory locally @@ -1539,6 +1543,8 @@ tag command action ~ |:sign| :sig[n] manipulate signs |:silent| :sil[ent] run a command silently |:sleep| :sl[eep] do nothing for a few seconds +|:sleep!| :sl[eep]! do nothing for a few seconds, without the + cursor visible |:slast| :sla[st] split window and go to last file in the argument list |:smagic| :sm[agic] :substitute with 'magic' diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 8e93b188e9..772afdcc1a 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -27,9 +27,9 @@ Follow these steps to get LSP features: 1. Install the nvim-lspconfig plugin. It provides common configuration for various servers so you can get started quickly. https://github.com/neovim/nvim-lspconfig - 2. Install a language server. Try ":LspInstall <tab>" or use your system - package manager to install the relevant language server: + 2. Install a language server. A list of language servers can be found here: https://microsoft.github.io/language-server-protocol/implementors/servers/ + See individual server documentation for installation instructions. 3. Add `lua require('lspconfig').xx.setup{…}` to your init.vim, where "xx" is the name of the relevant config. See the nvim-lspconfig README for details. NOTE: Make sure to restart nvim after installing and configuring. @@ -62,20 +62,39 @@ Example config (in init.vim): > vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.vim.lsp.omnifunc') -- For plugins with an `on_attach` callback, call them here. For example: - -- require('completion').on_attach(client) + -- require('completion').on_attach() end -- An example of configuring for `sumneko_lua`, -- a language server for Lua. - -- First, you must run `:LspInstall sumneko_lua` for this to work. + + -- set the path to the sumneko installation + local system_name = "Linux" -- (Linux, macOS, or Windows) + local sumneko_root_path = '/path/to/lua-language-server' + local sumneko_binary = sumneko_root_path.."/bin/"..system_name.."/lua-language-server" + require('lspconfig').sumneko_lua.setup({ + cmd = {sumneko_binary, "-E", sumneko_root_path .. "/main.lua"}; -- An example of settings for an LSP server. -- For more options, see nvim-lspconfig settings = { Lua = { + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT', + -- Setup your lua path + path = vim.split(package.path, ';'), + }, diagnostics = { - enable = true, - globals = { "vim" }, + -- Get the language server to recognize the `vim` global + globals = {'vim'}, + }, + workspace = { + -- Make the server aware of Neovim runtime files + library = { + [vim.fn.expand('$VIMRUNTIME/lua')] = true, + [vim.fn.expand('$VIMRUNTIME/lua/vim/lsp')] = true, + }, }, } }, @@ -176,6 +195,7 @@ specification. These LSP requests/notifications are defined by default: textDocument/typeDefinition* window/logMessage window/showMessage + window/showMessageRequest workspace/applyEdit workspace/symbol @@ -619,8 +639,9 @@ client() *vim.lsp.client* automatically escalate and force shutdown. • is_stopped() Checks whether a client is stopped. Returns: true if the client is fully stopped. - • on_attach(bufnr) Runs the on_attach function from the - client's config if it was defined. + • on_attach(client, bufnr) Runs the on_attach function from + the client's config if it was defined. Useful for + buffer-local setup. • Members • {id} (number): The id allocated to the client. @@ -755,6 +776,11 @@ start_client({config}) *vim.lsp.start_client()* array. {handlers} Map of language server method names to |lsp-handler| + {settings} Map with language server specific + settings. These are returned to the + language server if requested via + `workspace/configuration` . Keys are + case-sensitive. {init_options} Values to pass in the initialization request as `initializationOptions` . See `initialize` in the LSP spec. @@ -791,7 +817,14 @@ start_client({config}) *vim.lsp.start_client()* `capabilities.offsetEncoding` was sent to it. You can only modify the `client.offset_encoding` here before - any notifications are sent. + any notifications are sent. Most + language servers expect to be sent + client specified settings after + initialization. Neovim does not make + this assumption. A + `workspace/didChangeConfiguration` + notification should be sent to the + server during on_init. {on_exit} Callback (code, signal, client_id) invoked on client exit. • code: exit code of the process @@ -1318,6 +1351,10 @@ set_signs({diagnostics}, {bufnr}, {client_id}, {sign_ns}, {opts}) {sign_ns} number|nil {opts} table Configuration for signs. Keys: • priority: Set the priority of the signs. + • severity_limit (DiagnosticSeverity): + • Limit severity of diagnostics found. + E.g. "Warning" means { "Error", + "Warning" } will be valid. *vim.lsp.diagnostic.set_underline()* set_underline({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts}) @@ -1335,10 +1372,14 @@ set_underline({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts}) Parameters: ~ {diagnostics} Diagnostic [] - {bufnr} number The buffer number - {client_id} number the client id - {diagnostic_ns} number|nil - {opts} table Currently unused. + {bufnr} number: The buffer number + {client_id} number: The client id + {diagnostic_ns} number|nil: The namespace + {opts} table: Configuration table: + • severity_limit (DiagnosticSeverity): + • Limit severity of diagnostics found. + E.g. "Warning" means { "Error", + "Warning" } will be valid. *vim.lsp.diagnostic.set_virtual_text()* set_virtual_text({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts}) @@ -1365,6 +1406,10 @@ set_virtual_text({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts}) before virtual text on line • spacing (number): Number of spaces to insert before virtual text + • severity_limit (DiagnosticSeverity): + • Limit severity of diagnostics found. + E.g. "Warning" means { "Error", + "Warning" } will be valid. *vim.lsp.diagnostic.show_line_diagnostics()* show_line_diagnostics({opts}, {bufnr}, {line_nr}, {client_id}) @@ -1388,16 +1433,31 @@ show_line_diagnostics({opts}, {bufnr}, {line_nr}, {client_id}) {client_id} number|nil the client id Return: ~ - {popup_bufnr, win_id} + table {popup_bufnr, win_id} + + +============================================================================== +Lua module: vim.lsp.handlers *lsp-handlers* + + *vim.lsp.handlers.progress_callback()* +progress_callback({_}, {_}, {params}, {client_id}) + See also: ~ + https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand ============================================================================== Lua module: vim.lsp.util *lsp-util* *vim.lsp.util.apply_text_document_edit()* -apply_text_document_edit({text_document_edit}) +apply_text_document_edit({text_document_edit}, {index}) + Applies a `TextDocumentEdit` , which is a list of changes to a + single document. + Parameters: ~ - {text_document_edit} (table) a `TextDocumentEdit` object + {text_document_edit} table: a `TextDocumentEdit` object + {index} number: Optional index of the edit, + if from a list of edits (or nil, if + not from a list) See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit @@ -1577,6 +1637,9 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()* See also: ~ |softtabstop| +get_progress_messages() *vim.lsp.util.get_progress_messages()* + TODO: Documentation + jump_to_location({location}) *vim.lsp.util.jump_to_location()* Jumps to a location. @@ -1598,6 +1661,19 @@ locations_to_items({locations}) *vim.lsp.util.locations_to_items()* Return: ~ (table) list of items +lookup_section({settings}, {section}) *vim.lsp.util.lookup_section()* + Helper function to return nested values in language server + settings + + Parameters: ~ + {settings} a table of language server settings + {section} a string indicating the field of the settings + table + + Return: ~ + (table or string) The value of settings accessed via + section + *vim.lsp.util.make_floating_popup_options()* make_floating_popup_options({width}, {height}, {opts}) Creates a table with sensible default options for a floating @@ -1678,7 +1754,7 @@ make_workspace_params({added}, {removed}) Create the workspace params Parameters: ~ - {added} + {added} {removed} *vim.lsp.util.open_floating_preview()* diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index a03de10a17..0bbed56662 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -622,6 +622,9 @@ vim.api.{func}({...}) *vim.api* Example: call the "nvim_get_current_line()" API function: > print(tostring(vim.api.nvim_get_current_line())) +vim.version() *vim.version* + Returns the version of the current neovim build. + vim.in_fast_event() *vim.in_fast_event()* Returns true if the code is executing as part of a "fast" event handler, where most of the API is disabled. These are low-level events @@ -1262,14 +1265,12 @@ validate({opt}) *vim.validate()* vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}} => NOP (success) -< -> - vim.validate{arg1={1, 'table'}} - => error('arg1: expected table, got number') -< -> - vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}} - => error('arg1: expected even number, got 3') + + vim.validate{arg1={1, 'table'}} + => error('arg1: expected table, got number') + + vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}} + => error('arg1: expected even number, got 3') < Parameters: ~ diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index e740a45bec..2a757bbed9 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -734,6 +734,8 @@ A jump table for the options with a short description can be found at |Q_op|. eol allow backspacing over line breaks (join lines) start allow backspacing over the start of insert; CTRL-W and CTRL-U stop once at the start of insert. + nostop like start, except CTRL-W and CTRL-U do not stop at the start of + insert. When the value is empty, Vi compatible backspacing is used. @@ -742,6 +744,7 @@ A jump table for the options with a short description can be found at |Q_op|. 0 same as ":set backspace=" (Vi compatible) 1 same as ":set backspace=indent,eol" 2 same as ":set backspace=indent,eol,start" + 3 same as ":set backspace=indent,eol,nostop" *'backup'* *'bk'* *'nobackup'* *'nobk'* 'backup' 'bk' boolean (default off) @@ -2609,7 +2612,7 @@ A jump table for the options with a short description can be found at |Q_op|. when internal formatting is used. Make sure the cursor is kept in the same spot relative to the text then! The |mode()| function will return "i" or "R" in this situation. - + When the expression evaluates to non-zero Vim will fall back to using the internal format mechanism. @@ -3184,7 +3187,7 @@ A jump table for the options with a short description can be found at |Q_op|. *'inccommand'* *'icm'* 'inccommand' 'icm' string (default "") global - + "nosplit": Shows the effects of a command incrementally, as you type. "split" : Also shows partial off-screen results in a preview window. @@ -6838,7 +6841,7 @@ A jump table for the options with a short description can be found at |Q_op|. a built-in |highlight-groups| item to be overridden by {hl} group in the window. Only built-in |highlight-groups| are supported, not syntax highlighting (use |:ownsyntax| for that). - + Highlights of vertical separators are determined by the window to the left of the separator. The 'tabline' highlight of a tabpage is decided by the last-focused window of the tabpage. Highlights of diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index d6ff3ea9ea..fab3b11430 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -74,7 +74,7 @@ processing a quickfix or location list command, it will be aborted. *:cc* :cc[!] [nr] Display error [nr]. If [nr] is omitted, the same - error is displayed again. Without [!] this doesn't +:[nr]cc[!] error is displayed again. Without [!] this doesn't work when jumping to another buffer, the current buffer has been changed, there is the only window for the buffer and both 'hidden' and 'autowrite' are off. @@ -83,10 +83,13 @@ processing a quickfix or location list command, it will be aborted. there is another window for this buffer. The 'switchbuf' settings are respected when jumping to a buffer. + When used in the quickfix window the line number can + be used, including "." for the current line and "$" + for the last line. *:ll* :ll[!] [nr] Same as ":cc", except the location list for the - current window is used instead of the quickfix list. +:[nr]ll[!] current window is used instead of the quickfix list. *:cn* *:cne* *:cnext* *E553* :[count]cn[ext][!] Display the [count] next error in the list that @@ -125,8 +128,8 @@ processing a quickfix or location list command, it will be aborted. :[count]lab[ove] Same as ":cabove", except the location list for the current window is used instead of the quickfix list. - *:cbe* *:cbelow* -:[count]cbe[low] Go to the [count] error below the current line in the + *:cbel* *:cbelow* +:[count]cbel[ow] Go to the [count] error below the current line in the current buffer. If [count] is omitted, then 1 is used. If there are no errors, then an error message is displayed. Assumes that the entries in a quickfix @@ -136,8 +139,36 @@ processing a quickfix or location list command, it will be aborted. exceeds the number of entries below the current line, then the last error in the file is selected. - *:lbe* *:lbelow* -:[count]lbe[low] Same as ":cbelow", except the location list for the + *:lbel* *:lbelow* +:[count]lbel[ow] Same as ":cbelow", except the location list for the + current window is used instead of the quickfix list. + + *:cbe* *:cbefore* +:[count]cbe[fore] Go to the [count] error before the current cursor + position in the current buffer. If [count] is + omitted, then 1 is used. If there are no errors, then + an error message is displayed. Assumes that the + entries in a quickfix list are sorted by their buffer, + line and column numbers. If [count] exceeds the + number of entries before the current position, then + the first error in the file is selected. + + *:lbe* *:lbefore* +:[count]lbe[fore] Same as ":cbefore", except the location list for the + current window is used instead of the quickfix list. + + *:caf* *:cafter* +:[count]caf[ter] Go to the [count] error after the current cursor + position in the current buffer. If [count] is + omitted, then 1 is used. If there are no errors, then + an error message is displayed. Assumes that the + entries in a quickfix list are sorted by their buffer, + line and column numbers. If [count] exceeds the + number of entries after the current position, then + the last error in the file is selected. + + *:laf* *:lafter* +:[count]laf[ter] Same as ":cafter", except the location list for the current window is used instead of the quickfix list. *:cnf* *:cnfile* @@ -805,14 +836,19 @@ lists. They set one of the existing error lists as the current one. the current window instead of the quickfix list. *:chistory* *:chi* -:chi[story] Show the list of error lists. The current list is +:[count]chi[story] Show the list of error lists. The current list is marked with ">". The output looks like: error list 1 of 3; 43 errors ~ > error list 2 of 3; 0 errors ~ error list 3 of 3; 15 errors ~ + When [count] is given, then the count'th quickfix + list is made the current list. Example: > + " Make the 4th quickfix list current + :4chistory +< *:lhistory* *:lhi* -:lhi[story] Show the list of location lists, otherwise like +:[count]lhi[story] Show the list of location lists, otherwise like `:chistory`. When adding a new error list, it becomes the current list. @@ -1294,7 +1330,11 @@ Basic items %v virtual column number (finds a number representing screen column of the error (1 <tab> == 8 screen columns)) - %t error type (finds a single character) + %t error type (finds a single character): + e - error message + w - warning message + i - info message + n - note message %n error number (finds a number) %m error message (finds a string) %r matches the "rest" of a single-line file message %O/P/Q @@ -1365,6 +1405,7 @@ prefixes are: %E start of a multi-line error message %W start of a multi-line warning message %I start of a multi-line informational message + %N start of a multi-line note message %A start of a multi-line message (unspecified type) %> for next line start with current pattern again |efm-%>| %C continuation of a multi-line message diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index d4b6324bc3..604c969c64 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -180,7 +180,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. Read Ex commands from {file} in each directory given by 'runtimepath' and/or 'packpath'. There is no error for non-existing files. - + Example: > :runtime syntax/c.vim @@ -254,7 +254,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. *:packl* *:packloadall* :packl[oadall][!] Load all packages in the "start" directory under each entry in 'packpath'. - + First all the directories found are added to 'runtimepath', then the plugins found in the directories are sourced. This allows for a plugin to diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 160995b440..4a99aa47bf 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -1316,8 +1316,9 @@ file when reading and include: ============================================================================== Standard Paths *standard-path* -Nvim stores configuration and data in standard locations. Plugins are strongly -encouraged to follow this pattern also. Use |stdpath()| to get the paths. +Nvim stores configuration, data, and logs in standard locations. Plugins are +strongly encouraged to follow this pattern also. Use |stdpath()| to get the +paths. *base-directories* *xdg* The "base" (root) directories conform to the XDG Base Directory Specification. @@ -1342,8 +1343,8 @@ LOG FILE *$NVIM_LOG_FILE* Besides 'debug' and 'verbose', Nvim keeps a general log file for internal debugging, plugins and RPC clients. > :echo $NVIM_LOG_FILE -Usually the file is ~/.local/share/nvim/log unless that path is inaccessible -or if $NVIM_LOG_FILE was set before |startup|. +By default, the file is located at stdpath('cache')/log unless that path +is inaccessible or if $NVIM_LOG_FILE was set before |startup|. vim:noet:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index b011db3dd3..23db809543 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -544,7 +544,7 @@ only supported by new versions of ctags (such as Exuberant ctags). the bar) and ;" is used to have Vi ignore the rest of the line. Example: APP file.c call cursor(3, 4)|;" v - + {field} .. A list of optional fields. Each field has the form: <Tab>{fieldname}:{value} diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 911e7b8b47..1696d3b9ba 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -195,7 +195,8 @@ query:iter_captures({node}, {bufnr}, {start_row}, {end_row}) text of the buffer. {start_row} and {end_row} can be used to limit matches inside a row range (this is typically used with root node as the node, i e to get syntax highlight matches in the current - viewport) + viewport). When omitted the start and end row values are used from + the given node. The iterator returns three values, a numeric id identifying the capture, the captured node, and metadata from any directives processing the match. diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 0a8584927e..82406898c8 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -170,7 +170,7 @@ the editor. `mouse_shape`: (To be implemented.) Some keys are missing in some modes. - + The following keys are deprecated: `hl_id`: Use `attr_id` instead. @@ -460,7 +460,7 @@ is not active. New UIs should implement |ui-linegrid| instead. ["set_scroll_region", top, bot, left, right] Define the scroll region used by `scroll` below. - + Note: ranges are end-inclusive, which is inconsistent with API conventions. diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 31da51bfbe..e92e464c6a 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -723,6 +723,7 @@ Cursor and mark position: *cursor-functions* *mark-functions* getcurpos() get position of the cursor getpos() get position of cursor, mark, etc. setpos() set position of cursor, mark, etc. + getmarklist() list of global/local marks byte2line() get line number at a specific byte count line2byte() byte count at a specific line diff_filler() get the number of filler lines above a line diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 32551815b0..5fb7c4ce50 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -46,26 +46,26 @@ CTRL-L Clears and redraws the screen. The redraw may happen ga Print the ascii value of the character under the cursor in decimal, hexadecimal and octal. Mnemonic: Get Ascii value. - + For example, when the cursor is on a 'R': <R> 82, Hex 52, Octal 122 ~ When the character is a non-standard ASCII character, but printable according to the 'isprint' option, the non-printable version is also given. - + When the character is larger than 127, the <M-x> form is also printed. For example: <~A> <M-^A> 129, Hex 81, Octal 201 ~ <p> <|~> <M-~> 254, Hex fe, Octal 376 ~ (where <p> is a special character) - + The <Nul> character in a file is stored internally as <NL>, but it will be shown as: <^@> 0, Hex 00, Octal 000 ~ - + If the character has composing characters these are also shown. The value of 'maxcombine' doesn't matter. - + If the character can be inserted as a digraph, also output the two characters that can be used to create the character: @@ -317,11 +317,11 @@ g8 Print the hex values of the bytes used in the optional. :redi[r] @{a-z}>> Append messages to register {a-z}. -:redi[r] @*> +:redi[r] @*> :redi[r] @+> Redirect messages to the selection or clipboard. For backward compatibility, the ">" after the register name can be omitted. See |quotestar| and |quoteplus|. -:redi[r] @*>> +:redi[r] @*>> :redi[r] @+>> Append messages to the selection or clipboard. :redi[r] @"> Redirect messages to the unnamed register. For @@ -489,12 +489,12 @@ gO Show a filetype-specific, navigable "outline" of the Currently works in |help| and |:Man| buffers. [N]gs *gs* *:sl* *:sleep* -:[N]sl[eep] [N] [m] Do nothing for [N] seconds, or [N] milliseconds if [m] +:[N]sl[eep] [N][m] Do nothing for [N] seconds, or [N] milliseconds if [m] was given. "gs" always uses seconds. Default is one second. > :sleep "sleep for one second :5sleep "sleep for five seconds - :sleep 100m "sleep for a hundred milliseconds + :sleep 100m "sleep for 100 milliseconds 10gs "sleep for ten seconds < Can be interrupted with CTRL-C. "gs" stands for "goto sleep". diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index b5623f4ea4..2c3ffcbe9a 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -124,7 +124,7 @@ CTRL-W CTRL-S *CTRL-W_CTRL-S* :[N]sp[lit] [++opt] [+cmd] [file] *:sp* *:split* Split current window in two. The result is two viewports on the same file. - + Make the new window N high (default is to use half the height of the current window). Reduces the current window height to create room (and others, if the 'equalalways' option is set, diff --git a/runtime/filetype.vim b/runtime/filetype.vim index d2083b23d3..9104519451 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -495,6 +495,9 @@ au BufNewFile,BufRead *.com call dist#ft#BindzoneCheck('dcl') " DOT au BufNewFile,BufRead *.dot,*.gv setf dot +" Dune +au BufNewFile,BufRead jbuild,dune,dune-project,dune-workspace setf dune + " Dylan - lid files au BufNewFile,BufRead *.lid setf dylanlid @@ -1121,8 +1124,8 @@ au BufNewFile,BufRead *.nse setf lua " NSIS au BufNewFile,BufRead *.nsi,*.nsh setf nsis -" OCAML -au BufNewFile,BufRead *.ml,*.mli,*.mll,*.mly,.ocamlinit setf ocaml +" OCaml +au BufNewFile,BufRead *.ml,*.mli,*.mll,*.mly,.ocamlinit,*.mlt,*.mlp,*.mlip,*.mli.cppo,*.ml.cppo setf ocaml " Occam au BufNewFile,BufRead *.occ setf occam @@ -1130,6 +1133,9 @@ au BufNewFile,BufRead *.occ setf occam " Omnimark au BufNewFile,BufRead *.xom,*.xin setf omnimark +" OPAM +au BufNewFile,BufRead opam,*.opam,*.opam.template setf opam + " OpenROAD au BufNewFile,BufRead *.or setf openroad @@ -1164,7 +1170,9 @@ au BufNewFile,BufRead *.papp,*.pxml,*.pxsl setf papp au BufNewFile,BufRead */etc/passwd,*/etc/passwd-,*/etc/passwd.edit,*/etc/shadow,*/etc/shadow-,*/etc/shadow.edit,*/var/backups/passwd.bak,*/var/backups/shadow.bak setf passwd " Pascal (also *.p) -au BufNewFile,BufRead *.pas,*.pp setf pascal +au BufNewFile,BufRead *.pas setf pascal + +au BufNewFile,BufRead *.pp call dist#ft#FTpp() " Delphi or Lazarus program file au BufNewFile,BufRead *.dpr,*.lpr setf pascal @@ -1549,6 +1557,9 @@ au BufNewFile,BufRead *.scm,*.ss,*.rkt setf scheme " Screen RC au BufNewFile,BufRead .screenrc,screenrc setf screen +" Sexplib +au BufNewFile,BufRead *.sexp setf sexplib + " Simula au BufNewFile,BufRead *.sim setf simula @@ -1609,6 +1620,9 @@ au BufNewFile,BufRead *.mib,*.my setf mib au BufNewFile,BufRead *.hog,snort.conf,vision.conf setf hog au BufNewFile,BufRead *.rules call dist#ft#FTRules() +" SPARQL queries +au BufNewFile,BufRead *.rq,*.sparql setf sparql + " Spec (Linux RPM) au BufNewFile,BufRead *.spec setf spec diff --git a/runtime/ftplugin/elm.vim b/runtime/ftplugin/elm.vim new file mode 100644 index 0000000000..1e10346186 --- /dev/null +++ b/runtime/ftplugin/elm.vim @@ -0,0 +1,18 @@ +" Elm filetype plugin file +" Language: Elm +" Maintainer: Andreas Scharf <as@99n.de> +" Latest Revision: 2020-05-29 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +setlocal comments=s1fl:{-,mb:\ ,ex:-},:-- +setlocal commentstring=--\ %s + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim index 74225a558c..5d3e00d033 100644 --- a/runtime/ftplugin/man.vim +++ b/runtime/ftplugin/man.vim @@ -16,7 +16,11 @@ setlocal noswapfile buftype=nofile bufhidden=hide setlocal nomodified readonly nomodifiable setlocal noexpandtab tabstop=8 softtabstop=8 shiftwidth=8 setlocal wrap breakindent linebreak -setlocal iskeyword+=- + +" Parentheses and '-' for references like `git-ls-files(1)`; '@' for systemd +" pages; ':' for Perl and C++ pages. Here, I intentionally omit the locale +" specific characters matched by `@`. +setlocal iskeyword=@-@,:,a-z,A-Z,48-57,_,.,-,(,) setlocal nonumber norelativenumber setlocal foldcolumn=0 colorcolumn=0 nolist nofoldenable @@ -24,9 +28,10 @@ setlocal foldcolumn=0 colorcolumn=0 nolist nofoldenable setlocal tagfunc=man#goto_tag if !exists('g:no_plugin_maps') && !exists('g:no_man_maps') - nnoremap <silent> <buffer> j gj - nnoremap <silent> <buffer> k gk - nnoremap <silent> <buffer> gO :call man#show_toc()<CR> + nnoremap <silent> <buffer> j gj + nnoremap <silent> <buffer> k gk + nnoremap <silent> <buffer> gO :call man#show_toc()<CR> + nnoremap <silent> <buffer> <2-LeftMouse> :Man<CR> if s:pager nnoremap <silent> <buffer> <nowait> q :lclose<CR>:q<CR> else diff --git a/runtime/indent/elm.vim b/runtime/indent/elm.vim new file mode 100644 index 0000000000..232c347c66 --- /dev/null +++ b/runtime/indent/elm.vim @@ -0,0 +1,114 @@ +" Elm indent plugin file +" Language: Elm +" Maintainer: Andreas Scharf <as@99n.de> +" Original Author: Joseph Hager <ajhager@gmail.com> +" Copyright: Joseph Hager <ajhager@gmail.com> +" License: BSD3 +" Latest Revision: 2020-05-29 + +" Only load this indent file when no other was loaded. +if exists('b:did_indent') + finish +endif +let b:did_indent = 1 + +" Local defaults +setlocal expandtab +setlocal indentexpr=GetElmIndent() +setlocal indentkeys+=0=else,0=if,0=of,0=import,0=then,0=type,0\|,0},0\],0),=-},0=in +setlocal nolisp +setlocal nosmartindent + +" Only define the function once. +if exists('*GetElmIndent') + finish +endif + +" Indent pairs +function! s:FindPair(pstart, pmid, pend) + "call search(a:pend, 'bW') + return indent(searchpair(a:pstart, a:pmid, a:pend, 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string\\|comment"')) +endfunction + +function! GetElmIndent() + let l:lnum = v:lnum - 1 + + " Ident 0 if the first line of the file: + if l:lnum == 0 + return 0 + endif + + let l:ind = indent(l:lnum) + let l:lline = getline(l:lnum) + let l:line = getline(v:lnum) + + " Indent if current line begins with '}': + if l:line =~? '^\s*}' + return s:FindPair('{', '', '}') + + " Indent if current line begins with 'else': + elseif l:line =~# '^\s*else\>' + if l:lline !~# '^\s*\(if\|then\)\>' + return s:FindPair('\<if\>', '', '\<else\>') + endif + + " Indent if current line begins with 'then': + elseif l:line =~# '^\s*then\>' + if l:lline !~# '^\s*\(if\|else\)\>' + return s:FindPair('\<if\>', '', '\<then\>') + endif + + " HACK: Indent lines in case with nearest case clause: + elseif l:line =~# '->' && l:line !~# ':' && l:line !~# '\\' + return indent(search('^\s*case', 'bWn')) + &shiftwidth + + " HACK: Don't change the indentation if the last line is a comment. + elseif l:lline =~# '^\s*--' + return l:ind + + " Align the end of block comments with the start + elseif l:line =~# '^\s*-}' + return indent(search('{-', 'bWn')) + + " Indent double shift after let with an empty rhs + elseif l:lline =~# '\<let\>.*\s=$' + return l:ind + 4 + &shiftwidth + + " Align 'in' with the parent let. + elseif l:line =~# '^\s*in\>' + return indent(search('^\s*let', 'bWn')) + + " Align bindings with the parent let. + elseif l:lline =~# '\<let\>' + return l:ind + 4 + + " Align bindings with the parent in. + elseif l:lline =~# '^\s*in\>' + return l:ind + + endif + + " Add a 'shiftwidth' after lines ending with: + if l:lline =~# '\(|\|=\|->\|<-\|(\|\[\|{\|\<\(of\|else\|if\|then\)\)\s*$' + let l:ind = l:ind + &shiftwidth + + " Add a 'shiftwidth' after lines starting with type ending with '=': + elseif l:lline =~# '^\s*type' && l:line =~# '^\s*=' + let l:ind = l:ind + &shiftwidth + + " Back to normal indent after comments: + elseif l:lline =~# '-}\s*$' + call search('-}', 'bW') + let l:ind = indent(searchpair('{-', '', '-}', 'bWn', 'synIDattr(synID(line("."), col("."), 0), "name") =~? "string"')) + + " Ident some operators if there aren't any starting the last line. + elseif l:line =~# '^\s*\(!\|&\|(\|`\|+\||\|{\|[\|,\)=' && l:lline !~# '^\s*\(!\|&\|(\|`\|+\||\|{\|[\|,\)=' && l:lline !~# '^\s*$' + let l:ind = l:ind + &shiftwidth + + elseif l:lline ==# '' && getline(l:lnum - 1) !=# '' + let l:ind = indent(search('^\s*\S+', 'bWn')) + + endif + + return l:ind +endfunc diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 0326550245..64d08e9733 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -226,6 +226,7 @@ local function validate_client_config(config) on_error = { config.on_error, "f", true }; on_exit = { config.on_exit, "f", true }; on_init = { config.on_init, "f", true }; + settings = { config.settings, "t", true }; before_init = { config.before_init, "f", true }; offset_encoding = { config.offset_encoding, "s", true }; flags = { config.flags, "t", true }; @@ -327,8 +328,9 @@ end --- Checks whether a client is stopped. --- Returns: true if the client is fully stopped. --- ---- - on_attach(bufnr) +--- - on_attach(client, bufnr) --- Runs the on_attach function from the client's config if it was defined. +--- Useful for buffer-local setup. --- --- - Members --- - {id} (number): The id allocated to the client. @@ -398,6 +400,10 @@ end --- --@param handlers Map of language server method names to |lsp-handler| --- +--@param settings Map with language server specific settings. These are +--- returned to the language server if requested via `workspace/configuration`. +--- Keys are case-sensitive. +--- --@param init_options Values to pass in the initialization request --- as `initializationOptions`. See `initialize` in the LSP spec. --- @@ -424,7 +430,10 @@ end --- the server may send. For example, clangd sends --- `initialize_result.offsetEncoding` if `capabilities.offsetEncoding` was --- sent to it. You can only modify the `client.offset_encoding` here before ---- any notifications are sent. +--- any notifications are sent. Most language servers expect to be sent client specified settings after +--- initialization. Neovim does not make this assumption. A +--- `workspace/didChangeConfiguration` notification should be sent +--- to the server during on_init. --- --@param on_exit Callback (code, signal, client_id) invoked on client --- exit. @@ -457,6 +466,7 @@ function lsp.start_client(config) local cmd, cmd_args, offset_encoding = cleaned_config.cmd, cleaned_config.cmd_args, cleaned_config.offset_encoding config.flags = config.flags or {} + config.settings = config.settings or {} local client_id = next_client_id() @@ -581,12 +591,19 @@ function lsp.start_client(config) local valid_traces = { off = 'off'; messages = 'messages'; verbose = 'verbose'; } + local version = vim.version() local initialize_params = { -- The process Id of the parent process that started the server. Is null if -- the process has not been started by another process. If the parent -- process is not alive then the server should exit (see exit notification) -- its process. processId = uv.getpid(); + -- Information about the client + -- since 3.15.0 + clientInfo = { + name = "Neovim", + version = string.format("%s.%s.%s", version.major, version.minor, version.patch) + }; -- The rootPath of the workspace. Is null if no folder is open. -- -- @deprecated in favour of rootUri. diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 072349b226..a625098bab 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -16,6 +16,24 @@ local to_severity = function(severity) return type(severity) == 'string' and DiagnosticSeverity[severity] or severity end +local filter_to_severity_limit = function(severity, diagnostics) + local filter_level = to_severity(severity) + if not filter_level then + return diagnostics + end + + return vim.tbl_filter(function(t) return t.severity == filter_level end, diagnostics) +end + +local filter_by_severity_limit = function(severity_limit, diagnostics) + local filter_level = to_severity(severity_limit) + if not filter_level then + return diagnostics + end + + return vim.tbl_filter(function(t) return t.severity <= filter_level end, diagnostics) +end + local to_position = function(position, bufnr) vim.validate { position = {position, 't'} } @@ -377,11 +395,9 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) end if opts.severity then - local filter_level = to_severity(opts.severity) - line_diagnostics = vim.tbl_filter(function(t) return t.severity == filter_level end, line_diagnostics) + line_diagnostics = filter_to_severity_limit(opts.severity, line_diagnostics) elseif opts.severity_limit then - local filter_level = to_severity(opts.severity_limit) - line_diagnostics = vim.tbl_filter(function(t) return t.severity <= filter_level end, line_diagnostics) + line_diagnostics = filter_by_severity_limit(opts.severity_limit, line_diagnostics) end if opts.severity_sort then @@ -542,7 +558,7 @@ function M.goto_prev(opts) ) end ---- Get the previous diagnostic closest to the cursor_position +--- Get the next diagnostic closest to the cursor_position ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic function M.get_next(opts) @@ -609,6 +625,8 @@ end ---@param sign_ns number|nil ---@param opts table Configuration for signs. Keys: --- - priority: Set the priority of the signs. +--- - severity_limit (DiagnosticSeverity): +--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_signs(diagnostics, bufnr, client_id, sign_ns, opts) opts = opts or {} sign_ns = sign_ns or M._get_sign_namespace(client_id) @@ -622,9 +640,11 @@ function M.set_signs(diagnostics, bufnr, client_id, sign_ns, opts) end bufnr = get_bufnr(bufnr) + diagnostics = filter_by_severity_limit(opts.severity_limit, diagnostics) local ok = true for _, diagnostic in ipairs(diagnostics) do + ok = ok and pcall(vim.fn.sign_place, 0, sign_ns, @@ -654,15 +674,17 @@ end --- </pre> --- ---@param diagnostics Diagnostic[] ----@param bufnr number The buffer number ----@param client_id number the client id ----@param diagnostic_ns number|nil ----@param opts table Currently unused. +---@param bufnr number: The buffer number +---@param client_id number: The client id +---@param diagnostic_ns number|nil: The namespace +---@param opts table: Configuration table: +--- - severity_limit (DiagnosticSeverity): +--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_underline(diagnostics, bufnr, client_id, diagnostic_ns, opts) opts = opts or {} - assert(opts) -- lint diagnostic_ns = diagnostic_ns or M._get_diagnostic_namespace(client_id) + diagnostics = filter_by_severity_limit(opts.severity_limit, diagnostics) for _, diagnostic in ipairs(diagnostics) do local start = diagnostic.range["start"] @@ -703,6 +725,8 @@ end ---@param opts table Options on how to display virtual text. Keys: --- - prefix (string): Prefix to display before virtual text on line --- - spacing (number): Number of spaces to insert before virtual text +--- - severity_limit (DiagnosticSeverity): +--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_virtual_text(diagnostics, bufnr, client_id, diagnostic_ns, opts) opts = opts or {} @@ -721,6 +745,7 @@ function M.set_virtual_text(diagnostics, bufnr, client_id, diagnostic_ns, opts) end for line, line_diagnostics in pairs(buffer_line_diagnostics) do + line_diagnostics = filter_by_severity_limit(opts.severity_limit, line_diagnostics) local virt_texts = M.get_virtual_text_chunks_for_line(bufnr, line, line_diagnostics, opts) if virt_texts then @@ -1082,7 +1107,7 @@ end ---@param bufnr number The buffer number ---@param line_nr number The line number ---@param client_id number|nil the client id ----@return {popup_bufnr, win_id} +---@return table {popup_bufnr, win_id} function M.show_line_diagnostics(opts, bufnr, line_nr, client_id) opts = opts or {} opts.severity_sort = if_nil(opts.severity_sort, true) @@ -1151,30 +1176,14 @@ function M.set_loclist(opts) local bufnr = vim.api.nvim_get_current_buf() local buffer_diags = M.get(bufnr, opts.client_id) - local severity = to_severity(opts.severity) - local severity_limit = to_severity(opts.severity_limit) + if opts.severity then + buffer_diags = filter_to_severity_limit(opts.severity, buffer_diags) + elseif opts.severity_limit then + buffer_diags = filter_by_severity_limit(opts.severity_limit, buffer_diags) + end local items = {} local insert_diag = function(diag) - if severity then - -- Handle missing severities - if not diag.severity then - return - end - - if severity ~= diag.severity then - return - end - elseif severity_limit then - if not diag.severity then - return - end - - if severity_limit < diag.severity then - return - end - end - local pos = diag.range.start local row = pos.line local col = util.character_offset(bufnr, row, pos.character) diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index fd23a6a547..7eac3febd9 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -28,8 +28,9 @@ end -- Basically a token of type number/string local function progress_callback(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) + local client_name = client and client.name or string.format("id=%d", client_id) if not client then - err_message("LSP[", client_id, "] client has shut down after sending the message") + err_message("LSP[", client_name, "] client has shut down after sending the message") end local val = params.value -- unspecified yet local token = params.token -- string or number @@ -43,14 +44,11 @@ local function progress_callback(_, _, params, client_id) percentage = val.percentage, } elseif val.kind == 'report' then - client.messages.progress[token] = { - message = val.message, - percentage = val.percentage, - } + client.messages.progress[token].message = val.message; + client.messages.progress[token].percentage = val.percentage; elseif val.kind == 'end' then if client.messages.progress[token] == nil then - err_message( - 'echom "[lsp-status] Received `end` message with no corresponding `begin` from "') + err_message("LSP[", client_name, "] received `end` message with no corresponding `begin`") else client.messages.progress[token].message = val.message client.messages.progress[token].done = true @@ -70,8 +68,9 @@ M['$/progress'] = progress_callback M['window/workDoneProgress/create'] = function(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) local token = params.token -- string or number + local client_name = client and client.name or string.format("id=%d", client_id) if not client then - err_message("LSP[", client_id, "] client has shut down after sending the message") + err_message("LSP[", client_name, "] client has shut down after sending the message") end client.messages.progress[token] = {} return vim.NIL @@ -94,13 +93,22 @@ M['window/showMessageRequest'] = function(_, _, params) if choice < 1 or choice > #actions then return vim.NIL else - local action_chosen = actions[choice] - return { - title = action_chosen; - } + return actions[choice] end end +--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability +M['client/registerCapability'] = function(_, _, _, client_id) + local warning_tpl = "The language server %s triggers a registerCapability ".. + "handler despite dynamicRegistration set to false. ".. + "Report upstream, this warning is harmless" + local client = vim.lsp.get_client_by_id(client_id) + local client_name = client and client.name or string.format("id=%d", client_id) + local warning = string.format(warning_tpl, client_name) + log.warn(warning) + return vim.NIL +end + --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction M['textDocument/codeAction'] = function(_, _, actions) if actions == nil or vim.tbl_isempty(actions) then @@ -149,6 +157,32 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit) } end +--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration +M['workspace/configuration'] = function(err, _, params, client_id) + local client = vim.lsp.get_client_by_id(client_id) + if not client then + err_message("LSP[id=", client_id, "] client has shut down after sending the message") + return + end + if err then error(vim.inspect(err)) end + if not params.items then + return {} + end + + local result = {} + for _, item in ipairs(params.items) do + if item.section then + local value = util.lookup_section(client.config.settings, item.section) or vim.NIL + -- For empty sections with no explicit '' key, return settings as is + if value == vim.NIL and item.section == '' then + value = client.config.settings or vim.NIL + end + table.insert(result, value) + end + end + return result +end + M['textDocument/publishDiagnostics'] = function(...) return require('vim.lsp.diagnostic').on_publish_diagnostics(...) end diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 587a65cd96..b6e91e37b9 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -28,7 +28,7 @@ do local function path_join(...) return table.concat(vim.tbl_flatten{...}, path_sep) end - local logfilename = path_join(vim.fn.stdpath('data'), 'lsp.log') + local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log') --- Returns the log filename. --@returns (string) log filename @@ -36,7 +36,7 @@ do return logfilename end - vim.fn.mkdir(vim.fn.stdpath('data'), "p") + vim.fn.mkdir(vim.fn.stdpath('cache'), "p") local logfile = assert(io.open(logfilename, "a+")) for level, levelnr in pairs(log.levels) do -- Also export the log level on the root object. diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index b2d3d0641c..3e111c154a 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -34,6 +34,13 @@ local constants = { Hint = 4; }; + DiagnosticTag = { + -- Unused or unnecessary code + Unnecessary = 1; + -- Deprecated or obsolete code + Deprecated = 2; + }; + MessageType = { -- An error message. Error = 1; @@ -521,6 +528,13 @@ export interface TextDocumentClientCapabilities { publishDiagnostics?: { --Whether the clients accepts diagnostics with related information. relatedInformation?: boolean; + --Client supports the tag property to provide meta data about a diagnostic. + --Clients supporting tags have to handle unknown tags gracefully. + --Since 3.15.0 + tagSupport?: { + --The tags supported by this client + valueSet: DiagnosticTag[]; + }; }; --Capabilities specific to `textDocument/foldingRange` requests. -- @@ -706,6 +720,18 @@ function protocol.make_client_capabilities() dynamicRegistration = false; prepareSupport = true; }; + publishDiagnostics = { + relatedInformation = true; + tagSupport = { + valueSet = (function() + local res = {} + for k in ipairs(protocol.DiagnosticTag) do + if type(k) == 'number' then table.insert(res, k) end + end + return res + end)(); + }; + }; }; workspace = { symbol = { diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 0972ea83c4..e33e0109b6 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -254,19 +254,27 @@ function M.extract_completion_items(result) end --- Applies a `TextDocumentEdit`, which is a list of changes to a single --- document. +--- document. --- ---@param text_document_edit (table) a `TextDocumentEdit` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit -function M.apply_text_document_edit(text_document_edit) +---@param text_document_edit table: a `TextDocumentEdit` object +---@param index number: Optional index of the edit, if from a list of edits (or nil, if not from a list) +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit +function M.apply_text_document_edit(text_document_edit, index) local text_document = text_document_edit.textDocument local bufnr = vim.uri_to_bufnr(text_document.uri) + -- For lists of text document edits, + -- do not check the version after the first edit. + local should_check_version = true + if index and index > 1 then + should_check_version = false + end + -- `VersionedTextDocumentIdentifier`s version may be null -- https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier - if text_document.version + if should_check_version and (text_document.version and M.buf_versions[bufnr] - and M.buf_versions[bufnr] > text_document.version then + and M.buf_versions[bufnr] > text_document.version) then print("Buffer ", text_document.uri, " newer than edits.") return end @@ -459,12 +467,12 @@ end -- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit) if workspace_edit.documentChanges then - for _, change in ipairs(workspace_edit.documentChanges) do + for idx, change in ipairs(workspace_edit.documentChanges) do if change.kind then -- TODO(ashkan) handle CreateFile/RenameFile/DeleteFile error(string.format("Unsupported change: %q", vim.inspect(change))) else - M.apply_text_document_edit(change) + M.apply_text_document_edit(change, idx) end end return @@ -1422,6 +1430,21 @@ function M.character_offset(buf, row, col) return str_utfindex(line, col) end +--- Helper function to return nested values in language server settings +--- +--@param settings a table of language server settings +--@param section a string indicating the field of the settings table +--@returns (table or string) The value of settings accessed via section +function M.lookup_section(settings, section) + for part in vim.gsplit(section, '.', true) do + settings = settings[part] + if not settings then + return + end + end + return settings +end + M._get_line_byte_from_position = get_line_byte_from_position M._warn_once = warn_once diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 79dcf77f9e..38ac182e32 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -50,7 +50,7 @@ function M._create_parser(bufnr, lang, opts) end end - a.nvim_buf_attach(self.bufnr, false, {on_bytes=bytes_cb, on_detach=detach_cb, preview=true}) + a.nvim_buf_attach(self:source(), false, {on_bytes=bytes_cb, on_detach=detach_cb, preview=true}) self:parse() diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 9c620c422c..c864fe5878 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -425,23 +425,21 @@ function LanguageTree:register_cbs(cbs) end end -local function region_contains(region, range) - for _, node in ipairs(region) do - local start_row, start_col, end_row, end_col = node:range() - local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2]) - local end_fits = end_row > range[3] or (end_row == range[3] and end_col >= range[4]) +local function tree_contains(tree, range) + local start_row, start_col, end_row, end_col = tree:root():range() + local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2]) + local end_fits = end_row > range[3] or (end_row == range[3] and end_col >= range[4]) - if start_fits and end_fits then - return true - end + if start_fits and end_fits then + return true end return false end function LanguageTree:contains(range) - for _, region in pairs(self._regions) do - if region_contains(region, range) then + for _, tree in pairs(self._trees) do + if tree_contains(tree, range) then return true end end diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 682f981fbc..e49f54681d 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -8,36 +8,10 @@ Query.__index = Query local M = {} --- Filter the runtime query files, the spec is like regular runtime files but in the new `queries` --- directory. They resemble ftplugins, that is that you can override queries by adding things in the --- `queries` directory, and extend using the `after/queries` directory. -local function filter_files(file_list) - local main = nil - local after = {} - - for _, fname in ipairs(file_list) do - -- Only get the name of the directory containing the queries directory - if vim.fn.fnamemodify(fname, ":p:h:h:h:t") == "after" then - table.insert(after, fname) - -- The first one is the one with most priority - elseif not main then - main = fname - end - end - return main and { main, unpack(after) } or after -end - -local function runtime_query_path(lang, query_name) - return string.format('queries/%s/%s.scm', lang, query_name) -end - -local function filtered_runtime_queries(lang, query_name) - return filter_files(a.nvim_get_runtime_file(runtime_query_path(lang, query_name), true) or {}) -end - -local function get_query_files(lang, query_name, is_included) - local lang_files = filtered_runtime_queries(lang, query_name) +function M.get_query_files(lang, query_name, is_included) + local query_path = string.format('queries/%s/%s.scm', lang, query_name) + local lang_files = a.nvim_get_runtime_file(query_path, true) if #lang_files == 0 then return {} end @@ -51,10 +25,10 @@ local function get_query_files(lang, query_name, is_included) local MODELINE_FORMAT = "^;+%s*inherits%s*:?%s*([a-z_,()]+)%s*$" for _, file in ipairs(lang_files) do - local modeline = vim.fn.readfile(file, "", 1) + local modeline = io.open(file, 'r'):read('*l') - if #modeline == 1 then - local langlist = modeline[1]:match(MODELINE_FORMAT) + if modeline then + local langlist = modeline:match(MODELINE_FORMAT) if langlist then for _, incllang in ipairs(vim.split(langlist, ',', true)) do @@ -74,7 +48,7 @@ local function get_query_files(lang, query_name, is_included) local query_files = {} for _, base_lang in ipairs(base_langs) do - local base_files = get_query_files(base_lang, query_name, true) + local base_files = M.get_query_files(base_lang, query_name, true) vim.list_extend(query_files, base_files) end vim.list_extend(query_files, lang_files) @@ -86,10 +60,10 @@ local function read_query_files(filenames) local contents = {} for _,filename in ipairs(filenames) do - vim.list_extend(contents, vim.fn.readfile(filename)) + table.insert(contents, io.open(filename, 'r'):read('*a')) end - return table.concat(contents, '\n') + return table.concat(contents, '') end local match_metatable = { @@ -110,7 +84,7 @@ end -- -- @return The corresponding query, parsed. function M.get_query(lang, query_name) - local query_files = get_query_files(lang, query_name) + local query_files = M.get_query_files(lang, query_name) local query_string = read_query_files(query_files) if #query_string > 0 then @@ -366,6 +340,19 @@ function Query:apply_directives(match, pattern, source, metadata) end end + +--- Returns the start and stop value if set else the node's range. +-- When the node's range is used, the stop is incremented by 1 +-- to make the search inclusive. +local function value_or_node_range(start, stop, node) + if start == nil and stop == nil then + local node_start, _, node_stop, _ = node:range() + return node_start, node_stop + 1 -- Make stop inclusive + end + + return start, stop +end + --- Iterates of the captures of self on a given range. -- -- @param node The node under witch the search will occur @@ -379,6 +366,9 @@ function Query:iter_captures(node, source, start, stop) if type(source) == "number" and source == 0 then source = vim.api.nvim_get_current_buf() end + + start, stop = value_or_node_range(start, stop, node) + local raw_iter = node:_rawquery(self.query, true, start, stop) local function iter() local capture, captured_node, match = raw_iter() @@ -411,6 +401,9 @@ function Query:iter_matches(node, source, start, stop) if type(source) == "number" and source == 0 then source = vim.api.nvim_get_current_buf() end + + start, stop = value_or_node_range(start, stop, node) + local raw_iter = node:_rawquery(self.query, false, start, stop) local function iter() local pattern, match = raw_iter() diff --git a/runtime/nvim.appdata.xml b/runtime/nvim.appdata.xml index 025de1b5a9..e99c76a930 100644 --- a/runtime/nvim.appdata.xml +++ b/runtime/nvim.appdata.xml @@ -26,6 +26,7 @@ </screenshots> <releases> + <release date="2020-08-04" version="0.4.4"/> <release date="2019-11-06" version="0.4.3"/> <release date="2019-09-15" version="0.4.2"/> <release date="2019-09-15" version="0.4.1"/> diff --git a/runtime/scripts.vim b/runtime/scripts.vim index 6aae2b1ec3..536993d485 100644 --- a/runtime/scripts.vim +++ b/runtime/scripts.vim @@ -182,6 +182,10 @@ if s:line1 =~# "^#!" elseif s:name =~# 'clojure' set ft=clojure + " Free Pascal + elseif s:name =~# 'instantfpc\>' + set ft=pascal + endif unlet s:name diff --git a/runtime/syntax/elm.vim b/runtime/syntax/elm.vim new file mode 100644 index 0000000000..1277827f57 --- /dev/null +++ b/runtime/syntax/elm.vim @@ -0,0 +1,105 @@ +" Vim syntax file +" Language: Elm +" Maintainer: Andreas Scharf <as@99n.de> +" Original Author: Joseph Hager <ajhager@gmail.com> +" Copyright: Joseph Hager <ajhager@gmail.com> +" License: BSD3 +" Latest Revision: 2020-05-29 + +if exists('b:current_syntax') + finish +endif + +" Keywords +syn keyword elmConditional else if of then case +syn keyword elmAlias alias +syn keyword elmTypedef contained type port +syn keyword elmImport exposing as import module where + +" Operators +" elm/core +syn match elmOperator contained "\(<|\||>\|||\|&&\|==\|/=\|<=\|>=\|++\|::\|+\|-\|*\|/\|//\|^\|<>\|>>\|<<\|<\|>\|%\)" +" elm/parser +syn match elmOperator contained "\(|.\||=\)" +" elm/url +syn match elmOperator contained "\(</>\|<?>\)" + +" Types +syn match elmType "\<[A-Z][0-9A-Za-z_-]*" +syn keyword elmNumberType number + +" Modules +syn match elmModule "\<\([A-Z][0-9A-Za-z_'-\.]*\)\+\.[A-Za-z]"me=e-2 +syn match elmModule "^\(module\|import\)\s\+[A-Z][0-9A-Za-z_'-\.]*\(\s\+as\s\+[A-Z][0-9A-Za-z_'-\.]*\)\?\(\s\+exposing\)\?" contains=elmImport + +" Delimiters +syn match elmDelimiter "[,;]" +syn match elmBraces "[()[\]{}]" + +" Functions +syn match elmTupleFunction "\((,\+)\)" + +" Comments +syn keyword elmTodo TODO FIXME XXX contained +syn match elmLineComment "--.*" contains=elmTodo,@spell +syn region elmComment matchgroup=elmComment start="{-|\=" end="-}" contains=elmTodo,elmComment,@spell fold + +" Strings +syn match elmStringEscape "\\u[0-9a-fA-F]\{4}" contained +syn match elmStringEscape "\\[nrfvbt\\\"]" contained +syn region elmString start="\"" skip="\\\"" end="\"" contains=elmStringEscape,@spell +syn region elmTripleString start="\"\"\"" skip="\\\"" end="\"\"\"" contains=elmStringEscape,@spell +syn match elmChar "'[^'\\]'\|'\\.'\|'\\u[0-9a-fA-F]\{4}'" + +" Lambda +syn region elmLambdaFunc start="\\"hs=s+1 end="->"he=e-2 + +" Debug +syn match elmDebug "Debug.\(log\|todo\|toString\)" + +" Numbers +syn match elmInt "-\?\<\d\+\>" +syn match elmFloat "-\?\(\<\d\+\.\d\+\>\)" + +" Identifiers +syn match elmTopLevelDecl "^\s*[a-zA-Z][a-zA-z0-9_]*\('\)*\s\+:\(\r\n\|\r\|\n\|\s\)\+" contains=elmOperator +syn match elmFuncName /^\l\w*/ + +" Folding +syn region elmTopLevelTypedef start="type" end="\n\(\n\n\)\@=" contains=ALL fold +syn region elmTopLevelFunction start="^[a-zA-Z].\+\n[a-zA-Z].\+=" end="^\(\n\+\)\@=" contains=ALL fold +syn region elmCaseBlock matchgroup=elmCaseBlockDefinition start="^\z\(\s\+\)\<case\>" end="^\z1\@!\W\@=" end="\(\n\n\z1\@!\)\@=" end="\n\z1\@!\(\n\n\)\@=" contains=ALL fold +syn region elmCaseItemBlock start="^\z\(\s\+\).\+->$" end="^\z1\@!\W\@=" end="\(\n\n\z1\@!\)\@=" end="\(\n\z1\S\)\@=" contains=ALL fold +syn region elmLetBlock matchgroup=elmLetBlockDefinition start="\<let\>" end="\<in\>" contains=ALL fold + +hi def link elmFuncName Function +hi def link elmCaseBlockDefinition Conditional +hi def link elmCaseBlockItemDefinition Conditional +hi def link elmLetBlockDefinition TypeDef +hi def link elmTopLevelDecl Function +hi def link elmTupleFunction Normal +hi def link elmTodo Todo +hi def link elmComment Comment +hi def link elmLineComment Comment +hi def link elmString String +hi def link elmTripleString String +hi def link elmChar String +hi def link elmStringEscape Special +hi def link elmInt Number +hi def link elmFloat Float +hi def link elmDelimiter Delimiter +hi def link elmBraces Delimiter +hi def link elmTypedef TypeDef +hi def link elmImport Include +hi def link elmConditional Conditional +hi def link elmAlias Delimiter +hi def link elmOperator Operator +hi def link elmType Type +hi def link elmNumberType Identifier +hi def link elmLambdaFunc Function +hi def link elmDebug Debug +hi def link elmModule Type + +syn sync minlines=500 + +let b:current_syntax = 'elm' diff --git a/scripts/genvimvim.lua b/scripts/genvimvim.lua index 806533f2ff..ccd5489fdc 100644 --- a/scripts/genvimvim.lua +++ b/scripts/genvimvim.lua @@ -55,7 +55,7 @@ end vimcmd_start = 'syn keyword vimCommand contained ' w(vimcmd_start) local prev_cmd = nil -for _, cmd_desc in ipairs(ex_cmds) do +for _, cmd_desc in ipairs(ex_cmds.cmds) do if lld.line_length > 850 then w('\n' .. vimcmd_start) end diff --git a/src/nvim/README.md b/src/nvim/README.md index d14ba85546..affc5c79cc 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -38,7 +38,7 @@ alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. Requires Many log messages have a shared prefix, such as "UI" or "RPC". Use the shell to filter the log, e.g. at DEBUG level you might want to exclude UI messages: - tail -F ~/.local/share/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log + tail -F ~/.cache/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log Build with ASAN --------------- diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 2c99d3426c..7cee569989 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -820,6 +820,10 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, } buf_T *target_buf = find_buffer_by_handle(buffer, err); + if (!target_buf) { + return; + } + MapArguments parsed_args; memset(&parsed_args, 0, sizeof(parsed_args)); if (parse_keymap_opts(opts, &parsed_args, err)) { @@ -1641,6 +1645,43 @@ bool api_object_to_bool(Object obj, const char *what, } } +HlMessage parse_hl_msg(Array chunks, Error *err) +{ + HlMessage hl_msg = KV_INITIAL_VALUE; + for (size_t i = 0; i < chunks.size; i++) { + if (chunks.items[i].type != kObjectTypeArray) { + api_set_error(err, kErrorTypeValidation, "Chunk is not an array"); + goto free_exit; + } + Array chunk = chunks.items[i].data.array; + if (chunk.size == 0 || chunk.size > 2 + || chunk.items[0].type != kObjectTypeString + || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) { + api_set_error(err, kErrorTypeValidation, + "Chunk is not an array with one or two strings"); + goto free_exit; + } + + String str = copy_string(chunk.items[0].data.string); + + int attr = 0; + if (chunk.size == 2) { + String hl = chunk.items[1].data.string; + if (hl.size > 0) { + int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size); + attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; + } + } + kv_push(hl_msg, ((HlMessageChunk){ .text = str, .attr = attr })); + } + + return hl_msg; + +free_exit: + clear_hl_msg(&hl_msg); + return hl_msg; +} + const char *describe_ns(NS ns_id) { String name; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 1e972e01be..9e2fb6da6f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -990,6 +990,47 @@ void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); } +/// Echo a message. +/// +/// @param chunks A list of [text, hl_group] arrays, each representing a +/// text chunk with specified highlight. `hl_group` element +/// can be omitted for no highlight. +/// @param history if true, add to |message-history|. +/// @param opts Optional parameters. Reserved for future use. +void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err) + FUNC_API_SINCE(7) +{ + HlMessage hl_msg = parse_hl_msg(chunks, err); + if (ERROR_SET(err)) { + goto error; + } + + if (opts.size > 0) { + api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + goto error; + } + + no_wait_return++; + bool need_clear = true; + msg_start(); + for (uint32_t i = 0; i < kv_size(hl_msg); i++) { + HlMessageChunk chunk = kv_A(hl_msg, i); + msg_multiline_attr((const char *)chunk.text.data, chunk.attr, + false, &need_clear); + } + if (history) { + msg_ext_set_kind("echomsg"); + add_hl_msg_hist(hl_msg); + } else { + msg_ext_set_kind("echo"); + } + no_wait_return--; + msg_end(); + +error: + clear_hl_msg(&hl_msg); +} + /// Writes a message to the Vim output buffer. Does not append "\n", the /// message is buffered (won't display) until a linefeed is written. /// diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 93a03986e5..0134ee838d 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2159,10 +2159,11 @@ static buf_T *buflist_findname_file_id(char_u *ffname, FileID *file_id, int buflist_findpat( const char_u *pattern, const char_u *pattern_end, // pointer to first char after pattern - int unlisted, // find unlisted buffers - int diffmode, // find diff-mode buffers only - int curtab_only // find buffers in current tab only + bool unlisted, // find unlisted buffers + bool diffmode, // find diff-mode buffers only + bool curtab_only // find buffers in current tab only ) + FUNC_ATTR_NONNULL_ARG(1) { int match = -1; int find_listed; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 876e53e3cd..b2abb06075 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -8282,8 +8282,9 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) } } while (revins_on || (curwin->w_cursor.col > mincol - && (curwin->w_cursor.lnum != Insstart_orig.lnum - || curwin->w_cursor.col != Insstart_orig.col))); + && (can_bs(BS_NOSTOP) + || (curwin->w_cursor.lnum != Insstart_orig.lnum + || curwin->w_cursor.col != Insstart_orig.col)))); } did_backspace = true; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index f60504de5e..8a1556320c 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5948,6 +5948,19 @@ int assert_exception(typval_T *argvars) return 0; } +static void assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars, + const char *cmd) + FUNC_ATTR_NONNULL_ALL +{ + if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { + char *const tofree = encode_tv2echo(&argvars[2], NULL); + ga_concat(gap, (char_u *)tofree); + xfree(tofree); + } else { + ga_concat(gap, (char_u *)cmd); + } +} + int assert_fails(typval_T *argvars) FUNC_ATTR_NONNULL_ALL { @@ -5966,14 +5979,7 @@ int assert_fails(typval_T *argvars) if (!called_emsg) { prepare_assert_error(&ga); ga_concat(&ga, (const char_u *)"command did not fail: "); - if (argvars[1].v_type != VAR_UNKNOWN - && argvars[2].v_type != VAR_UNKNOWN) { - char *const tofree = encode_tv2echo(&argvars[2], NULL); - ga_concat(&ga, (char_u *)tofree); - xfree(tofree); - } else { - ga_concat(&ga, (const char_u *)cmd); - } + assert_append_cmd_or_arg(&ga, argvars, cmd); assert_error(&ga); ga_clear(&ga); ret = 1; @@ -5986,6 +5992,8 @@ int assert_fails(typval_T *argvars) prepare_assert_error(&ga); fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER); + ga_concat(&ga, (char_u *)": "); + assert_append_cmd_or_arg(&ga, argvars, cmd); assert_error(&ga); ga_clear(&ga); ret = 1; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 466f1800c7..952fa35b83 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -150,6 +150,7 @@ return { getjumplist={args={0, 2}}, getline={args={1, 2}}, getloclist={args={1, 2}}, + getmarklist={args={0, 1}}, getmatches={args={0, 1}}, getpid={}, getpos={args=1}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 16eb6f8898..8235d74cbb 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -726,7 +726,7 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only) p_cpo = (char_u *)""; buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name), - TRUE, FALSE, curtab_only)); + true, false, curtab_only)); p_magic = save_magic; p_cpo = save_cpo; @@ -2165,7 +2165,7 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr) .nextcmd = NULL, .cmdidx = CMD_USER, }; - eap.argt |= NOSPC; + eap.argt |= EX_NOSPC; expand_filename(&eap, &cmdstr, &errormsg); if (errormsg != NULL && *errormsg != NUL) { @@ -3483,6 +3483,25 @@ static void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) get_qf_loc_list(false, wp, &argvars[1], rettv); } + +/// "getmarklist()" function +static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + tv_list_alloc_ret(rettv, kListLenMayKnow); + + if (argvars[0].v_type == VAR_UNKNOWN) { + get_global_marks(rettv->vval.v_list); + return; + } + + buf_T *buf = tv_get_buf(&argvars[0], false); + if (buf == NULL) { + return; + } + + get_buf_local_marks(buf, rettv->vval.v_list); +} + /* * "getmatches()" function */ diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index ae389a6727..a2487336f1 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -629,6 +629,8 @@ void ex_sort(exarg_T *eap) if (sort_abort) goto sortend; + bcount_t old_count = 0, new_count = 0; + // Insert the lines in the sorted order below the last one. lnum = eap->line2; for (i = 0; i < count; i++) { @@ -641,6 +643,8 @@ void ex_sort(exarg_T *eap) } s = ml_get(get_lnum); + size_t bytelen = STRLEN(s) + 1; // include EOL in bytelen + old_count += bytelen; if (!unique || i == 0 || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0) { // Copy the line into a buffer, it may become invalid in @@ -649,6 +653,7 @@ void ex_sort(exarg_T *eap) if (ml_append(lnum++, sortbuf1, (colnr_T)0, false) == FAIL) { break; } + new_count += bytelen; } fast_breakcheck(); if (got_int) @@ -668,11 +673,16 @@ void ex_sort(exarg_T *eap) deleted = (long)(count - (lnum - eap->line2)); if (deleted > 0) { mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted, - kExtmarkUndo); + kExtmarkNOOP); msgmore(-deleted); } else if (deleted < 0) { - mark_adjust(eap->line2, MAXLNUM, -deleted, 0L, kExtmarkUndo); + mark_adjust(eap->line2, MAXLNUM, -deleted, 0L, kExtmarkNOOP); } + + extmark_splice(curbuf, eap->line1-1, 0, + count, 0, old_count, + lnum - eap->line2, 0, new_count, kExtmarkUndo); + if (change_occurred || deleted != 0) { changed_lines(eap->line1, 0, eap->line2 + 1, -deleted, true); } @@ -1032,14 +1042,15 @@ void free_prev_shellcmd(void) * Bangs in the argument are replaced with the previously entered command. * Remember the argument. */ -void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out) +void do_bang(int addr_count, exarg_T *eap, bool forceit, + bool do_in, bool do_out) + FUNC_ATTR_NONNULL_ALL { - char_u *arg = eap->arg; /* command */ - linenr_T line1 = eap->line1; /* start of range */ - linenr_T line2 = eap->line2; /* end of range */ - char_u *newcmd = NULL; /* the new command */ - int free_newcmd = FALSE; /* need to free() newcmd */ - int ins_prevcmd; + char_u *arg = eap->arg; // command + linenr_T line1 = eap->line1; // start of range + linenr_T line2 = eap->line2; // end of range + char_u *newcmd = NULL; // the new command + bool free_newcmd = false; // need to free() newcmd char_u *t; char_u *p; char_u *trailarg; @@ -1064,7 +1075,7 @@ void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out) * Try to find an embedded bang, like in :!<cmd> ! [args] * (:!! is indicated by the 'forceit' variable) */ - ins_prevcmd = forceit; + bool ins_prevcmd = forceit; trailarg = arg; do { len = (int)STRLEN(trailarg) + 1; @@ -1101,7 +1112,7 @@ void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out) else { trailarg = p; *trailarg++ = NUL; - ins_prevcmd = TRUE; + ins_prevcmd = true; break; } } @@ -1131,7 +1142,7 @@ void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out) STRCPY(newcmd, p_shq); STRCAT(newcmd, prevcmd); STRCAT(newcmd, p_shq); - free_newcmd = TRUE; + free_newcmd = true; } if (addr_count == 0) { /* :! */ /* echo the command */ @@ -1164,15 +1175,15 @@ void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out) // do this. // Alternatively, if on Unix and redirecting input or output, but not both, // and the 'shelltemp' option isn't set, use pipes. -// We use input redirection if do_in is TRUE. -// We use output redirection if do_out is TRUE. +// We use input redirection if do_in is true. +// We use output redirection if do_out is true. static void do_filter( linenr_T line1, linenr_T line2, exarg_T *eap, /* for forced 'ff' and 'fenc' */ char_u *cmd, - int do_in, - int do_out) + bool do_in, + bool do_out) { char_u *itmp = NULL; char_u *otmp = NULL; @@ -1669,10 +1680,17 @@ void ex_update(exarg_T *eap) */ void ex_write(exarg_T *eap) { - if (eap->usefilter) /* input lines to shell command */ - do_bang(1, eap, FALSE, TRUE, FALSE); - else + if (eap->cmdidx == CMD_saveas) { + // :saveas does not take a range, uses all lines. + eap->line1 = 1; + eap->line2 = curbuf->b_ml.ml_line_count; + } + + if (eap->usefilter) { // input lines to shell command + do_bang(1, eap, false, true, false); + } else { (void)do_write(eap); + } } /* @@ -3675,6 +3693,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, } else { char_u *orig_line = NULL; int len_change = 0; + const bool save_p_lz = p_lz; int save_p_fen = curwin->w_p_fen; curwin->w_p_fen = FALSE; @@ -3683,6 +3702,9 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, int temp = RedrawingDisabled; RedrawingDisabled = 0; + // avoid calling update_screen() in vgetorpeek() + p_lz = false; + if (new_start != NULL) { /* There already was a substitution, we would * like to show this to the user. We cannot @@ -3736,7 +3758,8 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, /* clear the question */ msg_didout = FALSE; /* don't scroll up */ msg_col = 0; - gotocmdline(TRUE); + gotocmdline(true); + p_lz = save_p_lz; // restore the line if (orig_line != NULL) { diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 380237c822..e9046da800 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1,6 +1,9 @@ local bit = require 'bit' +local module = {} + -- Description of the values below is contained in ex_cmds_defs.h file. +-- "EX_" prefix is omitted. local RANGE = 0x001 local BANG = 0x002 local EXTRA = 0x004 @@ -14,23 +17,26 @@ local REGSTR = 0x200 local COUNT = 0x400 local NOTRLCOM = 0x800 local ZEROR = 0x1000 -local USECTRLV = 0x2000 -local NOTADR = 0x4000 -local EDITCMD = 0x8000 -local BUFNAME = 0x10000 -local BUFUNL = 0x20000 -local ARGOPT = 0x40000 -local SBOXOK = 0x80000 -local CMDWIN = 0x100000 -local MODIFY = 0x200000 -local EXFLAGS = 0x400000 -local RESTRICT = 0x800000 +local CTRLV = 0x2000 +local CMDARG = 0x4000 +local BUFNAME = 0x8000 +local BUFUNL = 0x10000 +local ARGOPT = 0x20000 +local SBOXOK = 0x40000 +local CMDWIN = 0x80000 +local MODIFY = 0x100000 +local FLAGS = 0x200000 local FILES = bit.bor(XFILE, EXTRA) local WORD1 = bit.bor(EXTRA, NOSPC) local FILE1 = bit.bor(FILES, NOSPC) +module.flags = { + RANGE = RANGE, + DFLALL = DFLALL, +} + -- The following table is described in ex_cmds_defs.h file. -return { +module.cmds = { { command='append', flags=bit.bor(BANG, RANGE, ZEROR, TRLBAR, CMDWIN, MODIFY), @@ -39,247 +45,247 @@ return { }, { command='abbreviate', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='abclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_abclear', }, { command='aboveleft', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='all', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_all', }, { command='amenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='anoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='args', - flags=bit.bor(BANG, FILES, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILES, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_args', }, { command='argadd', - flags=bit.bor(BANG, RANGE, NOTADR, ZEROR, FILES, TRLBAR), + flags=bit.bor(BANG, RANGE, ZEROR, FILES, TRLBAR), addr_type='ADDR_ARGUMENTS', func='ex_argadd', }, { command='argdelete', - flags=bit.bor(BANG, RANGE, NOTADR, FILES, TRLBAR), + flags=bit.bor(BANG, RANGE, FILES, TRLBAR), addr_type='ADDR_ARGUMENTS', func='ex_argdelete', }, { command='argdo', - flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), addr_type='ADDR_ARGUMENTS', func='ex_listdo', }, { command='argedit', - flags=bit.bor(BANG, NEEDARG, RANGE, NOTADR, ZEROR, FILES, EDITCMD, ARGOPT, TRLBAR), + flags=bit.bor(BANG, NEEDARG, RANGE, ZEROR, FILES, CMDARG, ARGOPT, TRLBAR), addr_type='ADDR_ARGUMENTS', func='ex_argedit', }, { command='argglobal', - flags=bit.bor(BANG, FILES, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILES, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_args', }, { command='arglocal', - flags=bit.bor(BANG, FILES, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILES, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_args', }, { command='argument', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, EXTRA, EDITCMD, ARGOPT, TRLBAR), + flags=bit.bor(BANG, RANGE, COUNT, EXTRA, CMDARG, ARGOPT, TRLBAR), addr_type='ADDR_ARGUMENTS', func='ex_argument', }, { command='ascii', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='do_ascii', }, { command='autocmd', - flags=bit.bor(BANG, EXTRA, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, EXTRA, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_autocmd', }, { command='augroup', flags=bit.bor(BANG, WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_autocmd', }, { command='aunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='buffer', - flags=bit.bor(BANG, RANGE, NOTADR, BUFNAME, BUFUNL, COUNT, EXTRA, EDITCMD, TRLBAR), + flags=bit.bor(BANG, RANGE, BUFNAME, BUFUNL, COUNT, EXTRA, CMDARG, TRLBAR), addr_type='ADDR_BUFFERS', func='ex_buffer', }, { command='bNext', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bprevious', }, { command='ball', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_buffer_all', }, { command='badd', - flags=bit.bor(NEEDARG, FILE1, EDITCMD, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(NEEDARG, FILE1, CMDARG, TRLBAR, CMDWIN), + addr_type='ADDR_NONE', func='ex_edit', }, { command='bdelete', - flags=bit.bor(BANG, RANGE, NOTADR, BUFNAME, COUNT, EXTRA, TRLBAR), + flags=bit.bor(BANG, RANGE, BUFNAME, COUNT, EXTRA, TRLBAR), addr_type='ADDR_BUFFERS', func='ex_bunload', }, { command='behave', flags=bit.bor(NEEDARG, WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_behave', }, { command='belowright', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='bfirst', - flags=bit.bor(BANG, RANGE, NOTADR, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_brewind', }, { command='blast', - flags=bit.bor(BANG, RANGE, NOTADR, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_blast', }, { command='bmodified', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bmodified', }, { command='bnext', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bnext', }, { command='botright', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='bprevious', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bprevious', }, { command='brewind', - flags=bit.bor(BANG, RANGE, NOTADR, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_brewind', }, { command='break', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_break', }, { command='breakadd', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_breakadd', }, { command='breakdel', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_breakdel', }, { command='breaklist', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_breaklist', }, { command='browse', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='buffers', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='buflist_list', }, { command='bufdo', - flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), addr_type='ADDR_BUFFERS', func='ex_listdo', }, { command='bunload', - flags=bit.bor(BANG, RANGE, NOTADR, BUFNAME, COUNT, EXTRA, TRLBAR), + flags=bit.bor(BANG, RANGE, BUFNAME, COUNT, EXTRA, TRLBAR), addr_type='ADDR_LOADED_BUFFERS', func='ex_bunload', }, { command='bwipeout', - flags=bit.bor(BANG, RANGE, NOTADR, BUFNAME, BUFUNL, COUNT, EXTRA, TRLBAR), + flags=bit.bor(BANG, RANGE, BUFNAME, BUFUNL, COUNT, EXTRA, TRLBAR), addr_type='ADDR_BUFFERS', func='ex_bunload', }, @@ -291,53 +297,59 @@ return { }, { command='cNext', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='cNfile', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='cabbrev', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='cabclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_abclear', }, { command='cabove', - flags=bit.bor(RANGE, TRLBAR), - addr_type='ADDR_OTHER ', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='ex_cbelow', }, { command='caddbuffer', - flags=bit.bor(RANGE, NOTADR, WORD1, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, WORD1, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cbuffer', }, { command='caddexpr', flags=bit.bor(NEEDARG, WORD1, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cexpr', }, { command='caddfile', flags=bit.bor(TRLBAR, FILE1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cfile', }, { + command='cafter', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', + func='ex_cbelow', + }, + { command='call', flags=bit.bor(RANGE, NEEDARG, EXTRA, NOTRLCOM, SBOXOK, CMDWIN), addr_type='ADDR_LINES', @@ -346,49 +358,55 @@ return { { command='catch', flags=bit.bor(EXTRA, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_catch', }, { command='cbuffer', - flags=bit.bor(BANG, RANGE, NOTADR, WORD1, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, WORD1, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cbuffer', }, { + command='cbefore', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', + func='ex_cbelow', + }, + { command='cbelow', - flags=bit.bor(RANGE, TRLBAR), - addr_type='ADDR_OTHER ', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='ex_cbelow', }, { command='cbottom', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cbottom', }, { command='cc', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_QUICKFIX', func='ex_cc', }, { command='cclose', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(TRLBAR), + addr_type='ADDR_NONE', func='ex_cclose', }, { command='cd', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cd', }, { command='cdo', - flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), - addr_type='ADDR_QUICKFIX', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), + addr_type='ADDR_QUICKFIX_VALID', func='ex_listdo', }, { @@ -400,159 +418,159 @@ return { { command='cexpr', flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, BANG), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cexpr', }, { command='cfile', flags=bit.bor(TRLBAR, FILE1, BANG), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cfile', }, -- Even though 'cfdo' is alphabetically lower than 'cfile', it is after -- 'cfile' in this cmd list to support the existing ":cf" abbreviation. { command='cfdo', - flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), - addr_type='ADDR_QUICKFIX', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), + addr_type='ADDR_QUICKFIX_VALID', func='ex_listdo', }, { command='cfirst', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cc', }, { command='cgetfile', flags=bit.bor(TRLBAR, FILE1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cfile', }, { command='cgetbuffer', - flags=bit.bor(RANGE, NOTADR, WORD1, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, WORD1, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cbuffer', }, { command='cgetexpr', flags=bit.bor(NEEDARG, WORD1, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cexpr', }, { command='chdir', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cd', }, { command='changes', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_changes', }, { command='checkhealth', flags=bit.bor(EXTRA, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_checkhealth', }, { command='checkpath', flags=bit.bor(TRLBAR, BANG, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_checkpath', }, { command='checktime', - flags=bit.bor(RANGE, NOTADR, BUFNAME, COUNT, EXTRA, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BUFNAME, COUNT, EXTRA, TRLBAR), + addr_type='ADDR_OTHER', func='ex_checktime', }, { command='chistory', - flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='qf_history', }, { command='clist', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='qf_list', }, { command='clast', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cc', }, { command='close', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, TRLBAR, CMDWIN), + flags=bit.bor(BANG, RANGE, COUNT, TRLBAR, CMDWIN), addr_type='ADDR_WINDOWS', func='ex_close', }, { command='clearjumps', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_clearjumps', }, { command='cmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='cmapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='cmenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='cnext', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='cnewer', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='qf_age', }, { command='cnfile', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='cnoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='cnoreabbrev', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='cnoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { @@ -563,116 +581,116 @@ return { }, { command='colder', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='qf_age', }, { command='colorscheme', flags=bit.bor(WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_colorscheme', }, { command='command', - flags=bit.bor(EXTRA, BANG, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, BANG, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_command', }, { command='comclear', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_comclear', }, { command='compiler', flags=bit.bor(BANG, TRLBAR, WORD1, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_compiler', }, { command='continue', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_continue', }, { command='confirm', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='const', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_const', }, { command='copen', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_copen', }, { command='cprevious', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='cpfile', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_OTHER', func='ex_cnext', }, { command='cquit', - flags=bit.bor(RANGE, NOTADR, COUNT, ZEROR, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, ZEROR, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cquit', }, { command='crewind', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cc', }, { command='cscope', flags=bit.bor(EXTRA, NOTRLCOM, XFILE), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cscope', }, { command='cstag', flags=bit.bor(BANG, TRLBAR, WORD1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cstag', }, { command='cunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='cunabbrev', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='cunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='cwindow', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cwindow', }, { @@ -684,43 +702,43 @@ return { { command='delmarks', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_delmarks', }, { command='debug', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_debug', }, { command='debuggreedy', - flags=bit.bor(RANGE, NOTADR, ZEROR, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, TRLBAR, CMDWIN), + addr_type='ADDR_OTHER', func='ex_debuggreedy', }, { command='delcommand', flags=bit.bor(BANG, NEEDARG, WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_delcommand', }, { command='delfunction', flags=bit.bor(BANG, NEEDARG, WORD1, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_delfunction', }, { command='display', flags=bit.bor(EXTRA, NOTRLCOM, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_display', }, { command='diffupdate', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_diffupdate', }, { @@ -732,13 +750,13 @@ return { { command='diffoff', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_diffoff', }, { command='diffpatch', flags=bit.bor(EXTRA, FILE1, TRLBAR, MODIFY), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_diffpatch', }, { @@ -750,19 +768,19 @@ return { { command='diffsplit', flags=bit.bor(EXTRA, FILE1, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_diffsplit', }, { command='diffthis', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_diffthis', }, { command='digraphs', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_digraphs', }, { @@ -780,19 +798,19 @@ return { { command='doautocmd', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_doautocmd', }, { command='doautoall', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_doautoall', }, { command='drop', - flags=bit.bor(FILES, EDITCMD, NEEDARG, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(FILES, CMDARG, NEEDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_drop', }, { @@ -809,110 +827,110 @@ return { }, { command='edit', - flags=bit.bor(BANG, FILE1, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_edit', }, { command='earlier', flags=bit.bor(TRLBAR, EXTRA, NOSPC, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_later', }, { command='echo', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_echo', }, { command='echoerr', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_execute', }, { command='echohl', flags=bit.bor(EXTRA, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_echohl', }, { command='echomsg', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_execute', }, { command='echon', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_echo', }, { command='else', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_else', }, { command='elseif', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_else', }, { command='emenu', - flags=bit.bor(NEEDARG, EXTRA, TRLBAR, NOTRLCOM, RANGE, NOTADR, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(NEEDARG, EXTRA, TRLBAR, NOTRLCOM, RANGE, CMDWIN), + addr_type='ADDR_OTHER', func='ex_emenu', }, { command='endif', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_endif', }, { command='endfunction', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_endfunction', }, { command='endfor', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_endwhile', }, { command='endtry', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_endtry', }, { command='endwhile', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_endwhile', }, { command='enew', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_edit', }, { command='ex', - flags=bit.bor(BANG, FILE1, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_edit', }, { command='execute', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_execute', }, { @@ -924,55 +942,55 @@ return { { command='exusage', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_exusage', }, { command='file', - flags=bit.bor(RANGE, NOTADR, ZEROR, BANG, FILE1, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, BANG, FILE1, TRLBAR), + addr_type='ADDR_OTHER', func='ex_file', }, { command='files', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='buflist_list', }, { command='filetype', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_filetype', }, { command='filter', flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='find', - flags=bit.bor(RANGE, NOTADR, BANG, FILE1, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, FILE1, CMDARG, ARGOPT, TRLBAR, NEEDARG), + addr_type='ADDR_OTHER', func='ex_find', }, { command='finally', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_finally', }, { command='finish', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_finish', }, { command='first', - flags=bit.bor(EXTRA, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_rewind', }, { @@ -1008,13 +1026,13 @@ return { { command='for', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_while', }, { command='function', flags=bit.bor(EXTRA, BANG, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_function', }, { @@ -1025,56 +1043,56 @@ return { }, { command='goto', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, SBOXOK, CMDWIN), + addr_type='ADDR_OTHER', func='ex_goto', }, { command='grep', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_make', }, { command='grepadd', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_make', }, { command='gui', - flags=bit.bor(BANG, FILES, EDITCMD, ARGOPT, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILES, CMDARG, ARGOPT, TRLBAR, CMDWIN), + addr_type='ADDR_NONE', func='ex_nogui', }, { command='gvim', - flags=bit.bor(BANG, FILES, EDITCMD, ARGOPT, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILES, CMDARG, ARGOPT, TRLBAR, CMDWIN), + addr_type='ADDR_NONE', func='ex_nogui', }, { command='help', flags=bit.bor(BANG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_help', }, { command='helpclose', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_helpclose', }, { command='helpgrep', flags=bit.bor(EXTRA, NOTRLCOM, NEEDARG), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_helpgrep', }, { command='helptags', flags=bit.bor(NEEDARG, FILES, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_helptags', }, { @@ -1086,19 +1104,19 @@ return { { command='highlight', flags=bit.bor(BANG, EXTRA, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_highlight', }, { command='hide', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, EXTRA, TRLBAR), + flags=bit.bor(BANG, RANGE, COUNT, EXTRA, TRLBAR), addr_type='ADDR_WINDOWS', func='ex_hide', }, { command='history', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_history', }, { @@ -1109,20 +1127,20 @@ return { }, { command='iabbrev', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='iabclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_abclear', }, { command='if', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_if', }, { @@ -1139,44 +1157,44 @@ return { }, { command='imap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='imapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='imenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='inoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='inoreabbrev', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='inoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='intro', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_intro', }, { @@ -1193,32 +1211,32 @@ return { }, { command='iunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='iunabbrev', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='iunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='join', - flags=bit.bor(BANG, RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN, MODIFY), + flags=bit.bor(BANG, RANGE, WHOLEFOLD, COUNT, FLAGS, TRLBAR, CMDWIN, MODIFY), addr_type='ADDR_LINES', func='ex_join', }, { command='jumps', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_jumps', }, { @@ -1230,133 +1248,145 @@ return { { command='keepmarks', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='keepjumps', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='keeppatterns', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='keepalt', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='list', - flags=bit.bor(RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN), + flags=bit.bor(RANGE, WHOLEFOLD, COUNT, FLAGS, TRLBAR, CMDWIN), addr_type='ADDR_LINES', func='ex_print', }, { command='lNext', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='lNfile', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='last', - flags=bit.bor(EXTRA, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_last', }, { command='labove', - flags=bit.bor(RANGE, TRLBAR), - addr_type='ADDR_OTHER ', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='ex_cbelow', }, { command='language', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_language', }, { command='laddexpr', flags=bit.bor(NEEDARG, WORD1, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cexpr', }, { command='laddbuffer', - flags=bit.bor(RANGE, NOTADR, WORD1, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, WORD1, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cbuffer', }, { command='laddfile', flags=bit.bor(TRLBAR, FILE1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cfile', }, { + command='lafter', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', + func='ex_cbelow', + }, + { command='later', flags=bit.bor(TRLBAR, EXTRA, NOSPC, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_later', }, { command='lbuffer', - flags=bit.bor(BANG, RANGE, NOTADR, WORD1, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, WORD1, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cbuffer', }, { + command='lbefore', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', + func='ex_cbelow', + }, + { command='lbelow', - flags=bit.bor(RANGE, TRLBAR), - addr_type='ADDR_OTHER ', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='ex_cbelow', }, { command='lbottom', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cbottom', }, { command='lcd', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cd', }, { command='lchdir', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cd', }, { command='lclose', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cclose', }, { command='lcscope', flags=bit.bor(EXTRA, NOTRLCOM, XFILE), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cscope', }, { command='ldo', - flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), - addr_type='ADDR_QUICKFIX', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), + addr_type='ADDR_QUICKFIX_VALID', func='ex_listdo', }, { @@ -1368,249 +1398,249 @@ return { { command='leftabove', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='let', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_let', }, { command='lexpr', flags=bit.bor(NEEDARG, WORD1, NOTRLCOM, BANG), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cexpr', }, { command='lfile', flags=bit.bor(TRLBAR, FILE1, BANG), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cfile', }, -- Even though 'lfdo' is alphabetically lower than 'lfile', it is after -- 'lfile' in this cmd list to support the existing ":lf" abbreviation. { command='lfdo', - flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), - addr_type='ADDR_QUICKFIX', + flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), + addr_type='ADDR_QUICKFIX_VALID', func='ex_listdo', }, { command='lfirst', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cc', }, { command='lgetfile', flags=bit.bor(TRLBAR, FILE1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cfile', }, { command='lgetbuffer', - flags=bit.bor(RANGE, NOTADR, WORD1, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, WORD1, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cbuffer', }, { command='lgetexpr', flags=bit.bor(NEEDARG, WORD1, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cexpr', }, { command='lgrep', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_make', }, { command='lgrepadd', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_make', }, { command='lhelpgrep', flags=bit.bor(EXTRA, NOTRLCOM, NEEDARG), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_helpgrep', }, { command='lhistory', - flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='qf_history', }, { command='ll', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_QUICKFIX', func='ex_cc', }, { command='llast', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cc', }, { command='llist', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='qf_list', }, { command='lmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='lmapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='lmake', flags=bit.bor(BANG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_make', }, { command='lnoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='lnext', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='lnewer', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='qf_age', }, { command='lnfile', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='loadview', flags=bit.bor(FILE1, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_loadview', }, { command='loadkeymap', flags=bit.bor(CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_loadkeymap', }, { command='lockmarks', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='lockvar', flags=bit.bor(BANG, EXTRA, NEEDARG, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_lockvar', }, { command='lolder', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_UNSIGNED', func='qf_age', }, { command='lopen', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_copen', }, { command='lprevious', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cnext', }, { command='lpfile', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_OTHER', func='ex_cnext', }, { command='lrewind', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR, BANG), + addr_type='ADDR_UNSIGNED', func='ex_cc', }, { command='ltag', - flags=bit.bor(NOTADR, TRLBAR, BANG, WORD1), - addr_type='ADDR_LINES', + flags=bit.bor(TRLBAR, BANG, WORD1), + addr_type='ADDR_NONE', func='ex_tag', }, { command='lunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='lua', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_lua', }, { command='luado', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_luado', }, { command='luafile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_luafile', }, { command='lvimgrep', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_vimgrep', }, { command='lvimgrepadd', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_vimgrep', }, { command='lwindow', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_cwindow', }, { command='ls', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='buflist_list', }, { @@ -1628,43 +1658,43 @@ return { { command='make', flags=bit.bor(BANG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_make', }, { command='map', - flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='mapclear', flags=bit.bor(EXTRA, BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='marks', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_marks', }, { command='match', - flags=bit.bor(RANGE, NOTADR, EXTRA, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, EXTRA, CMDWIN), + addr_type='ADDR_OTHER', func='ex_match', }, { command='menu', - flags=bit.bor(RANGE, NOTADR, ZEROR, BANG, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, BANG, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='menutranslate', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menutranslate', }, { @@ -1676,37 +1706,37 @@ return { { command='mkexrc', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mkrc', }, { command='mksession', flags=bit.bor(BANG, FILE1, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mkrc', }, { command='mkspell', flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mkspell', }, { command='mkvimrc', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mkrc', }, { command='mkview', flags=bit.bor(BANG, FILE1, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mkrc', }, { command='mode', flags=bit.bor(WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mode', }, { @@ -1723,260 +1753,260 @@ return { }, { command='next', - flags=bit.bor(RANGE, NOTADR, BANG, FILES, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, FILES, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_next', }, { command='new', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, RANGE, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_splitview', }, { command='nmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='nmapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='nmenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='nnoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='nnoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='noremap', - flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='noautocmd', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='nohlsearch', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_nohlsearch', }, { command='noreabbrev', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='noremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, BANG, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, BANG, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='noswapfile', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='normal', - flags=bit.bor(RANGE, BANG, EXTRA, NEEDARG, NOTRLCOM, USECTRLV, SBOXOK, CMDWIN), + flags=bit.bor(RANGE, BANG, EXTRA, NEEDARG, NOTRLCOM, CTRLV, SBOXOK, CMDWIN), addr_type='ADDR_LINES', func='ex_normal', }, { command='number', - flags=bit.bor(RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN), + flags=bit.bor(RANGE, WHOLEFOLD, COUNT, FLAGS, TRLBAR, CMDWIN), addr_type='ADDR_LINES', func='ex_print', }, { command='nunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='nunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='oldfiles', flags=bit.bor(BANG, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_oldfiles', }, { command='omap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='omapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='omenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='only', - flags=bit.bor(BANG, NOTADR, RANGE, COUNT, TRLBAR), + flags=bit.bor(BANG, RANGE, COUNT, TRLBAR), addr_type='ADDR_WINDOWS', func='ex_only', }, { command='onoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='onoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='options', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_options', }, { command='ounmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='ounmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='ownsyntax', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_ownsyntax', }, { command='print', - flags=bit.bor(RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN, SBOXOK), + flags=bit.bor(RANGE, WHOLEFOLD, COUNT, FLAGS, TRLBAR, CMDWIN, SBOXOK), addr_type='ADDR_LINES', func='ex_print', }, { command='packadd', flags=bit.bor(BANG, FILE1, NEEDARG, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_packadd', }, { command='packloadall', flags=bit.bor(BANG, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_packloadall', }, { command='pclose', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_pclose', }, { command='perl', - flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, SBOXOK, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, SBOXOK, CMDWIN), addr_type='ADDR_LINES', func='ex_perl', }, { command='perldo', - flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_perldo', }, { command='perlfile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_perlfile', }, { command='pedit', - flags=bit.bor(BANG, FILE1, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_pedit', }, { command='pop', - flags=bit.bor(RANGE, NOTADR, BANG, COUNT, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, COUNT, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_tag', }, { command='popup', flags=bit.bor(NEEDARG, EXTRA, BANG, TRLBAR, NOTRLCOM, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_ni', }, { command='ppop', - flags=bit.bor(RANGE, NOTADR, BANG, COUNT, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, COUNT, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_ptag', }, { command='preserve', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_preserve', }, { command='previous', - flags=bit.bor(EXTRA, RANGE, NOTADR, COUNT, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, RANGE, COUNT, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_previous', }, { command='profile', flags=bit.bor(BANG, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_profile', }, { command='profdel', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_breakdel', }, { @@ -1987,56 +2017,56 @@ return { }, { command='ptag', - flags=bit.bor(RANGE, NOTADR, BANG, WORD1, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, WORD1, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_ptag', }, { command='ptNext', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_ptag', }, { command='ptfirst', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_ptag', }, { command='ptjump', flags=bit.bor(BANG, TRLBAR, WORD1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_ptag', }, { command='ptlast', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_ptag', }, { command='ptnext', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_ptag', }, { command='ptprevious', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_ptag', }, { command='ptrewind', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_ptag', }, { command='ptselect', flags=bit.bor(BANG, TRLBAR, WORD1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_ptag', }, { @@ -2048,91 +2078,91 @@ return { { command='pwd', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_pwd', }, { command='python', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_python', }, { command='pydo', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_pydo', }, { command='pyfile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_pyfile', }, { command='py3', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_python3', }, { command='py3do', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_pydo3', }, { command='python3', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_python3', }, { command='py3file', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_py3file', }, { command='pyx', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_pyx', }, { command='pyxdo', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_pyxdo', }, { command='pythonx', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_pyx', }, { command='pyxfile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_pyxfile', }, { command='quit', - flags=bit.bor(BANG, RANGE, COUNT, NOTADR, TRLBAR, CMDWIN), + flags=bit.bor(BANG, RANGE, COUNT, TRLBAR, CMDWIN), addr_type='ADDR_WINDOWS', func='ex_quit', }, { command='quitall', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_quit_all', }, { command='qall', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_quit_all', }, { @@ -2144,49 +2174,49 @@ return { { command='recover', flags=bit.bor(BANG, FILE1, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_recover', }, { command='redo', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_redo', }, { command='redir', flags=bit.bor(BANG, FILES, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_redir', }, { command='redraw', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_redraw', }, { command='redrawstatus', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_redrawstatus', }, { command='redrawtabline', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_redrawtabline', }, { command='registers', flags=bit.bor(EXTRA, NOTRLCOM, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_display', }, { command='resize', - flags=bit.bor(RANGE, NOTADR, TRLBAR, WORD1, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, TRLBAR, WORD1, CMDWIN), + addr_type='ADDR_OTHER', func='ex_resize', }, { @@ -2198,13 +2228,13 @@ return { { command='return', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_return', }, { command='rewind', - flags=bit.bor(EXTRA, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_rewind', }, { @@ -2216,49 +2246,49 @@ return { { command='rightbelow', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='rshada', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_shada', }, { command='runtime', flags=bit.bor(BANG, NEEDARG, FILES, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_runtime', }, { command='rundo', flags=bit.bor(NEEDARG, FILE1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_rundo', }, { command='ruby', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_ruby', }, { command='rubydo', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_rubydo', }, { command='rubyfile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), addr_type='ADDR_LINES', func='ex_rubyfile', }, { command='rviminfo', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_shada', }, { @@ -2269,170 +2299,170 @@ return { }, { command='sNext', - flags=bit.bor(EXTRA, RANGE, NOTADR, COUNT, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, RANGE, COUNT, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_previous', }, { command='sargument', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, EXTRA, EDITCMD, ARGOPT, TRLBAR), + flags=bit.bor(BANG, RANGE, COUNT, EXTRA, CMDARG, ARGOPT, TRLBAR), addr_type='ADDR_ARGUMENTS', func='ex_argument', }, { command='sall', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_all', }, { command='sandbox', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='saveas', - flags=bit.bor(BANG, DFLALL, FILE1, ARGOPT, CMDWIN, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, ARGOPT, CMDWIN, TRLBAR), + addr_type='ADDR_NONE', func='ex_write', }, { command='sbuffer', - flags=bit.bor(BANG, RANGE, NOTADR, BUFNAME, BUFUNL, COUNT, EXTRA, EDITCMD, TRLBAR), + flags=bit.bor(BANG, RANGE, BUFNAME, BUFUNL, COUNT, EXTRA, CMDARG, TRLBAR), addr_type='ADDR_BUFFERS', func='ex_buffer', }, { command='sbNext', - flags=bit.bor(RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bprevious', }, { command='sball', - flags=bit.bor(RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_buffer_all', }, { command='sbfirst', - flags=bit.bor(EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(CMDARG, TRLBAR), + addr_type='ADDR_NONE', func='ex_brewind', }, { command='sblast', - flags=bit.bor(EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(CMDARG, TRLBAR), + addr_type='ADDR_NONE', func='ex_blast', }, { command='sbmodified', - flags=bit.bor(RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bmodified', }, { command='sbnext', - flags=bit.bor(RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bnext', }, { command='sbprevious', - flags=bit.bor(RANGE, NOTADR, COUNT, EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, CMDARG, TRLBAR), + addr_type='ADDR_OTHER', func='ex_bprevious', }, { command='sbrewind', - flags=bit.bor(EDITCMD, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(CMDARG, TRLBAR), + addr_type='ADDR_NONE', func='ex_brewind', }, { command='scriptnames', - flags=bit.bor(BANG, RANGE, NOTADR, COUNT, TRLBAR, CMDWIN), + flags=bit.bor(BANG, RANGE, COUNT, TRLBAR, CMDWIN), addr_type='ADDR_OTHER', func='ex_scriptnames', }, { command='scriptencoding', flags=bit.bor(WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_scriptencoding', }, { command='scscope', flags=bit.bor(EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_scscope', }, { command='set', flags=bit.bor(TRLBAR, EXTRA, CMDWIN, SBOXOK), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_set', }, { command='setfiletype', flags=bit.bor(TRLBAR, EXTRA, NEEDARG, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_setfiletype', }, { command='setglobal', flags=bit.bor(TRLBAR, EXTRA, CMDWIN, SBOXOK), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_set', }, { command='setlocal', flags=bit.bor(TRLBAR, EXTRA, CMDWIN, SBOXOK), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_set', }, { command='sfind', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, RANGE, CMDARG, ARGOPT, TRLBAR, NEEDARG), + addr_type='ADDR_OTHER', func='ex_splitview', }, { command='sfirst', - flags=bit.bor(EXTRA, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_rewind', }, { command='simalt', flags=bit.bor(NEEDARG, WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_ni', }, { command='sign', - flags=bit.bor(NEEDARG, RANGE, NOTADR, EXTRA, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(NEEDARG, RANGE, EXTRA, CMDWIN), + addr_type='ADDR_OTHER', func='ex_sign', }, { command='silent', flags=bit.bor(NEEDARG, EXTRA, BANG, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='sleep', - flags=bit.bor(RANGE, NOTADR, COUNT, EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, COUNT, EXTRA, TRLBAR, CMDWIN), + addr_type='ADDR_OTHER', func='ex_sleep', }, { command='slast', - flags=bit.bor(EXTRA, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_last', }, { @@ -2443,26 +2473,26 @@ return { }, { command='smap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='smapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='smenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='snext', - flags=bit.bor(RANGE, NOTADR, BANG, FILES, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, FILES, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_next', }, { @@ -2473,20 +2503,20 @@ return { }, { command='snoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='snoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='source', flags=bit.bor(BANG, FILE1, TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_source', }, { @@ -2497,158 +2527,158 @@ return { }, { command='split', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, RANGE, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_splitview', }, { command='spellgood', - flags=bit.bor(BANG, RANGE, NOTADR, NEEDARG, EXTRA, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR), + addr_type='ADDR_OTHER', func='ex_spell', }, { command='spelldump', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_spelldump', }, { command='spellinfo', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_spellinfo', }, { command='spellrepall', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_spellrepall', }, { command='spellundo', - flags=bit.bor(BANG, RANGE, NOTADR, NEEDARG, EXTRA, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR), + addr_type='ADDR_OTHER', func='ex_spell', }, { command='spellwrong', - flags=bit.bor(BANG, RANGE, NOTADR, NEEDARG, EXTRA, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, RANGE, NEEDARG, EXTRA, TRLBAR), + addr_type='ADDR_OTHER', func='ex_spell', }, { command='sprevious', - flags=bit.bor(EXTRA, RANGE, NOTADR, COUNT, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, RANGE, COUNT, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_previous', }, { command='srewind', - flags=bit.bor(EXTRA, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_rewind', }, { command='stop', flags=bit.bor(TRLBAR, BANG, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_stop', }, { command='stag', - flags=bit.bor(RANGE, NOTADR, BANG, WORD1, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, WORD1, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_stag', }, { command='startinsert', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_startinsert', }, { command='startgreplace', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_startinsert', }, { command='startreplace', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_startinsert', }, { command='stopinsert', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_stopinsert', }, { command='stjump', flags=bit.bor(BANG, TRLBAR, WORD1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_stag', }, { command='stselect', flags=bit.bor(BANG, TRLBAR, WORD1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_stag', }, { command='sunhide', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_buffer_all', }, { command='sunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='sunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='suspend', flags=bit.bor(TRLBAR, BANG, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_stop', }, { command='sview', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, RANGE, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_splitview', }, { command='swapname', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_swapname', }, { command='syntax', flags=bit.bor(EXTRA, NOTRLCOM, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_syntax', }, { command='syntime', flags=bit.bor(NEEDARG, WORD1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_syntime', }, { command='syncbind', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_syncbind', }, { @@ -2660,121 +2690,121 @@ return { { command='tcd', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cd', }, { command='tchdir', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_cd', }, { command='tNext', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_tag', }, { command='tag', - flags=bit.bor(RANGE, NOTADR, BANG, WORD1, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, WORD1, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_tag', }, { command='tags', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='do_tags', }, { command='tab', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_TABS', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='tabclose', - flags=bit.bor(BANG, RANGE, NOTADR, ZEROR, EXTRA, NOSPC, TRLBAR, CMDWIN), + flags=bit.bor(BANG, RANGE, ZEROR, EXTRA, NOSPC, TRLBAR, CMDWIN), addr_type='ADDR_TABS', func='ex_tabclose', }, { command='tabdo', - flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), addr_type='ADDR_TABS', func='ex_listdo', }, { command='tabedit', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, ZEROR, EDITCMD, ARGOPT, TRLBAR), + flags=bit.bor(BANG, FILE1, RANGE, ZEROR, CMDARG, ARGOPT, TRLBAR), addr_type='ADDR_TABS', func='ex_splitview', }, { command='tabfind', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, ZEROR, EDITCMD, ARGOPT, NEEDARG, TRLBAR), + flags=bit.bor(BANG, FILE1, RANGE, ZEROR, CMDARG, ARGOPT, NEEDARG, TRLBAR), addr_type='ADDR_TABS', func='ex_splitview', }, { command='tabfirst', flags=bit.bor(TRLBAR), - addr_type='ADDR_TABS', + addr_type='ADDR_NONE', func='ex_tabnext', }, { command='tabmove', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, NOSPC, TRLBAR), + flags=bit.bor(RANGE, ZEROR, EXTRA, NOSPC, TRLBAR), addr_type='ADDR_TABS', func='ex_tabmove', }, { command='tablast', flags=bit.bor(TRLBAR), - addr_type='ADDR_TABS', + addr_type='ADDR_NONE', func='ex_tabnext', }, { command='tabnext', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, NOSPC, TRLBAR), + flags=bit.bor(RANGE, ZEROR, EXTRA, NOSPC, TRLBAR), addr_type='ADDR_TABS', func='ex_tabnext', }, { command='tabnew', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, ZEROR, EDITCMD, ARGOPT, TRLBAR), + flags=bit.bor(BANG, FILE1, RANGE, ZEROR, CMDARG, ARGOPT, TRLBAR), addr_type='ADDR_TABS', func='ex_splitview', }, { command='tabonly', - flags=bit.bor(BANG, RANGE, NOTADR, ZEROR, EXTRA, NOSPC, TRLBAR, CMDWIN), + flags=bit.bor(BANG, RANGE, ZEROR, EXTRA, NOSPC, TRLBAR, CMDWIN), addr_type='ADDR_TABS', func='ex_tabonly', }, { command='tabprevious', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, NOSPC, TRLBAR), + flags=bit.bor(RANGE, ZEROR, EXTRA, NOSPC, TRLBAR), addr_type='ADDR_TABS_RELATIVE', func='ex_tabnext', }, { command='tabNext', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, NOSPC, TRLBAR), + flags=bit.bor(RANGE, ZEROR, EXTRA, NOSPC, TRLBAR), addr_type='ADDR_TABS_RELATIVE', func='ex_tabnext', }, { command='tabrewind', flags=bit.bor(TRLBAR), - addr_type='ADDR_TABS', + addr_type='ADDR_NONE', func='ex_tabnext', }, { command='tabs', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_TABS', + addr_type='ADDR_NONE', func='ex_tabs', }, { @@ -2798,163 +2828,163 @@ return { { command='terminal', flags=bit.bor(BANG, FILES, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_terminal', }, { command='tfirst', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_tag', }, { command='throw', flags=bit.bor(EXTRA, NEEDARG, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_throw', }, { command='tjump', flags=bit.bor(BANG, TRLBAR, WORD1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_tag', }, { command='tlast', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_tag', }, { command='tmenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='tmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='tmapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='tnext', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_tag', }, { command='tnoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='topleft', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='tprevious', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_tag', }, { command='trewind', - flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, TRLBAR, ZEROR), + addr_type='ADDR_OTHER', func='ex_tag', }, { command='try', flags=bit.bor(TRLBAR, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_try', }, { command='tselect', flags=bit.bor(BANG, TRLBAR, WORD1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_tag', }, { command='tunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='tunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='undo', - flags=bit.bor(RANGE, NOTADR, COUNT, ZEROR, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, ZEROR, TRLBAR, CMDWIN), + addr_type='ADDR_OTHER', func='ex_undo', }, { command='undojoin', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_undojoin', }, { command='undolist', flags=bit.bor(TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_undolist', }, { command='unabbreviate', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_abbreviate', }, { command='unhide', - flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, COUNT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_buffer_all', }, { command='unlet', flags=bit.bor(BANG, EXTRA, NEEDARG, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_unlet', }, { command='unlockvar', flags=bit.bor(BANG, EXTRA, NEEDARG, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_lockvar', }, { command='unmap', - flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='unmenu', - flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { command='unsilent', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { @@ -2972,103 +3002,103 @@ return { { command='version', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_version', }, { command='verbose', - flags=bit.bor(NEEDARG, RANGE, NOTADR, EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(NEEDARG, RANGE, EXTRA, NOTRLCOM, SBOXOK, CMDWIN), + addr_type='ADDR_OTHER', func='ex_wrongmodifier', }, { command='vertical', flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wrongmodifier', }, { command='visual', - flags=bit.bor(BANG, FILE1, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_edit', }, { command='view', - flags=bit.bor(BANG, FILE1, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='ex_edit', }, { command='vimgrep', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_vimgrep', }, { command='vimgrepadd', - flags=bit.bor(RANGE, NOTADR, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, NEEDARG, EXTRA, NOTRLCOM, TRLBAR, XFILE), + addr_type='ADDR_OTHER', func='ex_vimgrep', }, { command='viusage', flags=bit.bor(TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_viusage', }, { command='vmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='vmapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='vmenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='vnoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='vnew', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, RANGE, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_splitview', }, { command='vnoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='vsplit', - flags=bit.bor(BANG, FILE1, RANGE, NOTADR, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, RANGE, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_splitview', }, { command='vunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='vunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { @@ -3079,56 +3109,56 @@ return { }, { command='wNext', - flags=bit.bor(RANGE, WHOLEFOLD, NOTADR, BANG, FILE1, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, WHOLEFOLD, BANG, FILE1, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_wnext', }, { command='wall', flags=bit.bor(BANG, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='do_wqall', }, { command='while', flags=bit.bor(EXTRA, NOTRLCOM, SBOXOK, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_while', }, { command='winsize', flags=bit.bor(EXTRA, NEEDARG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_winsize', }, { command='wincmd', - flags=bit.bor(NEEDARG, WORD1, RANGE, NOTADR, CMDWIN), - addr_type='ADDR_WINDOWS', + flags=bit.bor(NEEDARG, WORD1, RANGE, CMDWIN), + addr_type='ADDR_OTHER', func='ex_wincmd', }, { command='windo', - flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL), addr_type='ADDR_WINDOWS', func='ex_listdo', }, { command='winpos', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_ni', }, { command='wnext', - flags=bit.bor(RANGE, NOTADR, BANG, FILE1, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, FILE1, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_wnext', }, { command='wprevious', - flags=bit.bor(RANGE, NOTADR, BANG, FILE1, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, BANG, FILE1, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_wnext', }, { @@ -3139,26 +3169,26 @@ return { }, { command='wqall', - flags=bit.bor(BANG, FILE1, ARGOPT, DFLALL, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(BANG, FILE1, ARGOPT, TRLBAR), + addr_type='ADDR_NONE', func='do_wqall', }, { command='wshada', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_shada', }, { command='wundo', flags=bit.bor(BANG, NEEDARG, FILE1), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_wundo', }, { command='wviminfo', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_shada', }, { @@ -3170,49 +3200,49 @@ return { { command='xall', flags=bit.bor(BANG, TRLBAR), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='do_wqall', }, { command='xmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='xmapclear', flags=bit.bor(EXTRA, TRLBAR, CMDWIN), - addr_type='ADDR_LINES', + addr_type='ADDR_NONE', func='ex_mapclear', }, { command='xmenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='xnoremap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_map', }, { command='xnoremenu', - flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_OTHER', func='ex_menu', }, { command='xunmap', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_unmap', }, { command='xunmenu', - flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN), + addr_type='ADDR_NONE', func='ex_menu', }, { @@ -3223,7 +3253,7 @@ return { }, { command='z', - flags=bit.bor(RANGE, WHOLEFOLD, EXTRA, EXFLAGS, TRLBAR, CMDWIN), + flags=bit.bor(RANGE, WHOLEFOLD, EXTRA, FLAGS, TRLBAR, CMDWIN), addr_type='ADDR_LINES', func='ex_z', }, @@ -3237,7 +3267,7 @@ return { { command='#', enum='CMD_pound', - flags=bit.bor(RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN), + flags=bit.bor(RANGE, WHOLEFOLD, COUNT, FLAGS, TRLBAR, CMDWIN), addr_type='ADDR_LINES', func='ex_print', }, @@ -3251,21 +3281,21 @@ return { { command='<', enum='CMD_lshift', - flags=bit.bor(RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN, MODIFY), + flags=bit.bor(RANGE, WHOLEFOLD, COUNT, FLAGS, TRLBAR, CMDWIN, MODIFY), addr_type='ADDR_LINES', func='ex_operators', }, { command='=', enum='CMD_equal', - flags=bit.bor(RANGE, TRLBAR, DFLALL, EXFLAGS, CMDWIN), + flags=bit.bor(RANGE, TRLBAR, DFLALL, FLAGS, CMDWIN), addr_type='ADDR_LINES', func='ex_equal', }, { command='>', enum='CMD_rshift', - flags=bit.bor(RANGE, WHOLEFOLD, COUNT, EXFLAGS, TRLBAR, CMDWIN, MODIFY), + flags=bit.bor(RANGE, WHOLEFOLD, COUNT, FLAGS, TRLBAR, CMDWIN, MODIFY), addr_type='ADDR_LINES', func='ex_operators', }, @@ -3278,8 +3308,8 @@ return { }, { command='Next', - flags=bit.bor(EXTRA, RANGE, NOTADR, COUNT, BANG, EDITCMD, ARGOPT, TRLBAR), - addr_type='ADDR_LINES', + flags=bit.bor(EXTRA, RANGE, COUNT, BANG, CMDARG, ARGOPT, TRLBAR), + addr_type='ADDR_OTHER', func='ex_previous', }, { @@ -3290,3 +3320,5 @@ return { func='ex_substitute', }, } + +return module diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index bde584d27e..c400975108 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -2113,7 +2113,7 @@ void ex_listdo(exarg_T *eap) } } else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) { - qf_size = qf_get_size(eap); + qf_size = qf_get_valid_size(eap); assert(eap->line1 >= 0); if (qf_size == 0 || (size_t)eap->line1 > qf_size) { buf = NULL; diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 5613ae4b8c..ca84d375ce 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -36,35 +36,34 @@ // 4. Add documentation in ../doc/xxx.txt. Add a tag for both the short and // long name of the command. -#define RANGE 0x001 // allow a linespecs -#define BANG 0x002 // allow a ! after the command name -#define EXTRA 0x004 // allow extra args after command name -#define XFILE 0x008 // expand wildcards in extra part -#define NOSPC 0x010 // no spaces allowed in the extra part -#define DFLALL 0x020 // default file range is 1,$ -#define WHOLEFOLD 0x040 // extend range to include whole fold also - // when less than two numbers given -#define NEEDARG 0x080 // argument required -#define TRLBAR 0x100 // check for trailing vertical bar -#define REGSTR 0x200 // allow "x for register designation -#define COUNT 0x400 // allow count in argument, after command -#define NOTRLCOM 0x800 // no trailing comment allowed -#define ZEROR 0x1000 // zero line number allowed -#define USECTRLV 0x2000 // do not remove CTRL-V from argument -#define NOTADR 0x4000 // number before command is not an address -#define EDITCMD 0x8000 // allow "+command" argument -#define BUFNAME 0x10000 // accepts buffer name -#define BUFUNL 0x20000 // accepts unlisted buffer too -#define ARGOPT 0x40000 // allow "++opt=val" argument -#define SBOXOK 0x80000 // allowed in the sandbox -#define CMDWIN 0x100000 // allowed in cmdline window; when missing - // disallows editing another buffer when - // curbuf_lock is set -#define MODIFY 0x200000 // forbidden in non-'modifiable' buffer -#define EXFLAGS 0x400000 // allow flags after count in argument -#define FILES (XFILE | EXTRA) // multiple extra files allowed -#define WORD1 (EXTRA | NOSPC) // one extra word allowed -#define FILE1 (FILES | NOSPC) // 1 file allowed, defaults to current file +#define EX_RANGE 0x001 // allow a linespecs +#define EX_BANG 0x002 // allow a ! after the command name +#define EX_EXTRA 0x004 // allow extra args after command name +#define EX_XFILE 0x008 // expand wildcards in extra part +#define EX_NOSPC 0x010 // no spaces allowed in the extra part +#define EX_DFLALL 0x020 // default file range is 1,$ +#define EX_WHOLEFOLD 0x040 // extend range to include whole fold also + // when less than two numbers given +#define EX_NEEDARG 0x080 // argument required +#define EX_TRLBAR 0x100 // check for trailing vertical bar +#define EX_REGSTR 0x200 // allow "x for register designation +#define EX_COUNT 0x400 // allow count in argument, after command +#define EX_NOTRLCOM 0x800 // no trailing comment allowed +#define EX_ZEROR 0x1000 // zero line number allowed +#define EX_CTRLV 0x2000 // do not remove CTRL-V from argument +#define EX_CMDARG 0x4000 // allow "+command" argument +#define EX_BUFNAME 0x8000 // accepts buffer name +#define EX_BUFUNL 0x10000 // accepts unlisted buffer too +#define EX_ARGOPT 0x20000 // allow "++opt=val" argument +#define EX_SBOXOK 0x40000 // allowed in the sandbox +#define EX_CMDWIN 0x80000 // allowed in cmdline window; when missing + // disallows editing another buffer when + // curbuf_lock is set +#define EX_MODIFY 0x100000 // forbidden in non-'modifiable' buffer +#define EX_FLAGS 0x200000 // allow flags after count in argument +#define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed +#define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file +#define EX_WORD1 (EX_EXTRA | EX_NOSPC) // one extra word allowed // values for cmd_addr_type typedef enum { @@ -75,8 +74,10 @@ typedef enum { ADDR_BUFFERS, // buffer number ADDR_TABS, // tab page number ADDR_TABS_RELATIVE, // Tab page that only relative + ADDR_QUICKFIX_VALID, // quickfix list valid entry number ADDR_QUICKFIX, // quickfix list entry number - ADDR_OTHER, // something else + ADDR_UNSIGNED, // positive count or zero, defaults to 1 + ADDR_OTHER, // something else, use line number for '$', '%', etc. ADDR_NONE // no range used } cmd_addr_T; @@ -153,7 +154,7 @@ struct exarg { int addr_count; ///< the number of addresses given linenr_T line1; ///< the first line number linenr_T line2; ///< the second line number or count - int addr_type; ///< type of the count/range + cmd_addr_T addr_type; ///< type of the count/range int flags; ///< extra flags after count: EXFLAG_ char_u *do_ecmd_cmd; ///< +command arg to be used in edited file linenr_T do_ecmd_lnum; ///< the line number in an edited file diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 003c78b241..ccf7dd0f68 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1086,7 +1086,10 @@ static int compute_buffer_local_count(int addr_type, int lnum, int offset) return buf->b_fnum; } -static int current_win_nr(win_T *win) +// Return the window number of "win". +// When "win" is NULL return the number of windows. +static int current_win_nr(const win_T *win) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { int nr = 0; @@ -1163,7 +1166,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap) case 'd': case Ctrl_D: // window size or any count - eap->addr_type = ADDR_LINES; // -V1037 + eap->addr_type = ADDR_OTHER; // -V1037 break; case Ctrl_HAT: @@ -1199,7 +1202,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap) case '=': case CAR: // no count - eap->addr_type = 0; + eap->addr_type = ADDR_NONE; break; } } @@ -1380,6 +1383,10 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (ea.cmdidx == CMD_wincmd && p != NULL) { get_wincmd_addr_type(skipwhite(p), &ea); } + // :.cc in quickfix window uses line number + if ((ea.cmdidx == CMD_cc || ea.cmdidx == CMD_ll) && bt_quickfix(curbuf)) { + ea.addr_type = ADDR_OTHER; + } } ea.cmd = cmd; @@ -1411,7 +1418,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, } if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) { ea.cmdidx = CMD_print; - ea.argt = RANGE | COUNT | TRLBAR; + ea.argt = EX_RANGE | EX_COUNT | EX_TRLBAR; if ((errormsg = invalid_range(&ea)) == NULL) { correct_range(&ea); ex_print(&ea); @@ -1490,20 +1497,18 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.forceit = false; } - /* - * 6. Parse arguments. - */ + // 6. Parse arguments. Then check for errors. if (!IS_USER_CMDIDX(ea.cmdidx)) { ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt; } if (!ea.skip) { - if (sandbox != 0 && !(ea.argt & SBOXOK)) { + if (sandbox != 0 && !(ea.argt & EX_SBOXOK)) { // Command not allowed in sandbox. errormsg = (char_u *)_(e_sandbox); goto doend; } - if (!MODIFIABLE(curbuf) && (ea.argt & MODIFY) + if (!MODIFIABLE(curbuf) && (ea.argt & EX_MODIFY) // allow :put in terminals && (!curbuf->terminal || ea.cmdidx != CMD_put)) { /* Command not allowed in non-'modifiable' buffer */ @@ -1511,7 +1516,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, goto doend; } - if (text_locked() && !(ea.argt & CMDWIN) + if (text_locked() && !(ea.argt & EX_CMDWIN) && !IS_USER_CMDIDX(ea.cmdidx)) { // Command not allowed when editing the command line. errormsg = (char_u *)_(get_text_locked_msg()); @@ -1522,7 +1527,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, // Do allow ":checktime" (it is postponed). // Do allow ":edit" (check for an argument later). // Do allow ":file" with no arguments (check for an argument later). - if (!(ea.argt & CMDWIN) + if (!(ea.argt & EX_CMDWIN) && ea.cmdidx != CMD_checktime && ea.cmdidx != CMD_edit && ea.cmdidx != CMD_file @@ -1531,14 +1536,14 @@ static char_u * do_one_cmd(char_u **cmdlinep, goto doend; } - if (!ni && !(ea.argt & RANGE) && ea.addr_count > 0) { - /* no range allowed */ + if (!ni && !(ea.argt & EX_RANGE) && ea.addr_count > 0) { + // no range allowed errormsg = (char_u *)_(e_norange); goto doend; } } - if (!ni && !(ea.argt & BANG) && ea.forceit) { /* no <!> allowed */ + if (!ni && !(ea.argt & EX_BANG) && ea.forceit) { // no <!> allowed errormsg = (char_u *)_(e_nobang); goto doend; } @@ -1547,12 +1552,10 @@ static char_u * do_one_cmd(char_u **cmdlinep, * Don't complain about the range if it is not used * (could happen if line_count is accidentally set to 0). */ - if (!ea.skip && !ni) { - /* - * If the range is backwards, ask for confirmation and, if given, swap - * ea.line1 & ea.line2 so it's forwards again. - * When global command is busy, don't ask, will fail below. - */ + if (!ea.skip && !ni && (ea.argt & EX_RANGE)) { + // If the range is backwards, ask for confirmation and, if given, swap + // ea.line1 & ea.line2 so it's forwards again. + // When global command is busy, don't ask, will fail below. if (!global_busy && ea.line1 > ea.line2) { if (msg_silent == 0) { if ((flags & DOCMD_VERBOSE) || exmode_active) { @@ -1571,12 +1574,14 @@ static char_u * do_one_cmd(char_u **cmdlinep, goto doend; } - if ((ea.argt & NOTADR) && ea.addr_count == 0) /* default is 1, not cursor */ + if ((ea.addr_type == ADDR_OTHER) && ea.addr_count == 0) { + // default is 1, not cursor ea.line2 = 1; + } correct_range(&ea); - if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy + if (((ea.argt & EX_WHOLEFOLD) || ea.addr_count >= 2) && !global_busy && ea.addr_type == ADDR_LINES) { // Put the first line at the start of a closed fold, put the last line // at the end of a closed fold. @@ -1610,12 +1615,14 @@ static char_u * do_one_cmd(char_u **cmdlinep, * Check for "++opt=val" argument. * Must be first, allow ":w ++enc=utf8 !cmd" */ - if (ea.argt & ARGOPT) - while (ea.arg[0] == '+' && ea.arg[1] == '+') + if (ea.argt & EX_ARGOPT) { + while (ea.arg[0] == '+' && ea.arg[1] == '+') { if (getargopt(&ea) == FAIL && !ni) { errormsg = (char_u *)_(e_invarg); goto doend; } + } + } if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) { if (*ea.arg == '>') { /* append */ @@ -1654,14 +1661,15 @@ static char_u * do_one_cmd(char_u **cmdlinep, * Check for "+command" argument, before checking for next command. * Don't do this for ":read !cmd" and ":write !cmd". */ - if ((ea.argt & EDITCMD) && !ea.usefilter) + if ((ea.argt & EX_CMDARG) && !ea.usefilter) { ea.do_ecmd_cmd = getargcmd(&ea.arg); + } /* * Check for '|' to separate commands and '"' to start comments. * Don't do this for ":read !cmd" and ":write !cmd". */ - if ((ea.argt & TRLBAR) && !ea.usefilter) { + if ((ea.argt & EX_TRLBAR) && !ea.usefilter) { separate_nextcmd(&ea); } else if (ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal @@ -1688,12 +1696,13 @@ static char_u * do_one_cmd(char_u **cmdlinep, } } - if ((ea.argt & DFLALL) && ea.addr_count == 0) { + if ((ea.argt & EX_DFLALL) && ea.addr_count == 0) { buf_T *buf; ea.line1 = 1; switch (ea.addr_type) { case ADDR_LINES: + case ADDR_OTHER: ea.line2 = curbuf->b_ml.ml_line_count; break; case ADDR_LOADED_BUFFERS: @@ -1728,24 +1737,27 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.line2 = ARGCOUNT; } break; - case ADDR_QUICKFIX: - ea.line2 = qf_get_size(&ea); + case ADDR_QUICKFIX_VALID: + ea.line2 = qf_get_valid_size(&ea); if (ea.line2 == 0) { ea.line2 = 1; } break; case ADDR_NONE: - IEMSG(_("INTERNAL: Cannot use DFLALL with ADDR_NONE")); + case ADDR_UNSIGNED: + case ADDR_QUICKFIX: + IEMSG(_("INTERNAL: Cannot use EX_DFLALL " + "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX")); break; } } - /* accept numbered register only when no count allowed (:put) */ - if ((ea.argt & REGSTR) + // accept numbered register only when no count allowed (:put) + if ((ea.argt & EX_REGSTR) && *ea.arg != NUL /* Do not allow register = for user commands */ && (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=') - && !((ea.argt & COUNT) && ascii_isdigit(*ea.arg))) { + && !((ea.argt & EX_COUNT) && ascii_isdigit(*ea.arg))) { if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put && !IS_USER_CMDIDX(ea.cmdidx)))) { ea.regname = *ea.arg++; @@ -1759,19 +1771,19 @@ static char_u * do_one_cmd(char_u **cmdlinep, } // - // Check for a count. When accepting a BUFNAME, don't use "123foo" as a + // Check for a count. When accepting a EX_BUFNAME, don't use "123foo" as a // count, it's a buffer name. /// - if ((ea.argt & COUNT) && ascii_isdigit(*ea.arg) - && (!(ea.argt & BUFNAME) || *(p = skipdigits(ea.arg)) == NUL + if ((ea.argt & EX_COUNT) && ascii_isdigit(*ea.arg) + && (!(ea.argt & EX_BUFNAME) || *(p = skipdigits(ea.arg)) == NUL || ascii_iswhite(*p))) { n = getdigits_long(&ea.arg, false, -1); ea.arg = skipwhite(ea.arg); - if (n <= 0 && !ni && (ea.argt & ZEROR) == 0) { + if (n <= 0 && !ni && (ea.argt & EX_ZEROR) == 0) { errormsg = (char_u *)_(e_zerocount); goto doend; } - if (ea.argt & NOTADR) { /* e.g. :buffer 2, :sleep 3 */ + if (ea.addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3 ea.line2 = n; if (ea.addr_count == 0) ea.addr_count = 1; @@ -1780,8 +1792,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.line2 += n - 1; ++ea.addr_count; // Be vi compatible: no error message for out of range. - if (ea.addr_type == ADDR_LINES - && ea.line2 > curbuf->b_ml.ml_line_count) { + if (ea.line2 > curbuf->b_ml.ml_line_count) { ea.line2 = curbuf->b_ml.ml_line_count; } } @@ -1790,16 +1801,17 @@ static char_u * do_one_cmd(char_u **cmdlinep, /* * Check for flags: 'l', 'p' and '#'. */ - if (ea.argt & EXFLAGS) + if (ea.argt & EX_FLAGS) { get_flags(&ea); - /* no arguments allowed */ - if (!ni && !(ea.argt & EXTRA) && *ea.arg != NUL - && *ea.arg != '"' && (*ea.arg != '|' || (ea.argt & TRLBAR) == 0)) { + } + if (!ni && !(ea.argt & EX_EXTRA) && *ea.arg != NUL + && *ea.arg != '"' && (*ea.arg != '|' || (ea.argt & EX_TRLBAR) == 0)) { + // no arguments allowed but there is something errormsg = (char_u *)_(e_trailing); goto doend; } - if (!ni && (ea.argt & NEEDARG) && *ea.arg == NUL) { + if (!ni && (ea.argt & EX_NEEDARG) && *ea.arg == NUL) { errormsg = (char_u *)_(e_argreq); goto doend; } @@ -1828,9 +1840,9 @@ static char_u * do_one_cmd(char_u **cmdlinep, case CMD_function: break; - /* Commands that handle '|' themselves. Check: A command should - * either have the TRLBAR flag, appear in this list or appear in - * the list at ":help :bar". */ + // Commands that handle '|' themselves. Check: A command should + // either have the EX_TRLBAR flag, appear in this list or appear in + // the list at ":help :bar". case CMD_aboveleft: case CMD_and: case CMD_belowright: @@ -1901,16 +1913,17 @@ static char_u * do_one_cmd(char_u **cmdlinep, } } - if (ea.argt & XFILE) { - if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL) + if (ea.argt & EX_XFILE) { + if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL) { goto doend; + } } /* * Accept buffer name. Cannot be used at the same time with a buffer * number. Don't do this for a user command. */ - if ((ea.argt & BUFNAME) && *ea.arg != NUL && ea.addr_count == 0 + if ((ea.argt & EX_BUFNAME) && *ea.arg != NUL && ea.addr_count == 0 && !IS_USER_CMDIDX(ea.cmdidx) ) { /* @@ -1926,10 +1939,11 @@ static char_u * do_one_cmd(char_u **cmdlinep, while (p > ea.arg && ascii_iswhite(p[-1])) --p; } - ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & BUFUNL) != 0, - FALSE, FALSE); - if (ea.line2 < 0) /* failed */ + ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & EX_BUFUNL) != 0, + false, false); + if (ea.line2 < 0) { // failed goto doend; + } ea.addr_count = 1; ea.arg = skipwhite(p); } @@ -2325,6 +2339,7 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent) eap->line1 = eap->line2; switch (eap->addr_type) { case ADDR_LINES: + case ADDR_OTHER: // default is current line number eap->line2 = curwin->w_cursor.lnum; break; @@ -2345,9 +2360,13 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent) eap->line2 = CURRENT_TAB_NR; break; case ADDR_TABS_RELATIVE: + case ADDR_UNSIGNED: eap->line2 = 1; break; case ADDR_QUICKFIX: + eap->line2 = qf_get_cur_idx(eap); + break; + case ADDR_QUICKFIX_VALID: eap->line2 = qf_get_cur_valid_idx(eap); break; case ADDR_NONE: @@ -2365,6 +2384,7 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent) eap->cmd++; switch (eap->addr_type) { case ADDR_LINES: + case ADDR_OTHER: eap->line1 = 1; eap->line2 = curbuf->b_ml.ml_line_count; break; @@ -2400,7 +2420,8 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent) } break; case ADDR_TABS_RELATIVE: - case ADDR_OTHER: + case ADDR_UNSIGNED: + case ADDR_QUICKFIX: *errormsg = (char_u *)_(e_invrange); return FAIL; case ADDR_ARGUMENTS: @@ -2411,9 +2432,9 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent) eap->line2 = ARGCOUNT; } break; - case ADDR_QUICKFIX: + case ADDR_QUICKFIX_VALID: eap->line1 = 1; - eap->line2 = qf_get_size(eap); + eap->line2 = qf_get_valid_size(eap); if (eap->line2 == 0) { eap->line2 = 1; } @@ -2522,14 +2543,13 @@ static void append_command(char_u *cmd) *d = NUL; } -/* - * Find an Ex command by its name, either built-in or user. - * Start of the name can be found at eap->cmd. - * Returns pointer to char after the command name. - * "full" is set to TRUE if the whole command name matched. - * Returns NULL for an ambiguous user command. - */ +// Find an Ex command by its name, either built-in or user. +// Start of the name can be found at eap->cmd. +// Sets eap->cmdidx and returns a pointer to char after the command name. +// "full" is set to TRUE if the whole command name matched. +// Returns NULL for an ambiguous user command. static char_u *find_command(exarg_T *eap, int *full) + FUNC_ATTR_NONNULL_ARG(1) { int len; char_u *p; @@ -2980,7 +3000,7 @@ const char * set_one_cmd_context( const char *arg = (const char *)skipwhite((const char_u *)p); // Skip over ++argopt argument - if ((ea.argt & ARGOPT) && *arg != NUL && strncmp(arg, "++", 2) == 0) { + if ((ea.argt & EX_ARGOPT) && *arg != NUL && strncmp(arg, "++", 2) == 0) { p = arg; while (*p && !ascii_isspace(*p)) { MB_PTR_ADV(p); @@ -3015,9 +3035,9 @@ const char * set_one_cmd_context( arg = (const char *)skipwhite((const char_u *)arg); } - /* Does command allow "+command"? */ - if ((ea.argt & EDITCMD) && !usefilter && *arg == '+') { - /* Check if we're in the +command */ + // Does command allow "+command"? + if ((ea.argt & EX_CMDARG) && !usefilter && *arg == '+') { + // Check if we're in the +command p = arg + 1; arg = (const char *)skip_cmd_arg((char_u *)arg, false); @@ -3033,17 +3053,19 @@ const char * set_one_cmd_context( * Check for '|' to separate commands and '"' to start comments. * Don't do this for ":read !cmd" and ":write !cmd". */ - if ((ea.argt & TRLBAR) && !usefilter) { + if ((ea.argt & EX_TRLBAR) && !usefilter) { p = arg; /* ":redir @" is not the start of a comment */ if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') p += 2; while (*p) { if (*p == Ctrl_V) { - if (p[1] != NUL) - ++p; - } else if ( (*p == '"' && !(ea.argt & NOTRLCOM)) - || *p == '|' || *p == '\n') { + if (p[1] != NUL) { + p++; + } + } else if ((*p == '"' && !(ea.argt & EX_NOTRLCOM)) + || *p == '|' + || *p == '\n') { if (*(p - 1) != '\\') { if (*p == '|' || *p == '\n') return p + 1; @@ -3054,8 +3076,8 @@ const char * set_one_cmd_context( } } - // no arguments allowed - if (!(ea.argt & EXTRA) && *arg != NUL && strchr("|\"", *arg) == NULL) { + if (!(ea.argt & EX_EXTRA) && *arg != NUL && strchr("|\"", *arg) == NULL) { + // no arguments allowed but there is something return NULL; } @@ -3075,7 +3097,7 @@ const char * set_one_cmd_context( } } - if (ea.argt & XFILE) { + if (ea.argt & EX_XFILE) { int c; int in_quote = false; const char *bow = NULL; // Beginning of word. @@ -3496,8 +3518,8 @@ const char * set_one_cmd_context( case CMD_USER: case CMD_USER_BUF: if (context != EXPAND_NOTHING) { - // XFILE: file names are handled above. - if (!(ea.argt & XFILE)) { + // EX_XFILE: file names are handled above. + if (!(ea.argt & EX_XFILE)) { if (context == EXPAND_MENUS) { return (const char *)set_context_in_menu_cmd(xp, (char_u *)cmd, (char_u *)arg, forceit); @@ -3707,6 +3729,15 @@ char_u *skip_range( return (char_u *)cmd; } +static void addr_error(cmd_addr_T addr_type) +{ + if (addr_type == ADDR_NONE) { + EMSG(_(e_norange)); + } else { + EMSG(_(e_invrange)); + } +} + // Get a single EX address // // Set ptr to the next character after the part that was interpreted. @@ -3716,14 +3747,13 @@ char_u *skip_range( // Return MAXLNUM when no Ex address was found. static linenr_T get_address(exarg_T *eap, char_u **ptr, - cmd_addr_T addr_type_arg, + cmd_addr_T addr_type, int skip, // only skip the address, don't use it bool silent, // no errors or side effects int to_other_file, // flag: may jump to other file int address_count) // 1 for first, >1 after comma FUNC_ATTR_NONNULL_ALL { - const int addr_type = addr_type_arg; int c; int i; long n; @@ -3741,6 +3771,7 @@ static linenr_T get_address(exarg_T *eap, ++cmd; switch (addr_type) { case ADDR_LINES: + case ADDR_OTHER: lnum = curwin->w_cursor.lnum; break; case ADDR_WINDOWS: @@ -3756,13 +3787,17 @@ static linenr_T get_address(exarg_T *eap, case ADDR_TABS: lnum = CURRENT_TAB_NR; break; - case ADDR_TABS_RELATIVE: case ADDR_NONE: - EMSG(_(e_invrange)); + case ADDR_TABS_RELATIVE: + case ADDR_UNSIGNED: + addr_error(addr_type); cmd = NULL; goto error; break; case ADDR_QUICKFIX: + lnum = qf_get_cur_idx(eap); + break; + case ADDR_QUICKFIX_VALID: lnum = qf_get_cur_valid_idx(eap); break; } @@ -3772,6 +3807,7 @@ static linenr_T get_address(exarg_T *eap, ++cmd; switch (addr_type) { case ADDR_LINES: + case ADDR_OTHER: lnum = curbuf->b_ml.ml_line_count; break; case ADDR_WINDOWS: @@ -3796,9 +3832,10 @@ static linenr_T get_address(exarg_T *eap, case ADDR_TABS: lnum = LAST_TAB_NR; break; - case ADDR_TABS_RELATIVE: case ADDR_NONE: - EMSG(_(e_invrange)); + case ADDR_TABS_RELATIVE: + case ADDR_UNSIGNED: + addr_error(addr_type); cmd = NULL; goto error; break; @@ -3808,6 +3845,12 @@ static linenr_T get_address(exarg_T *eap, lnum = 1; } break; + case ADDR_QUICKFIX_VALID: + lnum = qf_get_valid_size(eap); + if (lnum == 0) { + lnum = 1; + } + break; } break; @@ -3817,7 +3860,7 @@ static linenr_T get_address(exarg_T *eap, goto error; } if (addr_type != ADDR_LINES) { - EMSG(_(e_invaddr)); + addr_error(addr_type); cmd = NULL; goto error; } @@ -3845,7 +3888,7 @@ static linenr_T get_address(exarg_T *eap, case '?': /* '/' or '?' - search */ c = *cmd++; if (addr_type != ADDR_LINES) { - EMSG(_(e_invaddr)); + addr_error(addr_type); cmd = NULL; goto error; } @@ -3892,7 +3935,7 @@ static linenr_T get_address(exarg_T *eap, case '\\': /* "\?", "\/" or "\&", repeat search */ ++cmd; if (addr_type != ADDR_LINES) { - EMSG(_(e_invaddr)); + addr_error(addr_type); cmd = NULL; goto error; } @@ -3939,7 +3982,9 @@ static linenr_T get_address(exarg_T *eap, if (lnum == MAXLNUM) { switch (addr_type) { case ADDR_LINES: - lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */ + case ADDR_OTHER: + // "+1" is same as ".+1" + lnum = curwin->w_cursor.lnum; break; case ADDR_WINDOWS: lnum = CURRENT_WIN_NR; @@ -3958,9 +4003,14 @@ static linenr_T get_address(exarg_T *eap, lnum = 1; break; case ADDR_QUICKFIX: + lnum = qf_get_cur_idx(eap); + break; + case ADDR_QUICKFIX_VALID: lnum = qf_get_cur_valid_idx(eap); break; case ADDR_NONE: + case ADDR_UNSIGNED: + lnum = 0; break; } } @@ -4051,12 +4101,11 @@ static char_u *invalid_range(exarg_T *eap) return (char_u *)_(e_invrange); } - if (eap->argt & RANGE) { - switch(eap->addr_type) { + if (eap->argt & EX_RANGE) { + switch (eap->addr_type) { case ADDR_LINES: - if (!(eap->argt & NOTADR) - && eap->line2 > curbuf->b_ml.ml_line_count - + (eap->cmdidx == CMD_diffget)) { + if (eap->line2 > (curbuf->b_ml.ml_line_count + + (eap->cmdidx == CMD_diffget))) { return (char_u *)_(e_invrange); } break; @@ -4105,11 +4154,24 @@ static char_u *invalid_range(exarg_T *eap) } break; case ADDR_TABS_RELATIVE: - // Do nothing + case ADDR_OTHER: + // Any range is OK. break; case ADDR_QUICKFIX: assert(eap->line2 >= 0); - if (eap->line2 != 1 && (size_t)eap->line2 > qf_get_size(eap)) { + // No error for value that is too big, will use the last entry. + if (eap->line2 <= 0) { + return (char_u *)_(e_invrange); + } + break; + case ADDR_QUICKFIX_VALID: + if ((eap->line2 != 1 && (size_t)eap->line2 > qf_get_valid_size(eap)) + || eap->line2 < 0) { + return (char_u *)_(e_invrange); + } + break; + case ADDR_UNSIGNED: + if (eap->line2 < 0) { return (char_u *)_(e_invrange); } break; @@ -4126,11 +4188,13 @@ static char_u *invalid_range(exarg_T *eap) */ static void correct_range(exarg_T *eap) { - if (!(eap->argt & ZEROR)) { /* zero in range not allowed */ - if (eap->line1 == 0) + if (!(eap->argt & EX_ZEROR)) { // zero in range not allowed + if (eap->line1 == 0) { eap->line1 = 1; - if (eap->line2 == 0) + } + if (eap->line2 == 0) { eap->line2 = 1; + } } } @@ -4297,7 +4361,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp) && eap->cmdidx != CMD_lmake && eap->cmdidx != CMD_make && eap->cmdidx != CMD_terminal - && !(eap->argt & NOSPC) + && !(eap->argt & EX_NOSPC) ) { char_u *l; #ifdef BACKSLASH_IN_FILENAME @@ -4338,7 +4402,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp) * One file argument: Expand wildcards. * Don't do this with ":r !command" or ":w !command". */ - if ((eap->argt & NOSPC) && !eap->usefilter) { + if ((eap->argt & EX_NOSPC) && !eap->usefilter) { // Replace environment variables. if (has_wildcards) { /* @@ -4451,38 +4515,39 @@ void separate_nextcmd(exarg_T *eap) for (; *p; MB_PTR_ADV(p)) { if (*p == Ctrl_V) { - if (eap->argt & (USECTRLV | XFILE)) - ++p; /* skip CTRL-V and next char */ - else - /* remove CTRL-V and skip next char */ + if (eap->argt & (EX_CTRLV | EX_XFILE)) { + p++; // skip CTRL-V and next char + } else { + // remove CTRL-V and skip next char STRMOVE(p, p + 1); - if (*p == NUL) /* stop at NUL after CTRL-V */ + } + if (*p == NUL) { // stop at NUL after CTRL-V break; - } - /* Skip over `=expr` when wildcards are expanded. */ - else if (p[0] == '`' && p[1] == '=' && (eap->argt & XFILE)) { + } + } else if (p[0] == '`' && p[1] == '=' && (eap->argt & EX_XFILE)) { + // Skip over `=expr` when wildcards are expanded. 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! - * :redir @" doesn't either. */ - else if ((*p == '"' && !(eap->argt & NOTRLCOM) - && (eap->cmdidx != CMD_at || p != eap->arg) - && (eap->cmdidx != CMD_redir - || p != eap->arg + 1 || p[-1] != '@')) - || *p == '|' || *p == '\n') { - /* - * We remove the '\' before the '|', unless USECTRLV is used - * AND 'b' is present in 'cpoptions'. - */ + } else if ( + // Check for '"': start of comment or '|': next command */ + // :@" does not start a comment! + // :redir @" doesn't either. + (*p == '"' + && !(eap->argt & EX_NOTRLCOM) + && (eap->cmdidx != CMD_at || p != eap->arg) + && (eap->cmdidx != CMD_redir + || p != eap->arg + 1 || p[-1] != '@')) + || *p == '|' + || *p == '\n') { + // We remove the '\' before the '|', unless EX_CTRLV is used + // AND 'b' is present in 'cpoptions'. if ((vim_strchr(p_cpo, CPO_BAR) == NULL - || !(eap->argt & USECTRLV)) && *(p - 1) == '\\') { - STRMOVE(p - 1, p); /* remove the '\' */ - --p; + || !(eap->argt & EX_CTRLV)) && *(p - 1) == '\\') { + STRMOVE(p - 1, p); // remove the '\' + p--; } else { eap->nextcmd = check_nextcmd(p); *p = NUL; @@ -4491,8 +4556,9 @@ void separate_nextcmd(exarg_T *eap) } } - if (!(eap->argt & NOTRLCOM)) /* remove trailing spaces */ + if (!(eap->argt & EX_NOTRLCOM)) { // remove trailing spaces del_trailing_spaces(eap->arg); + } } /* @@ -5181,11 +5247,11 @@ static void uc_list(char_u *name, size_t name_len) // Special cases int len = 4; - if (a & BANG) { + if (a & EX_BANG) { msg_putchar('!'); len--; } - if (a & REGSTR) { + if (a & EX_REGSTR) { msg_putchar('"'); len--; } @@ -5193,7 +5259,7 @@ static void uc_list(char_u *name, size_t name_len) msg_putchar('b'); len--; } - if (a & TRLBAR) { + if (a & EX_TRLBAR) { msg_putchar('|'); len--; } @@ -5215,20 +5281,20 @@ static void uc_list(char_u *name, size_t name_len) len = 0; // Arguments - switch (a & (EXTRA|NOSPC|NEEDARG)) { + switch (a & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) { case 0: IObuff[len++] = '0'; break; - case (EXTRA): + case (EX_EXTRA): IObuff[len++] = '*'; break; - case (EXTRA|NOSPC): + case (EX_EXTRA | EX_NOSPC): IObuff[len++] = '?'; break; - case (EXTRA|NEEDARG): + case (EX_EXTRA | EX_NEEDARG): IObuff[len++] = '+'; break; - case (EXTRA|NOSPC|NEEDARG): + case (EX_EXTRA | EX_NOSPC | EX_NEEDARG): IObuff[len++] = '1'; break; } @@ -5238,13 +5304,13 @@ static void uc_list(char_u *name, size_t name_len) } while (len < 5 - over); // Address / Range - if (a & (RANGE|COUNT)) { - if (a & COUNT) { + if (a & (EX_RANGE | EX_COUNT)) { + if (a & EX_COUNT) { // -count=N snprintf((char *)IObuff + len, IOSIZE, "%" PRId64 "c", (int64_t)cmd->uc_def); len += (int)STRLEN(IObuff + len); - } else if (a & DFLALL) { + } else if (a & EX_DFLALL) { IObuff[len++] = '%'; } else if (cmd->uc_def >= 0) { // -range=N @@ -5319,16 +5385,16 @@ static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, return FAIL; } - /* First, try the simple attributes (no arguments) */ - if (STRNICMP(attr, "bang", len) == 0) - *argt |= BANG; - else if (STRNICMP(attr, "buffer", len) == 0) + // First, try the simple attributes (no arguments) + if (STRNICMP(attr, "bang", len) == 0) { + *argt |= EX_BANG; + } else if (STRNICMP(attr, "buffer", len) == 0) { *flags |= UC_BUFFER; - else if (STRNICMP(attr, "register", len) == 0) - *argt |= REGSTR; - else if (STRNICMP(attr, "bar", len) == 0) - *argt |= TRLBAR; - else { + } else if (STRNICMP(attr, "register", len) == 0) { + *argt |= EX_REGSTR; + } else if (STRNICMP(attr, "bar", len) == 0) { + *argt |= EX_TRLBAR; + } else { int i; char_u *val = NULL; size_t vallen = 0; @@ -5346,28 +5412,29 @@ static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, if (STRNICMP(attr, "nargs", attrlen) == 0) { if (vallen == 1) { - if (*val == '0') - /* Do nothing - this is the default */; - else if (*val == '1') - *argt |= (EXTRA | NOSPC | NEEDARG); - else if (*val == '*') - *argt |= EXTRA; - else if (*val == '?') - *argt |= (EXTRA | NOSPC); - else if (*val == '+') - *argt |= (EXTRA | NEEDARG); - else + if (*val == '0') { + // Do nothing - this is the default; + } else if (*val == '1') { + *argt |= (EX_EXTRA | EX_NOSPC | EX_NEEDARG); + } else if (*val == '*') { + *argt |= EX_EXTRA; + } else if (*val == '?') { + *argt |= (EX_EXTRA | EX_NOSPC); + } else if (*val == '+') { + *argt |= (EX_EXTRA | EX_NEEDARG); + } else { goto wrong_nargs; + } } else { wrong_nargs: EMSG(_("E176: Invalid number of arguments")); return FAIL; } } else if (STRNICMP(attr, "range", attrlen) == 0) { - *argt |= RANGE; - if (vallen == 1 && *val == '%') - *argt |= DFLALL; - else if (val != NULL) { + *argt |= EX_RANGE; + if (vallen == 1 && *val == '%') { + *argt |= EX_DFLALL; + } else if (val != NULL) { p = val; if (*def >= 0) { two_count: @@ -5376,7 +5443,7 @@ two_count: } *def = getdigits_long(&p, true, 0); - *argt |= (ZEROR | NOTADR); + *argt |= EX_ZEROR; if (p != val + vallen || vallen == 0) { invalid_count: @@ -5384,8 +5451,16 @@ invalid_count: return FAIL; } } + // default for -range is using buffer lines + if (*addr_type_arg == ADDR_NONE) { + *addr_type_arg = ADDR_LINES; + } } else if (STRNICMP(attr, "count", attrlen) == 0) { - *argt |= (COUNT | ZEROR | RANGE | NOTADR); + *argt |= (EX_COUNT | EX_ZEROR | EX_RANGE); + // default for -count is using any number + if (*addr_type_arg == ADDR_NONE) { + *addr_type_arg = ADDR_OTHER; + } if (val != NULL) { p = val; @@ -5411,16 +5486,16 @@ invalid_count: return FAIL; } } else if (STRNICMP(attr, "addr", attrlen) == 0) { - *argt |= RANGE; + *argt |= EX_RANGE; if (val == NULL) { EMSG(_("E179: argument required for -addr")); return FAIL; } - if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) == FAIL) { + if (parse_addr_type_arg(val, (int)vallen, addr_type_arg) == FAIL) { return FAIL; } if (*addr_type_arg != ADDR_LINES) { - *argt |= (ZEROR | NOTADR); + *argt |= EX_ZEROR; } } else { char_u ch = attr[len]; @@ -5447,7 +5522,7 @@ static void ex_command(exarg_T *eap) int flags = 0; int compl = EXPAND_NOTHING; char_u *compl_arg = NULL; - cmd_addr_T addr_type_arg = ADDR_LINES; + cmd_addr_T addr_type_arg = ADDR_NONE; int has_attr = (eap->arg[0] == '-'); int name_len; @@ -5724,8 +5799,9 @@ uc_check_code( /* When specified there is a single argument don't split it. * Works for ":Cmd %" when % is "a b c". */ - if ((eap->argt & NOSPC) && quote == 2) + if ((eap->argt & EX_NOSPC) && quote == 2) { quote = 1; + } switch (quote) { case 0: /* No quoting, no splitting */ @@ -6105,8 +6181,7 @@ char_u *get_user_cmd_complete(expand_T *xp, int idx) /* * Parse address type argument */ -int parse_addr_type_arg(char_u *value, int vallen, uint32_t *argt, - cmd_addr_T *addr_type_arg) +int parse_addr_type_arg(char_u *value, int vallen, cmd_addr_T *addr_type_arg) FUNC_ATTR_NONNULL_ALL { int i, a, b; @@ -6129,9 +6204,6 @@ int parse_addr_type_arg(char_u *value, int vallen, uint32_t *argt, return FAIL; } - if (*addr_type_arg != ADDR_LINES) - *argt |= NOTADR; - return OK; } @@ -6169,9 +6241,9 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp, && STRNCMP(value, command_complete[i], valend) == 0) { *complp = i; if (i == EXPAND_BUFFERS) { - *argt |= BUFNAME; + *argt |= EX_BUFNAME; } else if (i == EXPAND_DIRECTORIES || i == EXPAND_FILES) { - *argt |= XFILE; + *argt |= EX_XFILE; } break; } @@ -7423,11 +7495,12 @@ static void ex_read(exarg_T *eap) int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); linenr_T lnum; - if (eap->usefilter) /* :r!cmd */ - do_bang(1, eap, FALSE, FALSE, TRUE); - else { - if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) + if (eap->usefilter) { // :r!cmd + do_bang(1, eap, false, false, true); + } else { + if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) { return; + } if (*eap->arg == NUL) { if (check_fname() == FAIL) /* check for no file name */ @@ -7799,7 +7872,7 @@ static void ex_copymove(exarg_T *eap) * move or copy lines from 'eap->line1'-'eap->line2' to below line 'n' */ if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count) { - EMSG(_(e_invaddr)); + EMSG(_(e_invrange)); return; } @@ -7897,7 +7970,7 @@ static void ex_at(exarg_T *eap) */ static void ex_bang(exarg_T *eap) { - do_bang(eap->addr_count, eap, eap->forceit, TRUE, TRUE); + do_bang(eap->addr_count, eap, eap->forceit, true, true); } /* @@ -8647,6 +8720,7 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen) * '#' to curwin->w_altfile * '<cword>' to word under the cursor * '<cWORD>' to WORD under the cursor + * '<cexpr>' to C-expression under the cursor * '<cfile>' to path name under the cursor * '<sfile>' to sourced file name * '<slnum>' to sourced file line number @@ -9475,16 +9549,16 @@ Dictionary commands_array(buf_T *buf) PUT(d, "name", STRING_OBJ(cstr_to_string((char *)cmd->uc_name))); PUT(d, "definition", STRING_OBJ(cstr_to_string((char *)cmd->uc_rep))); PUT(d, "script_id", INTEGER_OBJ(cmd->uc_script_ctx.sc_sid)); - PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & BANG))); - PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & TRLBAR))); - PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & REGSTR))); + PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_BANG))); + PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR))); + PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR))); - switch (cmd->uc_argt & (EXTRA|NOSPC|NEEDARG)) { - case 0: arg[0] = '0'; break; - case(EXTRA): arg[0] = '*'; break; - case(EXTRA|NOSPC): arg[0] = '?'; break; - case(EXTRA|NEEDARG): arg[0] = '+'; break; - case(EXTRA|NOSPC|NEEDARG): arg[0] = '1'; break; + switch (cmd->uc_argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) { + case 0: arg[0] = '0'; break; + case(EX_EXTRA): arg[0] = '*'; break; + case(EX_EXTRA | EX_NOSPC): arg[0] = '?'; break; + case(EX_EXTRA | EX_NEEDARG): arg[0] = '+'; break; + case(EX_EXTRA | EX_NOSPC | EX_NEEDARG): arg[0] = '1'; break; } PUT(d, "nargs", STRING_OBJ(cstr_to_string(arg))); @@ -9495,7 +9569,7 @@ Dictionary commands_array(buf_T *buf) ? NIL : STRING_OBJ(cstr_to_string((char *)cmd->uc_compl_arg))); Object obj = NIL; - if (cmd->uc_argt & COUNT) { + if (cmd->uc_argt & EX_COUNT) { if (cmd->uc_def >= 0) { snprintf(str, sizeof(str), "%" PRId64, (int64_t)cmd->uc_def); obj = STRING_OBJ(cstr_to_string(str)); // -count=N @@ -9506,8 +9580,8 @@ Dictionary commands_array(buf_T *buf) PUT(d, "count", obj); obj = NIL; - if (cmd->uc_argt & RANGE) { - if (cmd->uc_argt & DFLALL) { + if (cmd->uc_argt & EX_RANGE) { + if (cmd->uc_argt & EX_DFLALL) { obj = STRING_OBJ(cstr_to_string("%")); // -range=% } else if (cmd->uc_def >= 0) { snprintf(str, sizeof(str), "%" PRId64, (int64_t)cmd->uc_def); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0f50d5153d..2aa66f6a8c 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3828,7 +3828,7 @@ static void cmd_cursor_goto(int row, int col) ui_grid_cursor_goto(grid->handle, row, col); } -void gotocmdline(int clr) +void gotocmdline(bool clr) { if (ui_has(kUICmdline)) { return; @@ -4780,7 +4780,7 @@ char_u *addstar(char_u *fname, size_t len, int context) * EXPAND_COMMANDS Cursor is still touching the command, so complete * it. * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands. - * EXPAND_FILES After command with XFILE set, or after setting + * EXPAND_FILES After command with EX_XFILE set, or after setting * with P_EXPAND set. eg :e ^I, :w>>^I * EXPAND_DIRECTORIES In some cases this is used instead of the latter * when we know only directories are of interest. eg diff --git a/src/nvim/generators/gen_ex_cmds.lua b/src/nvim/generators/gen_ex_cmds.lua index 2574af6218..844661adc3 100644 --- a/src/nvim/generators/gen_ex_cmds.lua +++ b/src/nvim/generators/gen_ex_cmds.lua @@ -22,7 +22,10 @@ local defsfname = autodir .. '/ex_cmds_defs.generated.h' local enumfile = io.open(enumfname, 'w') local defsfile = io.open(defsfname, 'w') -local defs = require('ex_cmds') +local bit = require 'bit' +local ex_cmds = require('ex_cmds') +local defs = ex_cmds.cmds +local flags = ex_cmds.flags local byte_a = string.byte('a') local byte_z = string.byte('z') @@ -51,6 +54,17 @@ static CommandDefinition cmdnames[%u] = { ]], #defs, #defs)) local cmds, cmdidxs1, cmdidxs2 = {}, {}, {} for _, cmd in ipairs(defs) do + if bit.band(cmd.flags, flags.RANGE) == flags.RANGE then + assert(cmd.addr_type ~= 'ADDR_NONE', + string.format('ex_cmds.lua:%s: Using RANGE with ADDR_NONE\n', cmd.command)) + else + assert(cmd.addr_type == 'ADDR_NONE', + string.format('ex_cmds.lua:%s: Missing ADDR_NONE\n', cmd.command)) + end + if bit.band(cmd.flags, flags.DFLALL) == flags.DFLALL then + assert(cmd.addr_type ~= 'ADDR_OTHER' and cmd.addr_type ~= 'ADDR_NONE', + string.format('ex_cmds.lua:%s: Missing misplaced DFLALL\n', cmd.command)) + end local enumname = cmd.enum or ('CMD_' .. cmd.command) local byte_cmd = cmd.command:sub(1, 1):byte() if byte_a <= byte_cmd and byte_cmd <= byte_z then diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 31b905e858..3b8f4116b7 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -866,7 +866,6 @@ EXTERN char_u e_failed[] INIT(= N_("E472: Command failed")); EXTERN char_u e_internal[] INIT(= N_("E473: Internal error")); EXTERN char_u e_intern2[] INIT(= N_("E685: Internal error: %s")); EXTERN char_u e_interr[] INIT(= N_("Interrupted")); -EXTERN char_u e_invaddr[] INIT(= N_("E14: Invalid address")); EXTERN char_u e_invarg[] INIT(= N_("E474: Invalid argument")); EXTERN char_u e_invarg2[] INIT(= N_("E475: Invalid argument: %s")); EXTERN char_u e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); diff --git a/src/nvim/log.c b/src/nvim/log.c index 19203a3c2a..324382a0f7 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -51,7 +51,7 @@ static bool log_try_create(char *fname) /// Initializes path to log file. Sets $NVIM_LOG_FILE if empty. /// -/// Tries $NVIM_LOG_FILE, or falls back to $XDG_DATA_HOME/nvim/log. Path to log +/// Tries $NVIM_LOG_FILE, or falls back to $XDG_CACHE_HOME/nvim/log. Path to log /// file is cached, so only the first call has effect, unless first call was not /// successful. Failed initialization indicates either a bug in expand_env() /// or both $NVIM_LOG_FILE and $HOME environment variables are undefined. @@ -69,8 +69,16 @@ static bool log_path_init(void) || log_file_path[0] == '\0' || os_isdir((char_u *)log_file_path) || !log_try_create(log_file_path)) { + // Make kXDGCacheHome if it does not exist. + char *cachehome = get_xdg_home(kXDGCacheHome); + char *failed_dir = NULL; + bool log_dir_failure = false; + if (!os_isdir((char_u *)cachehome)) { + log_dir_failure = (os_mkdir_recurse(cachehome, 0700, &failed_dir) != 0); + } + XFREE_CLEAR(cachehome); // Invalid $NVIM_LOG_FILE or failed to expand; fall back to default. - char *defaultpath = stdpaths_user_data_subpath("log", 0, true); + char *defaultpath = stdpaths_user_cache_subpath("log"); size_t len = xstrlcpy(log_file_path, defaultpath, size); xfree(defaultpath); // Fall back to .nvimlog @@ -83,6 +91,11 @@ static bool log_path_init(void) return false; } os_setenv(LOG_FILE_ENV, log_file_path, true); + if (log_dir_failure) { + WLOG("Failed to create directory %s for writing logs: %s", + failed_dir, os_strerror(log_dir_failure)); + } + XFREE_CLEAR(failed_dir); } return true; } @@ -323,4 +336,3 @@ static bool v_do_log_to_file(FILE *log_file, int log_level, return true; } - diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 344a2387d6..3219c02068 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -5,6 +5,7 @@ #include <lualib.h> #include <lauxlib.h> +#include "nvim/version.h" #include "nvim/misc1.h" #include "nvim/getchar.h" #include "nvim/garray.h" @@ -78,6 +79,17 @@ static void nlua_error(lua_State *const lstate, const char *const msg) lua_pop(lstate, 1); } +/// Return version of current neovim build +/// +/// @param lstate Lua interpreter state. +static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL +{ + Dictionary version = version_dict(); + nlua_push_Dictionary(lstate, version, true); + api_free_dictionary(version); + return 1; +} + /// Compare two strings, ignoring case /// /// Expects two values on the stack: compared strings. Returns one of the @@ -420,6 +432,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL // str_byteindex lua_pushcfunction(lstate, &nlua_str_byteindex); lua_setfield(lstate, -2, "str_byteindex"); + // neovim version + lua_pushcfunction(lstate, &nlua_nvim_version); + lua_setfield(lstate, -2, "version"); // schedule lua_pushcfunction(lstate, &nlua_schedule); lua_setfield(lstate, -2, "schedule"); diff --git a/src/nvim/main.c b/src/nvim/main.c index 8bf745966e..9f71df3a46 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -2044,7 +2044,6 @@ static void usage(void) mch_msg(_(" -u <config> Use this config file\n")); mch_msg(_(" -v, --version Print version information\n")); mch_msg(_(" -V[N][file] Verbose [level][file]\n")); - mch_msg(_(" -Z Restricted mode\n")); mch_msg("\n"); mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n")); mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n")); diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 1ecfae57ed..73a9c1d1d7 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -777,6 +777,7 @@ void ex_delmarks(exarg_T *eap) n = i - 'A'; } namedfm[n].fmark.mark.lnum = 0; + namedfm[n].fmark.fnum = 0; XFREE_CLEAR(namedfm[n].fname); } } @@ -1552,3 +1553,87 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) } } } + + +// Add information about mark 'mname' to list 'l' +static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, + const char *fname) + FUNC_ATTR_NONNULL_ARG(1, 2, 3) +{ + if (pos->lnum <= 0) { + return OK; + } + + dict_T *d = tv_dict_alloc(); + tv_list_append_dict(l, d); + + list_T *lpos = tv_list_alloc(kListLenMayKnow); + + tv_list_append_number(lpos, bufnr); + tv_list_append_number(lpos, pos->lnum); + tv_list_append_number(lpos, pos->col + 1); + tv_list_append_number(lpos, pos->coladd); + + if (tv_dict_add_str(d, S_LEN("mark"), mname) == FAIL + || tv_dict_add_list(d, S_LEN("pos"), lpos) == FAIL + || (fname != NULL && tv_dict_add_str(d, S_LEN("file"), fname) == FAIL)) { + return FAIL; + } + + return OK; +} + + +/// Get information about marks local to a buffer. +/// +/// @param[in] buf Buffer to get the marks from +/// @param[out] l List to store marks +void get_buf_local_marks(const buf_T *buf, list_T *l) + FUNC_ATTR_NONNULL_ALL +{ + char mname[3] = "' "; + + // Marks 'a' to 'z' + for (int i = 0; i < NMARKS; i++) { + mname[1] = (char)('a' + i); + add_mark(l, mname, &buf->b_namedm[i].mark, buf->b_fnum, NULL); + } + + // Mark '' is a window local mark and not a buffer local mark + add_mark(l, "''", &curwin->w_pcmark, curbuf->b_fnum, NULL); + + add_mark(l, "'\"", &buf->b_last_cursor.mark, buf->b_fnum, NULL); + add_mark(l, "'[", &buf->b_op_start, buf->b_fnum, NULL); + add_mark(l, "']", &buf->b_op_end, buf->b_fnum, NULL); + add_mark(l, "'^", &buf->b_last_insert.mark, buf->b_fnum, NULL); + add_mark(l, "'.", &buf->b_last_change.mark, buf->b_fnum, NULL); + add_mark(l, "'<", &buf->b_visual.vi_start, buf->b_fnum, NULL); + add_mark(l, "'>", &buf->b_visual.vi_end, buf->b_fnum, NULL); +} + +/// Get information about global marks ('A' to 'Z' and '0' to '9') +/// +/// @param[out] l List to store global marks +void get_global_marks(list_T *l) + FUNC_ATTR_NONNULL_ALL +{ + char mname[3] = "' "; + char *name; + + // Marks 'A' to 'Z' and '0' to '9' + for (int i = 0; i < NMARKS + EXTRA_MARKS; i++) { + if (namedfm[i].fmark.fnum != 0) { + name = (char *)buflist_nr2name(namedfm[i].fmark.fnum, true, true); + } else { + name = (char *)namedfm[i].fname; + } + if (name != NULL) { + mname[1] = i >= NMARKS ? (char)(i - NMARKS + '0') : (char)(i + 'A'); + + add_mark(l, mname, &namedfm[i].fmark.mark, namedfm[i].fmark.fnum, name); + if (namedfm[i].fmark.fnum != 0) { + xfree(name); + } + } + } +} diff --git a/src/nvim/message.c b/src/nvim/message.c index f94529c687..ba7a667a60 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -890,6 +890,40 @@ char_u *msg_may_trunc(int force, char_u *s) return s; } +void clear_hl_msg(HlMessage *hl_msg) +{ + for (size_t i = 0; i < kv_size(*hl_msg); i++) { + xfree(kv_A(*hl_msg, i).text.data); + } + kv_destroy(*hl_msg); + *hl_msg = (HlMessage)KV_INITIAL_VALUE; +} + +#define LINE_BUFFER_SIZE 4096 + +void add_hl_msg_hist(HlMessage hl_msg) +{ + // TODO(notomo): support multi highlighted message history + size_t pos = 0; + char buf[LINE_BUFFER_SIZE]; + for (uint32_t i = 0; i < kv_size(hl_msg); i++) { + HlMessageChunk chunk = kv_A(hl_msg, i); + for (uint32_t j = 0; j < chunk.text.size; j++) { + if (pos == LINE_BUFFER_SIZE - 1) { + buf[pos] = NUL; + add_msg_hist((const char *)buf, -1, MSG_HIST, true); + pos = 0; + continue; + } + buf[pos++] = chunk.text.data[j]; + } + } + if (pos != 0) { + buf[pos] = NUL; + add_msg_hist((const char *)buf, -1, MSG_HIST, true); + } +} + /// @param[in] len Length of s or -1. static void add_msg_hist(const char *s, int len, int attr, bool multiline) { diff --git a/src/nvim/message.h b/src/nvim/message.h index fdb9bc96ca..377c725fa1 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -8,6 +8,8 @@ #include "nvim/macros.h" #include "nvim/types.h" #include "nvim/grid_defs.h" +#include "nvim/api/private/defs.h" +#include "nvim/lib/kvec.h" /* * Types of dialogs passed to do_dialog(). @@ -75,6 +77,13 @@ /// Like #MSG_PUTS_ATTR, but if middle part of long messages will be replaced #define MSG_PUTS_LONG_ATTR(s, a) msg_puts_long_attr((char_u *)(s), (a)) +typedef struct { + String text; + int attr; +} HlMessageChunk; + +typedef kvec_t(HlMessageChunk) HlMessage; + /// Message history for `:messages` typedef struct msg_hist { struct msg_hist *next; ///< Next message. diff --git a/src/nvim/option.c b/src/nvim/option.c index d43dd9ba15..47b9e9bb07 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -306,7 +306,7 @@ static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix", static char *(p_bufhidden_values[]) = { "hide", "unload", "delete", "wipe", NULL }; -static char *(p_bs_values[]) = { "indent", "eol", "start", NULL }; +static char *(p_bs_values[]) = { "indent", "eol", "start", "nostop", NULL }; static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent", "syntax", "diff", NULL }; static char *(p_fcl_values[]) = { "all", NULL }; @@ -1366,6 +1366,10 @@ int do_set( *(char_u **)varp = vim_strsave( (char_u *)"indent,eol,start"); break; + case 3: + *(char_u **)varp = vim_strsave( + (char_u *)"indent,eol,nostop"); + break; } xfree(oldval); if (origval == oldval) { @@ -2939,7 +2943,7 @@ ambw_end: } } else if (varp == &p_bs) { // 'backspace' if (ascii_isdigit(*p_bs)) { - if (*p_bs >'2' || p_bs[1] != NUL) { + if (*p_bs > '3' || p_bs[1] != NUL) { errmsg = e_invarg; } } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { @@ -6801,15 +6805,15 @@ static int check_opt_wim(void) } /// Check if backspacing over something is allowed. -/// The parameter what is one of the following: whatBS_INDENT, BS_EOL -/// or BS_START +/// @param what BS_INDENT, BS_EOL, BS_START, or BS_NOSTOP bool can_bs(int what) { if (what == BS_START && bt_prompt(curbuf)) { return false; } switch (*p_bs) { - case '2': return true; + case '3': return true; + case '2': return what != BS_NOSTOP; case '1': return what != BS_START; case '0': return false; } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index ec2160d365..683afc670e 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -282,9 +282,14 @@ enum { #define WIM_BUFLASTUSED 8 // arguments for can_bs() +// each defined char should be unique over all values +// except for BS_START, that intentionally also matches BS_NOSTOP +// because BS_NOSTOP behaves exactly the same except it +// does not stop at the start of the insert point #define BS_INDENT 'i' // "Indent" -#define BS_EOL 'o' // "eOl" +#define BS_EOL 'l' // "eoL" #define BS_START 's' // "Start" +#define BS_NOSTOP 'p' // "nostoP #define LISPWORD_VALUE \ "defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object" diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 879266e3d4..008f5ef63b 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -394,13 +394,21 @@ void os_get_hostname(char *hostname, size_t size) } /// To get the "real" home directory: -/// - get value of $HOME +/// 1. get value of $HOME +/// 2. if $HOME is not set, try the following +/// For Windows: +/// 1. assemble homedir using HOMEDRIVE and HOMEPATH +/// 2. try os_homedir() +/// 3. resolve a direct reference to another system variable +/// 4. guess C drive /// For Unix: -/// - go to that directory -/// - do os_dirname() to get the real name of that directory. -/// This also works with mounts and links. -/// Don't do this for Windows, it will change the "current dir" for a drive. +/// 1. try os_homedir() +/// 2. go to that directory +/// This also works with mounts and links. +/// Don't do this for Windows, it will change the "current dir" for a drive. +/// 3. fall back to current working directory as a last resort static char *homedir = NULL; +static char *os_homedir(void); void init_homedir(void) { @@ -430,7 +438,7 @@ void init_homedir(void) } } if (var == NULL) { - var = os_getenv("USERPROFILE"); + var = os_homedir(); } // Weird but true: $HOME may contain an indirect reference to another @@ -440,6 +448,7 @@ void init_homedir(void) const char *p = strchr(var + 1, '%'); if (p != NULL) { vim_snprintf(os_buf, (size_t)(p - var), "%s", var + 1); + var = NULL; const char *exp = os_getenv(os_buf); if (exp != NULL && *exp != NUL && STRLEN(exp) + STRLEN(p) < MAXPATHL) { @@ -458,8 +467,12 @@ void init_homedir(void) } #endif - if (var != NULL) { #ifdef UNIX + if (var == NULL) { + var = os_homedir(); + } + + if (var != NULL) { // Change to the directory and get the actual path. This resolves // links. Don't do it when we can't return. if (os_dirname((char_u *)os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) { @@ -470,11 +483,37 @@ void init_homedir(void) EMSG(_(e_prev_dir)); } } + } + + // Fall back to current working directory if home is not found + if ((var == NULL || *var == NUL) + && os_dirname((char_u *)os_buf, sizeof(os_buf)) == OK) { + var = os_buf; + } #endif + if (var != NULL) { homedir = xstrdup(var); } } +static char homedir_buf[MAXPATHL]; + +static char *os_homedir(void) +{ + homedir_buf[0] = NUL; + size_t homedir_size = MAXPATHL; + uv_mutex_lock(&mutex); + // http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_homedir + int ret_value = uv_os_homedir(homedir_buf, &homedir_size); + uv_mutex_unlock(&mutex); + if (ret_value == 0 && homedir_size < MAXPATHL) { + return homedir_buf; + } + ELOG("uv_os_homedir() failed %d: %s", ret_value, os_strerror(ret_value)); + homedir_buf[0] = NUL; + return NULL; +} + #if defined(EXITFREE) void free_homedir(void) diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index b7878d9da8..9d6518841a 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -393,7 +393,7 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events) prof_inchar_enter(); } - if ((ms == - 1 || ms > 0) && events == NULL && !input_eof) { + if ((ms == - 1 || ms > 0) && events != main_loop.events && !input_eof) { // The pending input provoked a blocking wait. Do special events now. #6247 blocking = true; multiqueue_process_events(ch_before_blocking_events); diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index 66bc990402..93b8d5ca12 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -108,6 +108,17 @@ char *get_xdg_home(const XDGVarType idx) return dir; } +/// Return subpath of $XDG_CACHE_HOME +/// +/// @param[in] fname New component of the path. +/// +/// @return [allocated] `$XDG_CACHE_HOME/nvim/{fname}` +char *stdpaths_user_cache_subpath(const char *fname) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET +{ + return concat_fnames_realloc(get_xdg_home(kXDGCacheHome), fname, true); +} + /// Return subpath of $XDG_CONFIG_HOME /// /// @param[in] fname New component of the path. diff --git a/src/nvim/po/af.po b/src/nvim/po/af.po index fa6674469c..db44f50a46 100644 --- a/src/nvim/po/af.po +++ b/src/nvim/po/af.po @@ -3290,10 +3290,6 @@ msgstr "-o[N]\t\tMaak N vensters oop (verstek: een vir elke lêer)" #~ msgid " -V[N][file] Verbose [level][file]\n" #~ msgstr "" -#, fuzzy -#~ msgid " -Z Restricted mode\n" -#~ msgstr " vir twee modusse " - #~ msgid " --api-info Write msgpack-encoded API metadata to stdout\n" #~ msgstr "" @@ -7473,9 +7469,6 @@ msgstr "E446: Geen lêernaam onder loper" #~ msgid "-b\t\t\tBinary mode" #~ msgstr "-b\t\t\tBinêre modus" -#~ msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -#~ msgstr "-Z\t\t\tBeperkte modus (soos \"rvim\")" - #~ msgid "-R\t\t\tReadonly mode (like \"view\")" #~ msgstr "-R\t\t\tLeesalleen modus (soos \"view\")" diff --git a/src/nvim/po/ca.po b/src/nvim/po/ca.po index be4206f36e..6c4d6ddd22 100644 --- a/src/nvim/po/ca.po +++ b/src/nvim/po/ca.po @@ -3469,10 +3469,6 @@ msgstr "-y\t\t\tMode senzill (com \"evim\", sense modes)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tMode només lectura (com \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tMode restringit (com \"rvim)" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tNo permet modificar (escriure) fitxers" diff --git a/src/nvim/po/cs.cp1250.po b/src/nvim/po/cs.cp1250.po index 5b9f3d3a58..859039eb87 100644 --- a/src/nvim/po/cs.cp1250.po +++ b/src/nvim/po/cs.cp1250.po @@ -3547,10 +3547,6 @@ msgstr "-v\t\t\tSnadný režim (stejné jako \"evim\", žádné módy )" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tRežim pouze_pro_ètení (jako \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tOmezený režim (stejné jako \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tZmìny (ukládání souborù) zakázány" diff --git a/src/nvim/po/cs.po b/src/nvim/po/cs.po index 31a90dc514..4d9ad58836 100644 --- a/src/nvim/po/cs.po +++ b/src/nvim/po/cs.po @@ -3547,10 +3547,6 @@ msgstr "-v\t\t\tSnadný re¾im (stejné jako \"evim\", ¾ádné módy )" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tRe¾im pouze_pro_ètení (jako \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tOmezený re¾im (stejné jako \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tZmìny (ukládání souborù) zakázány" diff --git a/src/nvim/po/da.po b/src/nvim/po/da.po index f35272810b..7a75425019 100644 --- a/src/nvim/po/da.po +++ b/src/nvim/po/da.po @@ -3015,9 +3015,6 @@ msgstr "-y\t\t\tEasy-tilstand (ligesom \"evim\", tilstandsløs)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tSkrivebeskyttet tilstand (ligesom \"view\")" -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tRestriktiv tilstand (ligesom \"rvim\")" - msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tÆndringer (skrivning af filer) ikke tilladt" diff --git a/src/nvim/po/de.po b/src/nvim/po/de.po index a2e04965e5..740e9e5f6a 100644 --- a/src/nvim/po/de.po +++ b/src/nvim/po/de.po @@ -2895,10 +2895,6 @@ msgstr "-y\t\t\tLeichter Modus (wie \"evim\", ohne Modi)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tModus ohne Schreibrechte (wie \"view\")" -#: ../main.c:2186 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tEingeschränkter Modus (wie \"rvim\")" - #: ../main.c:2187 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tÄnderungen (beim Schreiben von Dateien) sind nicht erlaubt" diff --git a/src/nvim/po/en_GB.po b/src/nvim/po/en_GB.po index 7919fc8946..66cdba6f92 100644 --- a/src/nvim/po/en_GB.po +++ b/src/nvim/po/en_GB.po @@ -3368,10 +3368,6 @@ msgstr "" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "" diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po index 99c46c7275..5480e6a4d8 100644 --- a/src/nvim/po/eo.po +++ b/src/nvim/po/eo.po @@ -2989,9 +2989,6 @@ msgstr "-y\t\t\tFacila reÄimo (kiel \"evim\", senreÄima)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tNurlegebla reÄimo (kiel \"view\")" -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tLimigita reÄimo (kiel \"rvim\")" - msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tÅœanÄoj (skribo al dosieroj) nepermeseblaj" diff --git a/src/nvim/po/es.po b/src/nvim/po/es.po index eeea27610d..064484d1a4 100644 --- a/src/nvim/po/es.po +++ b/src/nvim/po/es.po @@ -3524,10 +3524,6 @@ msgstr "-y\t\t\tModo fácil (como \"evim\", sin modo)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tModo de solo lectura (como \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tModo restringido (como \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tModificación de archivos desactivada" diff --git a/src/nvim/po/fi.po b/src/nvim/po/fi.po index 4489139cfb..5986a57488 100644 --- a/src/nvim/po/fi.po +++ b/src/nvim/po/fi.po @@ -3249,10 +3249,6 @@ msgstr "" #~ msgstr " kahta tilaa varten " #, fuzzy -#~ msgid " -Z Restricted mode\n" -#~ msgstr " kahta tilaa varten " - -#, fuzzy #~ msgid " -m Modifications (writing files) not allowed\n" #~ msgstr "-m\t\t\tMuokkaukset (kirjoittaminen tiedostoon) pois käytöstä" @@ -6961,9 +6957,6 @@ msgstr "Lista tai luku tarvitaan" #~ msgid "-b\t\t\tBinary mode" #~ msgstr "-b\t\t\tBinääritila" -#~ msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -#~ msgstr "-Z\t\t\tRajoitettu tila (kuten rvimillä)" - #~ msgid "-R\t\t\tReadonly mode (like \"view\")" #~ msgstr "-R\t\t\tKirjoitussuojattu tila (kuten view'lla)" diff --git a/src/nvim/po/fr.po b/src/nvim/po/fr.po index bb60649c91..5f1ca2fec5 100644 --- a/src/nvim/po/fr.po +++ b/src/nvim/po/fr.po @@ -3231,9 +3231,6 @@ msgstr "-y\t\tMode facile (comme \"evim\", vim sans modes)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\tMode lecture seule (comme \"view\")" -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\tMode restreint (comme \"rvim\")" - msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\tInterdire l'enregistrement des fichiers" diff --git a/src/nvim/po/ga.po b/src/nvim/po/ga.po index 1104b31c32..bad01d592a 100644 --- a/src/nvim/po/ga.po +++ b/src/nvim/po/ga.po @@ -3022,9 +3022,6 @@ msgstr "-y\t\t\tMód éasca (mar \"evim\", gan mhóid)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tMód inléite amháin (mar \"view\")" -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tMód srianta (mar \"rvim\")" - msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tNí cheadaítear athruithe (.i. scríobh na gcomhad)" diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po index 511f910b71..dfabc4bee0 100644 --- a/src/nvim/po/it.po +++ b/src/nvim/po/it.po @@ -3510,10 +3510,6 @@ msgstr "-y\t\t\tModalità Facile (come \"evim\", senza modalità)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tModalità Sola Lettura (come \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tModalità Ristretta (come \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tRiscritture del file non permesse" diff --git a/src/nvim/po/ja.euc-jp.po b/src/nvim/po/ja.euc-jp.po index 523e9ca4e3..e2cf68f016 100644 --- a/src/nvim/po/ja.euc-jp.po +++ b/src/nvim/po/ja.euc-jp.po @@ -3024,9 +3024,6 @@ msgstr "-y\t\t\t¥¤¡¼¥¸¡¼¥â¡¼¥É (\"evim\" ¤ÈƱ¤¸¡¢¥â¡¼¥É̵)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tÆÉ¹þÀìÍѥ⡼¥É (\"view\" ¤ÈƱ¤¸)" -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tÀ©¸Â¥â¡¼¥É (\"rvim\" ¤ÈƱ¤¸)" - msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tÊѹ¹ (¥Õ¥¡¥¤¥ëÊݸ»þ) ¤ò¤Ç¤¤Ê¤¤¤è¤¦¤Ë¤¹¤ë" diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po index 5a69d0c5bf..85a45cd171 100644 --- a/src/nvim/po/ja.po +++ b/src/nvim/po/ja.po @@ -3024,9 +3024,6 @@ msgstr "-y\t\t\tイージーモード (\"evim\" ã¨åŒã˜ã€ãƒ¢ãƒ¼ãƒ‰ç„¡)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tèªè¾¼å°‚用モード (\"view\" ã¨åŒã˜)" -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\t制é™ãƒ¢ãƒ¼ãƒ‰ (\"rvim\" ã¨åŒã˜)" - msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\t変更 (ファイルä¿å˜æ™‚) ã‚’ã§ããªã„よã†ã«ã™ã‚‹" diff --git a/src/nvim/po/ko.UTF-8.po b/src/nvim/po/ko.UTF-8.po index 128b238f8b..b99c22caeb 100644 --- a/src/nvim/po/ko.UTF-8.po +++ b/src/nvim/po/ko.UTF-8.po @@ -3438,10 +3438,6 @@ msgstr "-y\t\t\t쉬운 ìƒíƒœ (\"evim\"ê³¼ ê°™ìŒ, modeless)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tì½ê¸° ì „ìš© ìƒíƒœ (\"view\"와 ê°™ìŒ)" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tì œí•œëœ ìƒíƒœ (\"rvim\"ê³¼ ê°™ìŒ)" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tìˆ˜ì •(íŒŒì¼ ì“°ê¸°)ì´ í—ˆìš©ë˜ì§€ 않ìŒ" diff --git a/src/nvim/po/nb.po b/src/nvim/po/nb.po index 34617ccf18..2285d755cf 100644 --- a/src/nvim/po/nb.po +++ b/src/nvim/po/nb.po @@ -3452,10 +3452,6 @@ msgstr "-y\t\t\tLett modus (som \"evim\", uten modus)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tSkrivebeskyttet modus (som \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tBegrenset modus (som \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tModifisering (lagring av filer) ikke tillatt" diff --git a/src/nvim/po/nl.po b/src/nvim/po/nl.po index 30f34508f5..00d113c83c 100644 --- a/src/nvim/po/nl.po +++ b/src/nvim/po/nl.po @@ -3449,10 +3449,6 @@ msgstr "-y\t\t\tEenvoudige modus (zoals \"evim\", zonder modus)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tAlleen-lezen modus (zoals \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tBeperkte modus (zoals \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tAanpassingen (bestanden opslaan) niet toegestaan" diff --git a/src/nvim/po/no.po b/src/nvim/po/no.po index 34617ccf18..2285d755cf 100644 --- a/src/nvim/po/no.po +++ b/src/nvim/po/no.po @@ -3452,10 +3452,6 @@ msgstr "-y\t\t\tLett modus (som \"evim\", uten modus)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tSkrivebeskyttet modus (som \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tBegrenset modus (som \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tModifisering (lagring av filer) ikke tillatt" diff --git a/src/nvim/po/pl.UTF-8.po b/src/nvim/po/pl.UTF-8.po index f5c452e924..5f1779d1bd 100644 --- a/src/nvim/po/pl.UTF-8.po +++ b/src/nvim/po/pl.UTF-8.po @@ -3417,10 +3417,6 @@ msgstr "-y\t\t\tTryb Å‚atwy (jak \"evim\", bez trybów)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tTryb wyłącznie do odczytu (jak \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tTryb ograniczenia (jak \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tModyfikacje (zapisywanie plików) niedozwolone" diff --git a/src/nvim/po/pt_BR.po b/src/nvim/po/pt_BR.po index 4f39cb5bdb..533d916de1 100644 --- a/src/nvim/po/pt_BR.po +++ b/src/nvim/po/pt_BR.po @@ -6229,10 +6229,6 @@ msgstr "-y\t\t\tModo fácil (como \"evim\", o Vim não modal)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tmodo somente-leitura (como \"view\")" -#: ../main.c:2186 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tmodo restrito (como \"rvim\")" - #: ../main.c:2187 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tNão permitir alterações (gravação de arquivos)" diff --git a/src/nvim/po/ru.po b/src/nvim/po/ru.po index 62f892d257..3a96ece2fb 100644 --- a/src/nvim/po/ru.po +++ b/src/nvim/po/ru.po @@ -3442,10 +3442,6 @@ msgstr "-y\t\t\tПроÑтой режим (как \"evim\", безрежимны msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tТолько Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ (как \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tОграниченный режим (как \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tБез возможноÑти ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ (запиÑи файлов)" diff --git a/src/nvim/po/sk.cp1250.po b/src/nvim/po/sk.cp1250.po index ced343bf6b..ff95c68a12 100644 --- a/src/nvim/po/sk.cp1250.po +++ b/src/nvim/po/sk.cp1250.po @@ -3450,10 +3450,6 @@ msgstr "-y\t\t\tJednoduchý mód (rovnaké ako \"evim\", bezmódový)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tMód iba pre èítanie (ako \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tObmedzený mód (rovnaké ako \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tZmeny (ukladanie súborov) zakázané" diff --git a/src/nvim/po/sk.po b/src/nvim/po/sk.po index 66b3d5abb1..d35622726f 100644 --- a/src/nvim/po/sk.po +++ b/src/nvim/po/sk.po @@ -3450,10 +3450,6 @@ msgstr "-y\t\t\tJednoduchý mód (rovnaké ako \"evim\", bezmódový)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tMód iba pre èítanie (ako \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tObmedzený mód (rovnaké ako \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tZmeny (ukladanie súborov) zakázané" diff --git a/src/nvim/po/sr.po b/src/nvim/po/sr.po index 4c157658e5..a93a2ec584 100644 --- a/src/nvim/po/sr.po +++ b/src/nvim/po/sr.po @@ -3028,9 +3028,6 @@ msgstr "-y\t\t\tEasy режим (као \"evim\", безрежимни)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tReadonly режим (као \"view\")" -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tRestricted режим (као \"rvim\")" - msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tИзмене (упиÑивање датотека) ниÑу дозвољене" diff --git a/src/nvim/po/sv.po b/src/nvim/po/sv.po index db7bada888..d50c9d695d 100644 --- a/src/nvim/po/sv.po +++ b/src/nvim/po/sv.po @@ -5735,10 +5735,6 @@ msgstr "-y\t\t\tLätt läge (som \"evim\", lägeslös)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tSkrivskyddat läge (som \"view\")" -#: ../main.c:2186 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tBegränsat läge (som \"rvim\")" - #: ../main.c:2187 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tModifieringar (skriva filer) inte tillåtet" diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po index 604e425bd0..f0ae154648 100644 --- a/src/nvim/po/uk.po +++ b/src/nvim/po/uk.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: vim 7.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-23 18:45+0300\n" +"POT-Creation-Date: 2021-01-18 17:46+0200\n" "PO-Revision-Date: 2020-08-23 20:19+0300\n" "Last-Translator: Ðнатолій Сахнік <sakhnik@gmail.com>\n" "Language-Team: Ukrainian\n" @@ -23,6 +23,67 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +msgid "--Deleted--" +msgstr "--Знищено--" + +#, c-format +msgid "auto-removing autocommand: %s <buffer=%d>" +msgstr "Ðвтоматичне Ð·Ð½Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸: %s <буфер=%d>" + +#, c-format +msgid "E367: No such group: \"%s\"" +msgstr "E367: Ðемає такої групи: «%s»" + +msgid "E936: Cannot delete the current group" +msgstr "E936: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ цю групу" + +msgid "W19: Deleting augroup that is still in use" +msgstr "W19: Ð—Ð½Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð³Ñ€ÑƒÐ¿Ð¸, Ñка вÑе ще викориÑтовуєтьÑÑ" + +#, c-format +msgid "E215: Illegal character after *: %s" +msgstr "E215: Ðедозволений Ñимвол піÑÐ»Ñ *: %s" + +#, c-format +msgid "E216: No such event: %s" +msgstr "E216: Ðемає такої події: %s" + +#, c-format +msgid "E216: No such group or event: %s" +msgstr "E216: Ðемає такої групи чи події: %s" + +msgid "" +"\n" +"--- Autocommands ---" +msgstr "" +"\n" +"--- Ðвтокоманди ---" + +#, c-format +msgid "E680: <buffer=%d>: invalid buffer number " +msgstr "E680: <буфер=%d>: некоректний номер буфера " + +msgid "E217: Can't execute autocommands for ALL events" +msgstr "E217: Ðе можу виконувати автокоманди Ð´Ð»Ñ Ð£Ð¡Ð†Ð¥ подій" + +msgid "No matching autocommands" +msgstr "Ðемає відповідних автокоманд" + +msgid "E218: autocommand nesting too deep" +msgstr "E218: Забагато вкладених автокоманд" + +#, c-format +msgid "%s Autocommands for \"%s\"" +msgstr "%s Ðвтокоманди Ð´Ð»Ñ Â«%s»" + +#, c-format +msgid "Executing %s" +msgstr "ВиконуєтьÑÑ %s" + +#, c-format +msgid "autocommand %s" +msgstr "автокоманда %s" + msgid "[Location List]" msgstr "[СпиÑок міÑць]" @@ -95,9 +156,15 @@ msgid "" "E89: No write since last change for buffer %<PRId64> (add ! to override)" msgstr "E89: Буфер %<PRId64> має зміни (! щоб не зважати)" +msgid "E948: Job still running (add ! to end the job)" +msgstr "E948: Задача вÑе ще виконуєтьÑÑ (! щоб закінчити)" + msgid "E37: No write since last change (add ! to override)" msgstr "E37: Зміни не було запиÑано (! щоб не зважати)" +msgid "E948: Job still running" +msgstr "E948: Задача вÑе ще виконуєтьÑÑ" + msgid "E37: No write since last change" msgstr "E37: Ðе запиÑано піÑÐ»Ñ Ð¾Ñтанніх змін" @@ -465,6 +532,10 @@ msgid "E957: Invalid window number" msgstr "E957: Ðекоректний номер вікна" #, c-format +msgid "E940: Cannot lock or unlock variable %s" +msgstr "E940: Ðеможливо заблокувати чи розблокувати змінну %s" + +#, c-format msgid "E734: Wrong variable type for %s=" msgstr "E734: Ðеправильний тип змінної Ð´Ð»Ñ %s=" @@ -544,10 +615,6 @@ msgstr "E690: Пропущено «in» піÑÐ»Ñ :for" msgid "E108: No such variable: \"%s\"" msgstr "E108: Змінної немає: «%s»" -#, c-format -msgid "E940: Cannot lock or unlock variable %s" -msgstr "E940: Ðеможливо заблокувати чи розблокувати змінну %s" - msgid "E109: Missing ':' after '?'" msgstr "E109: Бракує ':' піÑÐ»Ñ '?'" @@ -950,9 +1017,6 @@ msgstr "E684: Ð†Ð½Ð´ÐµÐºÑ ÑпиÑку поза межами: %<PRId64>" msgid "E686: Argument of %s must be a List" msgstr "E686: Ðргумент у %s має бути ÑпиÑком" -msgid "E928: String required" -msgstr "E928: Потрібен String" - #, c-format msgid "Error converting the call result: %s" msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ результат виклику: %s" @@ -1591,6 +1655,10 @@ msgid "Close \"%s\"?" msgstr "Закрити «%s»?" #, c-format +msgid "E947: Job still running in buffer \"%s\"" +msgstr "E947: Задача вÑе ще запущена у буфері «%s»" + +#, c-format msgid "E162: No write since last change for buffer \"%s\"" msgstr "E162: Буфер «%s» має незбережені зміни" @@ -1615,18 +1683,6 @@ msgid "E666: compiler not supported: %s" msgstr "E666: КомпілÑтор не підтримуєтьÑÑ: %s" #, c-format -msgid "Searching for \"%s\" in \"%s\"" -msgstr "Пошук «%s» в «%s»" - -#, c-format -msgid "Searching for \"%s\"" -msgstr "Пошук «%s»" - -#, c-format -msgid "not found in '%s': \"%s\"" -msgstr "не знайдено в '%s': «%s»" - -#, c-format msgid ":source error parsing command %s" msgstr ":source помилка розбору команди %s" @@ -1702,12 +1758,16 @@ msgstr "Режим Ex. Ð”Ð»Ñ Ð¿Ð¾Ð²ÐµÑ€Ð½ÐµÐ½Ð½Ñ Ð´Ð¾ нормального Ñ msgid "E501: At end-of-file" msgstr "E501: Кінець файлу" -msgid "E169: Command too recursive" -msgstr "E169: Команда занадто рекурÑивна" +#, c-format +msgid "Executing: %s" +msgstr "ВиконуєтьÑÑ: %s" msgid "line %" msgstr "Ñ€Ñдок %" +msgid "E169: Command too recursive" +msgstr "E169: Команда занадто рекурÑивна" + #, c-format msgid "E605: Exception not caught: %s" msgstr "E605: ВинÑткова ÑÐ¸Ñ‚ÑƒÐ°Ñ†Ñ–Ñ Ð½Ðµ оброблена: %s" @@ -1724,9 +1784,6 @@ msgstr "E464: Ðеоднозначний вжиток команди кориÑÑ msgid "E492: Not an editor command" msgstr "E492: Це не команда редактора" -msgid "E981: Command not allowed in restricted mode" -msgstr "E981: Команду не дозволено у обмеженому режимі" - msgid "E493: Backwards range given" msgstr "E493: Інтервал задано навиворіт" @@ -1736,6 +1793,11 @@ msgstr "Інтервал задано навиворіт, щоб помінÑтРmsgid "E494: Use w or w>>" msgstr "E494: Спробуйте w або w>>" +msgid "" +"INTERNAL: Cannot use EX_DFLALL with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX" +msgstr "" +"Ð’ÐУТРІШÐЄ: Ðе можна вживати EX_DFLALL з ADDR_NONE, ADDR_UNSIGNED чи ADDR_QUICKFIX" + msgid "E943: Command table needs to be updated, run 'make'" msgstr "E943: Потрібно поновити таблицю команд, запуÑтіть 'make'" @@ -1762,10 +1824,10 @@ msgstr "E174: Команда вже Ñ–Ñнує, ! щоб замінити Ñ—Ñ—: msgid "" "\n" -" Name Args Address Complete Definition" +" Name Args Address Complete Definition" msgstr "" "\n" -" Ðазва Ðрг. ÐдреÑа Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ" +" Ðазва Ðрг. ÐдреÑа Ð”Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ" msgid "No user-defined commands found" msgstr "Ðе знайдено команд кориÑтувача" @@ -2077,12 +2139,12 @@ msgstr "E347: У шлÑху пошуку більше немає файлів « msgid "E812: Autocommands changed buffer or buffer name" msgstr "E812: Ðвтокоманди змінили буфер чи його назву" -msgid "Illegal file name" -msgstr "Ðедозволена назва файлу" - msgid "is a directory" msgstr "каталог" +msgid "Illegal file name" +msgstr "Ðедозволена назва файлу" + msgid "is not a file" msgstr "не файл" @@ -2104,9 +2166,6 @@ msgstr "E201: Ðвтокоманди *ReadPre не повинні змінюва msgid "E202: Conversion made file unreadable!" msgstr "E202: ÐšÐ¾Ð½Ð²ÐµÑ€Ñ‚Ð°Ñ†Ñ–Ñ ÑƒÐ½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¸Ð»Ð° Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ!" -msgid "[fifo/socket]" -msgstr "[канал/Ñокет]" - msgid "[fifo]" msgstr "[канал]" @@ -2353,67 +2412,6 @@ msgstr "E462: Ðе вдалоÑÑ Ð¿Ñ–Ð´Ð³Ð¾Ñ‚ÑƒÐ²Ð°Ñ‚Ð¸ «%s», щоб пере msgid "E321: Could not reload \"%s\"" msgstr "E321: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ «%s»" -msgid "--Deleted--" -msgstr "--Знищено--" - -#, c-format -msgid "auto-removing autocommand: %s <buffer=%d>" -msgstr "Ðвтоматичне Ð·Ð½Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸: %s <буфер=%d>" - -#, c-format -msgid "E367: No such group: \"%s\"" -msgstr "E367: Ðемає такої групи: «%s»" - -msgid "E936: Cannot delete the current group" -msgstr "E936: Ðе вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸ цю групу" - -msgid "W19: Deleting augroup that is still in use" -msgstr "W19: Ð—Ð½Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð³Ñ€ÑƒÐ¿Ð¸, Ñка вÑе ще викориÑтовуєтьÑÑ" - -#, c-format -msgid "E215: Illegal character after *: %s" -msgstr "E215: Ðедозволений Ñимвол піÑÐ»Ñ *: %s" - -#, c-format -msgid "E216: No such event: %s" -msgstr "E216: Ðемає такої події: %s" - -#, c-format -msgid "E216: No such group or event: %s" -msgstr "E216: Ðемає такої групи чи події: %s" - -msgid "" -"\n" -"--- Autocommands ---" -msgstr "" -"\n" -"--- Ðвтокоманди ---" - -#, c-format -msgid "E680: <buffer=%d>: invalid buffer number " -msgstr "E680: <буфер=%d>: некоректний номер буфера " - -msgid "E217: Can't execute autocommands for ALL events" -msgstr "E217: Ðе можу виконувати автокоманди Ð´Ð»Ñ Ð£Ð¡Ð†Ð¥ подій" - -msgid "No matching autocommands" -msgstr "Ðемає відповідних автокоманд" - -msgid "E218: autocommand nesting too deep" -msgstr "E218: Забагато вкладених автокоманд" - -#, c-format -msgid "%s Autocommands for \"%s\"" -msgstr "%s Ðвтокоманди Ð´Ð»Ñ Â«%s»" - -#, c-format -msgid "Executing %s" -msgstr "ВиконуєтьÑÑ %s" - -#, c-format -msgid "autocommand %s" -msgstr "автокоманда %s" - msgid "E219: Missing {." msgstr "E219: Бракує {." @@ -2519,9 +2517,6 @@ msgstr "E685: Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°: %s" msgid "Interrupted" msgstr "Перервано" -msgid "E14: Invalid address" -msgstr "E14: Ðеправильна адреÑа" - msgid "E474: Invalid argument" msgstr "E474: Ðекоректний аргумент" @@ -2719,6 +2714,9 @@ msgstr "E45: Ð’Ñтановлено опцію 'readonly' (! щоб не зваРmsgid "E46: Cannot change read-only variable \"%.*s\"" msgstr "E46: Змінна тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ: «%.*s»" +msgid "E928: String required" +msgstr "E928: Потрібен String" + msgid "E715: Dictionary required" msgstr "E715: Потрібен Ñловник" @@ -2727,8 +2725,8 @@ msgid "E118: Too many arguments for function: %s" msgstr "E118: Забагато аргументів Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ—: %s" #, c-format -msgid "E716: Key not present in Dictionary: %s" -msgstr "E716: Ðемає такого ключа у Ñловнику: %s" +msgid "E716: Key not present in Dictionary: \"%s\"" +msgstr "E716: Ðемає такого ключа у Ñловнику: «%s»" msgid "E714: List required" msgstr "E714: Потрібен ÑпиÑок" @@ -3158,6 +3156,10 @@ msgid "E5106: Error while creating shared module: %.*s" msgstr "E5106: Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð´Ñ–Ð»ÑŽÐ²Ð°Ð½Ð¾Ð³Ð¾ модулÑ: %.*s" #, c-format +msgid "E5106: Error while creating inspect module: %.*s" +msgstr "E5106: Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ inspect: %.*s" + +#, c-format msgid "E5106: Error while creating vim module: %.*s" msgstr "E5106: Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ vim: %.*s" @@ -3165,10 +3167,6 @@ msgid "E970: Failed to initialize lua interpreter" msgstr "E970: Ðе вдалоÑÑ Ñ–Ð½Ñ–Ñ†Ñ–Ð°Ð»Ñ–Ð·ÑƒÐ²Ð°Ñ‚Ð¸ інтерпретатор lua" #, c-format -msgid "E5117: Error while updating package paths: %.*s" -msgstr "E5117: Помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑˆÐ»Ñхів пакунку: %.*s" - -#, c-format msgid "E5114: Error while converting print argument #%i: %.*s" msgstr "E5114: Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€Ð¸Ñ‚Ð¸ аргумент #%i друку: %.*s" @@ -3256,6 +3254,10 @@ msgid "pre-vimrc command line" msgstr "команди перед vimrc" #, c-format +msgid "Conflicting configs: \"%s\" \"%s\"" +msgstr "Суперечливі конфігурації: «%s» «%s»" + +#, c-format msgid "E282: Cannot read from \"%s\"" msgstr "E282: Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ñ‡Ð¸Ñ‚Ð°Ñ‚Ð¸ з «%s»" @@ -3367,9 +3369,6 @@ msgstr " -v, --version Ðадрукувати інформацію пр msgid " -V[N][file] Verbose [level][file]\n" msgstr " -V[N][файл] Більше повідомлень [рівень][файл]\n" -msgid " -Z Restricted mode\n" -msgstr " -Z Обмежений режим\n" - msgid " --api-info Write msgpack-encoded API metadata to stdout\n" msgstr "" " --api-info ЗапиÑати метадані API, Ñеріалізовані у msgpack, у " @@ -4005,8 +4004,7 @@ msgstr "" "Введіть :qa! Ñ– натиÑніÑть <Enter> щоб відкинути вÑÑ– зміни Ñ– вийти Nvim" msgid "Type :qa and press <Enter> to exit Nvim" -msgstr "" -"Введіть :qa Ñ– натиÑніÑть <Enter> щоб вийти з Nvim" +msgstr "Введіть :qa Ñ– натиÑніÑть <Enter> щоб вийти з Nvim" #, c-format msgid "1 line %sed 1 time" @@ -4071,10 +4069,10 @@ msgstr "E353: У регіÑтрі %s нічого немає" msgid "" "\n" -"--- Registers ---" +"Type Name Content" msgstr "" "\n" -"--- РегіÑтри ---" +"Тип Ðаз. ВміÑÑ‚ " msgid "" "E883: search pattern and expression register may not contain two or more " @@ -4187,9 +4185,6 @@ msgstr "E537: 'commentstring' має бути порожньою чи міÑти msgid "E540: Unclosed expression sequence" msgstr "E540: ПоÑлідовніÑть виразів не завершено" -msgid "E541: too many items" -msgstr "E541: Забагато елементів" - msgid "E542: unbalanced groups" msgstr "E542: Групи не збаланÑовано" @@ -4277,6 +4272,9 @@ msgstr "" msgid "E5677: Error writing input to shell-command: %s" msgstr "E5677: Ðе вдалоÑÑ Ð·Ð°Ð¿Ð¸Ñати на вхід команди оболонки: %s" +msgid "%a %b %d %H:%M:%S %Y" +msgstr "%H:%M:%S %a, %d %B %Y Ñ€." + #, c-format msgid "E447: Can't find file \"%s\" in path" msgstr "E447: Файл «%s» не знайдено у шлÑху пошуку" @@ -4284,8 +4282,11 @@ msgstr "E447: Файл «%s» не знайдено у шлÑху пошуку" msgid "E553: No more items" msgstr "E553: Ðемає більше елементів" +msgid "E925: Current quickfix list was changed" +msgstr "E925: Поточний ÑпиÑок quickfix змінивÑÑ" + msgid "E926: Current location list was changed" -msgstr "E926: Цей ÑпиÑок міÑць було змінено" +msgstr "E926: Поточний ÑпиÑок міÑць змінивÑÑ" #, c-format msgid "E372: Too many %%%c in format string" @@ -4319,9 +4320,6 @@ msgstr "E379: Пропущена чи Ð¿Ð¾Ñ€Ð¾Ð¶Ð½Ñ Ð½Ð°Ð·Ð²Ð° каталогу msgid "E924: Current window was closed" msgstr "E924: Ðктивне вікно було закрито" -msgid "E925: Current quickfix was changed" -msgstr "E925: Цей quickfix було змінено" - #, c-format msgid "(%d of %d)%s%s: " msgstr "(%d з %d)%s%s: " @@ -4349,6 +4347,9 @@ msgstr "E683: Пропущено назву файлу чи некоректни msgid "Cannot open file \"%s\"" msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл «%s»" +msgid "cannot have both a list and a \"what\" argument" +msgstr "не можна задавати одночаÑно ÑпиÑок Ñ– аргумент «що»" + msgid "E681: Buffer is not loaded" msgstr "E681: Буфер не завантажено" @@ -4469,6 +4470,18 @@ msgstr "" msgid "Switching to backtracking RE engine for pattern: " msgstr "ÐŸÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð´Ð¾ проÑтого Ñ€ÑƒÑˆÑ–Ñ Ñ€ÐµÐ³ÑƒÐ»Ñрних виразів: " +#, c-format +msgid "Searching for \"%s\" in \"%s\"" +msgstr "Пошук «%s» в «%s»" + +#, c-format +msgid "Searching for \"%s\"" +msgstr "Пошук «%s»" + +#, c-format +msgid "not found in '%s': \"%s\"" +msgstr "не знайдено в '%s': «%s»" + msgid " TERMINAL" msgstr " ТЕРМІÐÐЛ" @@ -5252,6 +5265,9 @@ msgstr "ÑинхронізуєтьÑÑ Ð¿Ð¾ коментарÑÑ… Ñтилю С" msgid "no syncing" msgstr "без Ñинхронізації" +msgid "syncing starts at the first line" +msgstr "ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð¿Ð¾Ñ‡Ð¸Ð½Ð°Ñ”Ñ‚ÑŒÑÑ Ð· першого Ñ€Ñдка" + msgid "syncing starts " msgstr "починаєтьÑÑ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ð·Ð° " @@ -5283,6 +5299,9 @@ msgstr "" msgid "E392: No such syntax cluster: %s" msgstr "E392: Ðемає такого ÑинтакÑичного клаÑтера: %s" +msgid "from the first line" +msgstr "з першого Ñ€Ñдка" + msgid "minimal " msgstr "мінімальний " diff --git a/src/nvim/po/vi.po b/src/nvim/po/vi.po index a954ea6e34..c693f910d8 100644 --- a/src/nvim/po/vi.po +++ b/src/nvim/po/vi.po @@ -3479,10 +3479,6 @@ msgstr "-y\t\t\tChế độ đơn giản (giống \"evim\", không có chế Ä‘á msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tChế độ chỉ Ä‘á»c (giống \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\tChế độ hạn chế (giống \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tKhông có khả năng ghi nhá»› thay đổi (ghi nhá»› táºp tin)" diff --git a/src/nvim/po/zh_CN.UTF-8.po b/src/nvim/po/zh_CN.UTF-8.po index 542157002a..1e329443ce 100644 --- a/src/nvim/po/zh_CN.UTF-8.po +++ b/src/nvim/po/zh_CN.UTF-8.po @@ -3427,10 +3427,6 @@ msgstr "-y\t\t\tå®¹æ˜“æ¨¡å¼ (åŒ \"evim\"ï¼Œæ— æ¨¡å¼)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tåªè¯»æ¨¡å¼ (åŒ \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\té™åˆ¶æ¨¡å¼ (åŒ \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tä¸å¯ä¿®æ”¹(写入文件)" diff --git a/src/nvim/po/zh_TW.UTF-8.po b/src/nvim/po/zh_TW.UTF-8.po index 6a11b5e669..c97f31ddcf 100644 --- a/src/nvim/po/zh_TW.UTF-8.po +++ b/src/nvim/po/zh_TW.UTF-8.po @@ -3482,10 +3482,6 @@ msgstr "-y\t\t\tç°¡æ˜“æ¨¡å¼ (åŒ \"evim\", modeless)" msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tå”¯è®€æ¨¡å¼ (åŒ \"view\")" -#: ../main.c:2208 -msgid "-Z\t\t\tRestricted mode (like \"rvim\")" -msgstr "-Z\t\t\té™åˆ¶æ¨¡å¼ (åŒ \"rvim\")" - #: ../main.c:2209 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tä¸å¯ä¿®æ”¹ (寫入檔案)" diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index aeac6e4905..a625c09f78 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -143,6 +143,7 @@ struct efm_S { // 'E' error message // 'W' warning message // 'I' informational message + // 'N' note message // 'C' continuation line // 'Z' end of multi-line message // 'G' general, unspecific message @@ -457,7 +458,7 @@ static const char_u *efm_analyze_prefix(const char_u *efmp, efm_T *efminfo, if (vim_strchr((char_u *)"+-", *efmp) != NULL) { efminfo->flags = *efmp++; } - if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) { + if (vim_strchr((char_u *)"DXAEWINCZGOPQ", *efmp) != NULL) { efminfo->prefix = *efmp; } else { snprintf((char *)errmsg, errmsglen, @@ -967,7 +968,7 @@ restofline: fmt_start = fmt_ptr; } - if (vim_strchr((char_u *)"AEWI", idx) != NULL) { + if (vim_strchr((char_u *)"AEWIN", idx) != NULL) { qfl->qf_multiline = true; // start of a multi-line message qfl->qf_multiignore = false; // reset continuation } else if (vim_strchr((char_u *)"CZ", idx) != NULL) { @@ -1499,7 +1500,7 @@ static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, if ((idx == 'C' || idx == 'Z') && !qf_multiline) { return QF_FAIL; } - if (vim_strchr((char_u *)"EWI", idx) != NULL) { + if (vim_strchr((char_u *)"EWIN", idx) != NULL) { fields->type = idx; } else { fields->type = 0; @@ -3300,6 +3301,24 @@ void qf_history(exarg_T *eap) qf_info_T *qi = qf_cmd_get_stack(eap, false); int i; + if (eap->addr_count > 0) { + if (qi == NULL) { + EMSG(_(e_loclist)); + return; + } + + // Jump to the specified quickfix list + if (eap->line2 > 0 && eap->line2 <= qi->qf_listcount) { + qi->qf_curlist = (int)(eap->line2 - 1); + qf_msg(qi, qi->qf_curlist, ""); + qf_update_buffer(qi, NULL); + } else { + EMSG(_(e_invrange)); + } + + return; + } + if (qf_stack_empty(qi)) { MSG(_("No entries")); } else { @@ -3414,11 +3433,13 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, // e or E 0 " error" // w or W 0 " warning" // i or I 0 " info" +// n or N 0 " note" // 0 0 "" // other 0 " c" // e or E n " error n" // w or W n " warning n" // i or I n " info n" +// n or N n " note n" // 0 n " error n" // other n " c n" // 1 x "" :helpgrep @@ -3428,15 +3449,17 @@ static char_u *qf_types(int c, int nr) static char_u cc[3]; char_u *p; - if (c == 'W' || c == 'w') + if (c == 'W' || c == 'w') { p = (char_u *)" warning"; - else if (c == 'I' || c == 'i') + } else if (c == 'I' || c == 'i') { p = (char_u *)" info"; - else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) + } else if (c == 'N' || c == 'n') { + p = (char_u *)" note"; + } else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) { p = (char_u *)" error"; - else if (c == 0 || c == 1) + } else if (c == 0 || c == 1) { p = (char_u *)""; - else { + } else { cc[0] = ' '; cc[1] = (char_u)c; cc[2] = NUL; @@ -3622,7 +3645,7 @@ static int qf_open_new_cwindow(qf_info_T *qi, int height) // Set the options for the quickfix buffer/window (if not already done) // Do this even if the quickfix buffer was already present, as an autocmd // might have previously deleted (:bdelete) the quickfix buffer. - if (curbuf->b_p_bt[0] != 'q') { + if (!bt_quickfix(curbuf)) { qf_set_cwindow_options(); } @@ -4269,11 +4292,22 @@ static char_u *get_mef_name(void) return name; } -/// Returns the number of valid entries in the current quickfix/location list. +/// Returns the number of entries in the current quickfix/location list. size_t qf_get_size(exarg_T *eap) FUNC_ATTR_NONNULL_ALL { qf_info_T *qi; + + if ((qi = qf_cmd_get_stack(eap, false)) == NULL) { + return 0; + } + return (size_t)qf_get_curlist(qi)->qf_count; +} + +/// Returns the number of valid entries in the current quickfix/location list. +size_t qf_get_valid_size(exarg_T *eap) +{ + qf_info_T *qi; qf_list_T *qfl; if ((qi = qf_cmd_get_stack(eap, false)) == NULL) { @@ -4562,74 +4596,150 @@ static qfline_T * qf_find_last_entry_on_line(qfline_T *entry, int *errornr) return entry; } -/// Find the first quickfix entry below line 'lnum' in buffer 'bnr'. +// Returns true if the specified quickfix entry is +// after the given line (linewise is true) +// or after the line and column. +static bool qf_entry_after_pos(const qfline_T *qfp, const pos_T *pos, + bool linewise) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (linewise) { + return qfp->qf_lnum > pos->lnum; + } + return qfp->qf_lnum > pos->lnum + || (qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col); +} + +// Returns true if the specified quickfix entry is +// before the given line (linewise is true) +// or before the line and column. +static bool qf_entry_before_pos(const qfline_T *qfp, const pos_T *pos, + bool linewise) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (linewise) { + return qfp->qf_lnum < pos->lnum; + } + return qfp->qf_lnum < pos->lnum + || (qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col); +} + +// Returns true if the specified quickfix entry is +// on or after the given line (linewise is true) +// or on or after the line and column. +static bool qf_entry_on_or_after_pos(const qfline_T *qfp, const pos_T *pos, + bool linewise) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (linewise) { + return qfp->qf_lnum >= pos->lnum; + } + return qfp->qf_lnum > pos->lnum + || (qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col); +} + +// Returns true if the specified quickfix entry is +// on or before the given line (linewise is true) +// or on or before the line and column. +static bool qf_entry_on_or_before_pos(const qfline_T *qfp, const pos_T *pos, + bool linewise) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (linewise) { + return qfp->qf_lnum <= pos->lnum; + } + return qfp->qf_lnum < pos->lnum + || (qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col); +} + +/// Find the first quickfix entry after position 'pos' in buffer 'bnr'. +/// If 'linewise' is true, returns the entry after the specified line and treats +/// multiple entries on a single line as one. Otherwise returns the entry after +/// the specified line and column. /// 'qfp' points to the very first entry in the buffer and 'errornr' is the /// index of the very first entry in the quickfix list. -/// Returns NULL if an entry is not found after 'lnum'. -static qfline_T *qf_find_entry_on_next_line(int bnr, - linenr_T lnum, - qfline_T *qfp, - int *errornr) +/// Returns NULL if an entry is not found after 'pos'. +static qfline_T *qf_find_entry_after_pos( + int bnr, + const pos_T *pos, + bool linewise, + qfline_T *qfp, + int *errornr +) + FUNC_ATTR_NONNULL_ALL { - if (qfp->qf_lnum > lnum) { - // First entry is after line 'lnum' + if (qf_entry_after_pos(qfp, pos, linewise)) { + // First entry is after postion 'pos' return qfp; } - // Find the entry just before or at the line 'lnum' + // Find the entry just before or at the position 'pos' while (qfp->qf_next != NULL && qfp->qf_next->qf_fnum == bnr - && qfp->qf_next->qf_lnum <= lnum) { + && qf_entry_on_or_before_pos(qfp->qf_next, pos, linewise)) { qfp = qfp->qf_next; (*errornr)++; } if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr) { - // No entries found after 'lnum' + // No entries found after position 'pos' return NULL; } - // Use the entry just after line 'lnum' + // Use the entry just after position 'pos' qfp = qfp->qf_next; (*errornr)++; return qfp; } -/// Find the first quickfix entry before line 'lnum' in buffer 'bnr'. +/// Find the first quickfix entry before position 'pos' in buffer 'bnr'. +/// If 'linewise' is true, returns the entry before the specified line and +/// treats multiple entries on a single line as one. Otherwise returns the entry +/// before the specified line and column. /// 'qfp' points to the very first entry in the buffer and 'errornr' is the /// index of the very first entry in the quickfix list. -/// Returns NULL if an entry is not found before 'lnum'. -static qfline_T *qf_find_entry_on_prev_line(int bnr, - linenr_T lnum, - qfline_T *qfp, - int *errornr) +/// Returns NULL if an entry is not found before 'pos'. +static qfline_T *qf_find_entry_before_pos( + int bnr, + const pos_T *pos, + bool linewise, + qfline_T *qfp, + int *errornr +) + FUNC_ATTR_NONNULL_ALL { - // Find the entry just before the line 'lnum' + // Find the entry just before the position 'pos' while (qfp->qf_next != NULL && qfp->qf_next->qf_fnum == bnr - && qfp->qf_next->qf_lnum < lnum) { + && qf_entry_before_pos(qfp->qf_next, pos, linewise)) { qfp = qfp->qf_next; (*errornr)++; } - if (qfp->qf_lnum >= lnum) { // entry is after 'lnum' + if (qf_entry_on_or_after_pos(qfp, pos, linewise)) { return NULL; } - // If multiple entries are on the same line, then use the first entry - qfp = qf_find_first_entry_on_line(qfp, errornr); + if (linewise) { + // If multiple entries are on the same line, then use the first entry + qfp = qf_find_first_entry_on_line(qfp, errornr); + } return qfp; } -/// Find a quickfix entry in 'qfl' closest to line 'lnum' in buffer 'bnr' in +/// Find a quickfix entry in 'qfl' closest to position 'pos' in buffer 'bnr' in /// the direction 'dir'. -static qfline_T *qf_find_closest_entry(qf_list_T *qfl, - int bnr, - linenr_T lnum, - int dir, - int *errornr) +static qfline_T *qf_find_closest_entry( + qf_list_T *qfl, + int bnr, + const pos_T *pos, + Direction dir, + bool linewise, + int *errornr +) + FUNC_ATTR_NONNULL_ALL { qfline_T *qfp; @@ -4642,33 +4752,38 @@ static qfline_T *qf_find_closest_entry(qf_list_T *qfl, } if (dir == FORWARD) { - qfp = qf_find_entry_on_next_line(bnr, lnum, qfp, errornr); + qfp = qf_find_entry_after_pos(bnr, pos, linewise, qfp, errornr); } else { - qfp = qf_find_entry_on_prev_line(bnr, lnum, qfp, errornr); + qfp = qf_find_entry_before_pos(bnr, pos, linewise, qfp, errornr); } return qfp; } -/// Get the nth quickfix entry below the specified entry treating multiple -/// entries on a single line as one. Searches forward in the list. -static void qf_get_nth_below_entry(qfline_T *entry, - int *errornr, - linenr_T n) +/// Get the nth quickfix entry below the specified entry. Searches forward in +/// the list. If linewise is true, then treat multiple entries on a single line +/// as one. +static void qf_get_nth_below_entry(qfline_T *entry, linenr_T n, + bool linewise, int *errornr) + FUNC_ATTR_NONNULL_ALL { while (n-- > 0 && !got_int) { // qfline_T *first_entry = entry; int first_errornr = *errornr; - // Treat all the entries on the same line in this file as one - entry = qf_find_last_entry_on_line(entry, errornr); + if (linewise) { + // Treat all the entries on the same line in this file as one + entry = qf_find_last_entry_on_line(entry, errornr); + } if (entry->qf_next == NULL || entry->qf_next->qf_fnum != entry->qf_fnum) { - // If multiple entries are on the same line, then use the first - // entry - // entry = first_entry; - *errornr = first_errornr; + if (linewise) { + // If multiple entries are on the same line, then use the first + // entry + // entry = first_entry; + *errornr = first_errornr; + } break; } @@ -4677,11 +4792,12 @@ static void qf_get_nth_below_entry(qfline_T *entry, } } -/// Get the nth quickfix entry above the specified entry treating multiple -/// entries on a single line as one. Searches backwards in the list. -static void qf_get_nth_above_entry(qfline_T *entry, - int *errornr, - linenr_T n) +/// Get the nth quickfix entry above the specified entry. Searches backwards in +/// the list. If linewise is TRUE, then treat multiple entries on a single line +/// as one. +static void qf_get_nth_above_entry(qfline_T *entry, linenr_T n, + bool linewise, int *errornr) + FUNC_ATTR_NONNULL_ALL { while (n-- > 0 && !got_int) { if (entry->qf_prev == NULL @@ -4692,25 +4808,30 @@ static void qf_get_nth_above_entry(qfline_T *entry, entry = entry->qf_prev; (*errornr)--; - // If multiple entries are on the same line, then use the first entry - entry = qf_find_first_entry_on_line(entry, errornr); + if (linewise) { + entry = qf_find_first_entry_on_line(entry, errornr); + } } } -/// Find the n'th quickfix entry adjacent to line 'lnum' in buffer 'bnr' in the -/// specified direction. -/// Returns the error number in the quickfix list or 0 if an entry is not found. -static int qf_find_nth_adj_entry(qf_list_T *qfl, - int bnr, - linenr_T lnum, - linenr_T n, - int dir) +/// Find the n'th quickfix entry adjacent to position 'pos' in buffer 'bnr' in +/// the specified direction. Returns the error number in the quickfix list or 0 +/// if an entry is not found. +static int qf_find_nth_adj_entry( + qf_list_T *qfl, + int bnr, + pos_T *pos, + linenr_T n, + Direction dir, + bool linewise +) + FUNC_ATTR_NONNULL_ALL { - qfline_T *adj_entry; int errornr; - // Find an entry closest to the specified line - adj_entry = qf_find_closest_entry(qfl, bnr, lnum, dir, &errornr); + // Find an entry closest to the specified position + qfline_T *const adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir, + linewise, &errornr); if (adj_entry == NULL) { return 0; } @@ -4718,24 +4839,25 @@ static int qf_find_nth_adj_entry(qf_list_T *qfl, if (--n > 0) { // Go to the n'th entry in the current buffer if (dir == FORWARD) { - qf_get_nth_below_entry(adj_entry, &errornr, n); + qf_get_nth_below_entry(adj_entry, n, linewise, &errornr); } else { - qf_get_nth_above_entry(adj_entry, &errornr, n); + qf_get_nth_above_entry(adj_entry, n, linewise, &errornr); } } return errornr; } -/// Jump to a quickfix entry in the current file nearest to the current line. -/// ":cabove", ":cbelow", ":labove" and ":lbelow" commands +/// Jump to a quickfix entry in the current file nearest to the current line or +/// current line/col. +/// ":cabove", ":cbelow", ":labove", ":lbelow", ":cafter", ":cbefore", +/// ":lafter" and ":lbefore" commands void ex_cbelow(exarg_T *eap) { qf_info_T *qi; qf_list_T *qfl; int dir; int buf_has_flag; - int errornr = 0; if (eap->addr_count > 0 && eap->line2 <= 0) { EMSG(_(e_invrange)); @@ -4743,7 +4865,8 @@ void ex_cbelow(exarg_T *eap) } // Check whether the current buffer has any quickfix entries - if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow) { + if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow + || eap->cmdidx == CMD_cbefore || eap->cmdidx == CMD_cafter) { buf_has_flag = BUF_HAS_QF_ENTRY; } else { buf_has_flag = BUF_HAS_LL_ENTRY; @@ -4764,14 +4887,30 @@ void ex_cbelow(exarg_T *eap) return; } - if (eap->cmdidx == CMD_cbelow || eap->cmdidx == CMD_lbelow) { + if (eap->cmdidx == CMD_cbelow + || eap->cmdidx == CMD_lbelow + || eap->cmdidx == CMD_cafter + || eap->cmdidx == CMD_lafter) { + // Forward motion commands dir = FORWARD; } else { dir = BACKWARD; } - errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, curwin->w_cursor.lnum, - eap->addr_count > 0 ? eap->line2 : 0, dir); + pos_T pos = curwin->w_cursor; + // A quickfix entry column number is 1 based whereas cursor column + // number is 0 based. Adjust the column number. + pos.col++; + const int errornr = qf_find_nth_adj_entry( + qfl, + curbuf->b_fnum, + &pos, + eap->addr_count > 0 ? eap->line2 : 0, + dir, + eap->cmdidx == CMD_cbelow + || eap->cmdidx == CMD_lbelow + || eap->cmdidx == CMD_cabove + || eap->cmdidx == CMD_labove); if (errornr > 0) { qf_jump(qi, 0, errornr, false); @@ -6818,8 +6957,9 @@ void ex_helpgrep(exarg_T *eap) if (au_name != NULL) { apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf); - if (!new_qi && IS_LL_STACK(qi) && qf_find_buf(qi) == NULL) { - // autocommands made "qi" invalid + // When adding a location list to an existing location list stack, + // if the autocmd made the stack invalid, then just return. + if (!new_qi && IS_LL_STACK(qi) && qf_find_win_with_loclist(qi) == NULL) { decr_quickfix_busy(); return; } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index a7fd2bfcc6..a78f905a70 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2417,8 +2417,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } } - if (wp->w_p_list) { - if (curwin->w_p_lcs_chars.space + if (wp->w_p_list && !has_fold) { + if (wp->w_p_lcs_chars.space || wp->w_p_lcs_chars.trail || wp->w_p_lcs_chars.nbsp) { extra_check = true; @@ -2665,7 +2665,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } } - //sign column + // sign column, this is hit until sign_idx reaches count if (draw_state == WL_SIGN - 1 && n_extra == 0) { draw_state = WL_SIGN; /* Show the sign column when there are any signs in this @@ -2883,8 +2883,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } if (draw_state == WL_LINE - && foldinfo.fi_level != 0 - && foldinfo.fi_lines > 0 + && has_fold && vcol == 0 && n_extra == 0 && row == startrow) { @@ -2905,8 +2904,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } if (draw_state == WL_LINE - && foldinfo.fi_level != 0 - && foldinfo.fi_lines > 0 + && has_fold && col < grid->Columns && n_extra == 0 && row == startrow) { @@ -2918,8 +2916,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } if (draw_state == WL_LINE - && foldinfo.fi_level != 0 - && foldinfo.fi_lines > 0 + && has_fold && col >= grid->Columns && n_extra != 0 && row == startrow) { @@ -3087,7 +3084,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, || vcol < fromcol || vcol_prev < fromcol_prev || vcol >= tocol)) { char_attr = line_attr; - } else { + } else { attr_pri = false; if (has_syntax) { char_attr = syntax_attr; @@ -3742,7 +3739,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } wp->w_wrow = row; did_wcol = true; - curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; + wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; } // Don't override visual selection highlighting. @@ -3835,9 +3832,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, // Add a blank character to highlight. schar_from_ascii(linebuf_char[off], ' '); } - if (area_attr == 0) { - /* Use attributes from match with highest priority among - * 'search_hl' and the match list. */ + if (area_attr == 0 && !has_fold) { + // Use attributes from match with highest priority among + // 'search_hl' and the match list. char_attr = search_hl.attr; cur = wp->w_match_head; shl_flag = FALSE; @@ -4053,6 +4050,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, && !wp->w_p_wrap && filler_todo <= 0 && (wp->w_p_rl ? col == 0 : col == grid->Columns - 1) + && !has_fold && (*ptr != NUL || lcs_eol_one > 0 || (n_extra && (c_extra != NUL || *p_extra != NUL)))) { @@ -4347,6 +4345,10 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off) // Get information needed to display the sign in line 'lnum' in window 'wp'. // If 'nrcol' is TRUE, the sign is going to be displayed in the number column. // Otherwise the sign is going to be displayed in the sign column. +// +// @param count max number of signs +// @param[out] n_extrap number of characters from pp_extra to display +// @param[in, out] sign_idxp Index of the displayed sign static void get_sign_display_info( bool nrcol, win_T *wp, @@ -4423,6 +4425,8 @@ static void get_sign_display_info( (*sign_idxp)++; if (*sign_idxp < count) { *draw_statep = WL_SIGN - 1; + } else { + *sign_idxp = 0; } } diff --git a/src/nvim/search.c b/src/nvim/search.c index 787a464070..2802da6f7f 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -4497,9 +4497,9 @@ find_pattern_in_path( regmatch_T regmatch; regmatch_T incl_regmatch; regmatch_T def_regmatch; - int matched = FALSE; - int did_show = FALSE; - int found = FALSE; + bool matched = false; + bool did_show = false; + bool found = false; int i; char_u *already = NULL; char_u *startp = NULL; @@ -4611,7 +4611,7 @@ find_pattern_in_path( } MSG_PUTS_TITLE(_("in path ---\n")); } - did_show = TRUE; + did_show = true; while (depth_displayed < depth && !got_int) { ++depth_displayed; for (i = 0; i < depth_displayed; i++) @@ -4761,10 +4761,10 @@ search_line: matched = !STRNCMP(startp, ptr, len); if (matched && define_matched && whole && vim_iswordc(startp[len])) - matched = FALSE; + matched = false; } else if (regmatch.regprog != NULL && vim_regexec(®match, line, (colnr_T)(p - line))) { - matched = TRUE; + matched = true; startp = regmatch.startp[0]; // Check if the line is not a comment line (unless we are // looking for a define). A line starting with "# define" @@ -4789,15 +4789,16 @@ search_line: if (matched && p[0] == '/' && (p[1] == '*' || p[1] == '/')) { - matched = FALSE; - /* After "//" all text is comment */ - if (p[1] == '/') + matched = false; + // After "//" all text is comment + if (p[1] == '/') { break; - ++p; + } + p++; } else if (!matched && p[0] == '*' && p[1] == '/') { - /* Can find match after "* /". */ - matched = TRUE; - ++p; + // Can find match after "* /". + matched = true; + p++; } } } @@ -4811,7 +4812,7 @@ search_line: if (depth == -1 && lnum == curwin->w_cursor.lnum) break; - found = TRUE; + found = true; aux = p = startp; if (compl_cont_status & CONT_ADDING) { p += compl_length; @@ -4879,9 +4880,10 @@ search_line: break; } } else if (action == ACTION_SHOW_ALL) { - found = TRUE; - if (!did_show) - gotocmdline(TRUE); /* cursor at status line */ + found = true; + if (!did_show) { + gotocmdline(true); // cursor at status line + } if (curr_fname != prev_fname) { if (did_show) msg_putchar('\n'); /* cursor below last one */ @@ -4890,28 +4892,28 @@ search_line: msg_home_replace_hl(curr_fname); prev_fname = curr_fname; } - did_show = TRUE; - if (!got_int) - show_pat_in_path(line, type, TRUE, action, - (depth == -1) ? NULL : files[depth].fp, - (depth == -1) ? &lnum : &files[depth].lnum, - match_count++); + did_show = true; + if (!got_int) { + show_pat_in_path(line, type, true, action, + (depth == -1) ? NULL : files[depth].fp, + (depth == -1) ? &lnum : &files[depth].lnum, + match_count++); + } /* Set matched flag for this file and all the ones that * include it */ for (i = 0; i <= depth; ++i) files[i].matched = TRUE; } else if (--count <= 0) { - found = TRUE; + found = true; if (depth == -1 && lnum == curwin->w_cursor.lnum - && l_g_do_tagpreview == 0 - ) + && l_g_do_tagpreview == 0) { EMSG(_("E387: Match is on current line")); - else if (action == ACTION_SHOW) { + } else if (action == ACTION_SHOW) { show_pat_in_path(line, type, did_show, action, - (depth == -1) ? NULL : files[depth].fp, - (depth == -1) ? &lnum : &files[depth].lnum, 1L); - did_show = TRUE; + (depth == -1) ? NULL : files[depth].fp, + (depth == -1) ? &lnum : &files[depth].lnum, 1L); + did_show = true; } else { /* ":psearch" uses the preview window */ if (l_g_do_tagpreview != 0) { @@ -4960,15 +4962,16 @@ search_line: break; } exit_matched: - matched = FALSE; - /* look for other matches in the rest of the line if we - * are not at the end of it already */ + matched = false; + // look for other matches in the rest of the line if we + // are not at the end of it already if (def_regmatch.regprog == NULL && action == ACTION_EXPAND && !(compl_cont_status & CONT_SOL) && *startp != NUL - && *(p = startp + utfc_ptr2len(startp)) != NUL) + && *(p = startp + utfc_ptr2len(startp)) != NUL) { goto search_line; + } } line_breakcheck(); if (action == ACTION_EXPAND) @@ -5046,16 +5049,20 @@ fpip_end: vim_regfree(def_regmatch.regprog); } -static void show_pat_in_path(char_u *line, int type, int did_show, int action, FILE *fp, linenr_T *lnum, long count) +static void show_pat_in_path(char_u *line, int type, bool did_show, int action, + FILE *fp, linenr_T *lnum, long count) + FUNC_ATTR_NONNULL_ARG(1, 6) { char_u *p; - if (did_show) - msg_putchar('\n'); /* cursor below last one */ - else if (!msg_silent) - gotocmdline(TRUE); /* cursor at status line */ - if (got_int) /* 'q' typed at "--more--" message */ + if (did_show) { + msg_putchar('\n'); // cursor below last one + } else if (!msg_silent) { + gotocmdline(true); // cursor at status line + } + if (got_int) { // 'q' typed at "--more--" message return; + } for (;; ) { p = line + STRLEN(line) - 1; if (fp != NULL) { diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 4d88df5a3a..f99eca7953 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4275,7 +4275,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing) * Everything that's left, up to the next command, should be the * filename to include. */ - eap->argt |= (XFILE | NOSPC); + eap->argt |= (EX_XFILE | EX_NOSPC); separate_nextcmd(eap); if (*eap->arg == '<' || *eap->arg == '$' || path_is_absolute(eap->arg)) { // For an absolute path, "$VIM/..." or "<sfile>.." we ":source" the diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 641e98ab30..c571e37ac3 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1110,14 +1110,14 @@ func Test_BufReadCmd() endfunc func SetChangeMarks(start, end) - exe a:start. 'mark [' - exe a:end. 'mark ]' + exe a:start .. 'mark [' + exe a:end .. 'mark ]' endfunc " Verify the effects of autocmds on '[ and '] func Test_change_mark_in_autocmds() edit! Xtest - call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u", 'xtn') + call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u\<Esc>", 'xtn') call SetChangeMarks(2, 3) write diff --git a/src/nvim/testdir/test_backspace_opt.vim b/src/nvim/testdir/test_backspace_opt.vim new file mode 100644 index 0000000000..d680b442db --- /dev/null +++ b/src/nvim/testdir/test_backspace_opt.vim @@ -0,0 +1,151 @@ +" Tests for 'backspace' settings + +func Exec(expr) + let str='' + try + exec a:expr + catch /.*/ + let str=v:exception + endtry + return str +endfunc + +func Test_backspace_option() + set backspace= + call assert_equal('', &backspace) + set backspace=indent + call assert_equal('indent', &backspace) + set backspace=eol + call assert_equal('eol', &backspace) + set backspace=start + call assert_equal('start', &backspace) + set backspace=nostop + call assert_equal('nostop', &backspace) + " Add the value + set backspace= + set backspace=indent + call assert_equal('indent', &backspace) + set backspace+=eol + call assert_equal('indent,eol', &backspace) + set backspace+=start + call assert_equal('indent,eol,start', &backspace) + set backspace+=nostop + call assert_equal('indent,eol,start,nostop', &backspace) + " Delete the value + set backspace-=nostop + call assert_equal('indent,eol,start', &backspace) + set backspace-=indent + call assert_equal('eol,start', &backspace) + set backspace-=start + call assert_equal('eol', &backspace) + set backspace-=eol + call assert_equal('', &backspace) + " Check the error + call assert_equal(0, match(Exec('set backspace=ABC'), '.*E474')) + call assert_equal(0, match(Exec('set backspace+=def'), '.*E474')) + " NOTE: Vim doesn't check following error... + "call assert_equal(0, match(Exec('set backspace-=ghi'), '.*E474')) + + " Check backwards compatibility with version 5.4 and earlier + set backspace=0 + call assert_equal('0', &backspace) + set backspace=1 + call assert_equal('1', &backspace) + set backspace=2 + call assert_equal('2', &backspace) + set backspace=3 + call assert_equal('3', &backspace) + call assert_false(match(Exec('set backspace=4'), '.*E474')) + call assert_false(match(Exec('set backspace=10'), '.*E474')) + + " Cleared when 'compatible' is set + " set compatible + " call assert_equal('', &backspace) + set nocompatible viminfo+=nviminfo +endfunc + +" Test with backspace set to the non-compatible setting +func Test_backspace_ctrl_u() + new + call append(0, [ + \ "1 this shouldn't be deleted", + \ "2 this shouldn't be deleted", + \ "3 this shouldn't be deleted", + \ "4 this should be deleted", + \ "5 this shouldn't be deleted", + \ "6 this shouldn't be deleted", + \ "7 this shouldn't be deleted", + \ "8 this shouldn't be deleted (not touched yet)"]) + call cursor(2, 1) + + " set compatible + set backspace=2 + + exe "normal Avim1\<C-U>\<Esc>\<CR>" + exe "normal Avim2\<C-G>u\<C-U>\<Esc>\<CR>" + + set cpo-=< + inoremap <c-u> <left><c-u> + exe "normal Avim3\<C-U>\<Esc>\<CR>" + iunmap <c-u> + exe "normal Avim4\<C-U>\<C-U>\<Esc>\<CR>" + + " Test with backspace set to the compatible setting + set backspace= visualbell + exe "normal A vim5\<Esc>A\<C-U>\<C-U>\<Esc>\<CR>" + exe "normal A vim6\<Esc>Azwei\<C-G>u\<C-U>\<Esc>\<CR>" + + inoremap <c-u> <left><c-u> + exe "normal A vim7\<C-U>\<C-U>\<Esc>\<CR>" + + call assert_equal([ + \ "1 this shouldn't be deleted", + \ "2 this shouldn't be deleted", + \ "3 this shouldn't be deleted", + \ "4 this should be deleted3", + \ "", + \ "6 this shouldn't be deleted vim5", + \ "7 this shouldn't be deleted vim6", + \ "8 this shouldn't be deleted (not touched yet) vim7", + \ ""], getline(1, '$')) + + " Reset values + set compatible&vim + set visualbell&vim + set backspace&vim + + " Test new nostop option + %d_ + let expected = "foo bar foobar" + call setline(1, expected) + call cursor(1, 8) + exe ":norm! ianotherone\<c-u>" + call assert_equal(expected, getline(1)) + call cursor(1, 8) + exe ":norm! ianothertwo\<c-w>" + call assert_equal(expected, getline(1)) + + let content = getline(1) + for value in ['indent,nostop', 'eol,nostop', 'indent,eol,nostop', 'indent,eol,start,nostop'] + exe ":set bs=".. value + %d _ + call setline(1, content) + let expected = " foobar" + call cursor(1, 8) + exe ":norm! ianotherone\<c-u>" + call assert_equal(expected, getline(1), 'CTRL-U backspace value: '.. &bs) + let expected = "foo foobar" + call setline(1, content) + call cursor(1, 8) + exe ":norm! ianothertwo\<c-w>" + call assert_equal(expected, getline(1), 'CTRL-W backspace value: '.. &bs) + endfor + + " Reset options + set compatible&vim + set visualbell&vim + set backspace&vim + close! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim index 4a027c3864..20508b12d3 100644 --- a/src/nvim/testdir/test_excmd.vim +++ b/src/nvim/testdir/test_excmd.vim @@ -1,5 +1,7 @@ " Tests for various Ex commands. +source check.vim + func Test_ex_delete() new call setline(1, ['a', 'b', 'c']) @@ -9,6 +11,17 @@ func Test_ex_delete() call assert_equal(['a', 'c'], getline(1, 2)) endfunc +func Test_range_error() + call assert_fails(':.echo 1', 'E481:') + call assert_fails(':$echo 1', 'E481:') + call assert_fails(':1,2echo 1', 'E481:') + call assert_fails(':+1echo 1', 'E481:') + call assert_fails(':/1/echo 1', 'E481:') + call assert_fails(':\/echo 1', 'E481:') + normal vv + call assert_fails(":'<,'>echo 1", 'E481:') +endfunc + func Test_buffers_lastused() edit bufc " oldest @@ -40,3 +53,81 @@ func Test_buffers_lastused() bwipeout bufb bwipeout bufc endfunc + +" Test for the :confirm command dialog +func Test_confirm_cmd() + CheckNotGui + CheckRunVimInTerminal + call writefile(['foo1'], 'foo') + call writefile(['bar1'], 'bar') + " Test for saving all the modified buffers + let buf = RunVimInTerminal('', {'rows': 20}) + call term_sendkeys(buf, ":set nomore\n") + call term_sendkeys(buf, ":new foo\n") + call term_sendkeys(buf, ":call setline(1, 'foo2')\n") + call term_sendkeys(buf, ":new bar\n") + call term_sendkeys(buf, ":call setline(1, 'bar2')\n") + call term_sendkeys(buf, ":wincmd b\n") + call term_sendkeys(buf, ":confirm qall\n") + call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, "A") + call StopVimInTerminal(buf) + call assert_equal(['foo2'], readfile('foo')) + call assert_equal(['bar2'], readfile('bar')) + " Test for discarding all the changes to modified buffers + let buf = RunVimInTerminal('', {'rows': 20}) + call term_sendkeys(buf, ":set nomore\n") + call term_sendkeys(buf, ":new foo\n") + call term_sendkeys(buf, ":call setline(1, 'foo3')\n") + call term_sendkeys(buf, ":new bar\n") + call term_sendkeys(buf, ":call setline(1, 'bar3')\n") + call term_sendkeys(buf, ":wincmd b\n") + call term_sendkeys(buf, ":confirm qall\n") + call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, "D") + call StopVimInTerminal(buf) + call assert_equal(['foo2'], readfile('foo')) + call assert_equal(['bar2'], readfile('bar')) + " Test for saving and discarding changes to some buffers + let buf = RunVimInTerminal('', {'rows': 20}) + call term_sendkeys(buf, ":set nomore\n") + call term_sendkeys(buf, ":new foo\n") + call term_sendkeys(buf, ":call setline(1, 'foo4')\n") + call term_sendkeys(buf, ":new bar\n") + call term_sendkeys(buf, ":call setline(1, 'bar4')\n") + call term_sendkeys(buf, ":wincmd b\n") + call term_sendkeys(buf, ":confirm qall\n") + call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, "N") + call WaitForAssert({-> assert_match('\[Y\]es, (N)o, (C)ancel: ', term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, "Y") + call StopVimInTerminal(buf) + call assert_equal(['foo4'], readfile('foo')) + call assert_equal(['bar2'], readfile('bar')) + + call delete('foo') + call delete('bar') +endfunc + +func Test_confirm_cmd_cancel() + CheckNotGui + CheckRunVimInTerminal + + " Test for closing a window with a modified buffer + let buf = RunVimInTerminal('', {'rows': 20}) + call term_sendkeys(buf, ":set nomore\n") + call term_sendkeys(buf, ":new\n") + call term_sendkeys(buf, ":call setline(1, 'abc')\n") + call term_sendkeys(buf, ":confirm close\n") + call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$', + \ term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, "C") + call WaitForAssert({-> assert_equal('', term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, ":confirm close\n") + call WaitForAssert({-> assert_match('^\[Y\]es, (N)o, (C)ancel: *$', + \ term_getline(buf, 20))}, 1000) + call term_sendkeys(buf, "N") + call WaitForAssert({-> assert_match('^ *0,0-1 All$', + \ term_getline(buf, 20))}, 1000) + call StopVimInTerminal(buf) +endfunc diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 2123780f11..180170fe9a 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -150,6 +150,7 @@ let s:filename_checks = { \ 'dsl': ['file.dsl'], \ 'dtd': ['file.dtd'], \ 'dts': ['file.dts', 'file.dtsi'], + \ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace'], \ 'dylan': ['file.dylan'], \ 'dylanintr': ['file.intr'], \ 'dylanlid': ['file.lid'], @@ -322,15 +323,16 @@ let s:filename_checks = { \ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom'], \ 'nsis': ['file.nsi', 'file.nsh'], \ 'obj': ['file.obj'], - \ 'ocaml': ['file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit'], + \ 'ocaml': ['file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit', 'file.mlt', 'file.mlp', 'file.mlip', 'file.mli.cppo', 'file.ml.cppo'], \ 'occam': ['file.occ'], \ 'omnimark': ['file.xom', 'file.xin'], + \ 'opam': ['opam', 'file.opam', 'file.opam.template'], \ 'openroad': ['file.or'], \ 'ora': ['file.ora'], \ 'pamconf': ['/etc/pam.conf'], \ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment'], \ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'], - \ 'pascal': ['file.pas', 'file.pp', 'file.dpr', 'file.lpr'], + \ 'pascal': ['file.pas', 'file.dpr', 'file.lpr'], \ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'], \ 'pbtxt': ['file.pbtxt'], \ 'pccts': ['file.g'], @@ -366,6 +368,7 @@ let s:filename_checks = { \ 'proto': ['file.proto'], \ 'protocols': ['/etc/protocols'], \ 'psf': ['file.psf'], + \ 'puppet': ['file.pp'], \ 'pyrex': ['file.pyx', 'file.pxd'], \ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'], \ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg'], @@ -398,6 +401,7 @@ let s:filename_checks = { \ 'scheme': ['file.scm', 'file.ss', 'file.rkt'], \ 'scilab': ['file.sci', 'file.sce'], \ 'screen': ['.screenrc', 'screenrc'], + \ 'sexplib': ['file.sexp'], \ 'scss': ['file.scss'], \ 'sd': ['file.sd'], \ 'sdc': ['file.sdc'], @@ -425,6 +429,7 @@ let s:filename_checks = { \ 'smith': ['file.smt', 'file.smith'], \ 'sml': ['file.sml'], \ 'snobol4': ['file.sno', 'file.spt'], + \ 'sparql': ['file.rq', 'file.sparql'], \ 'spec': ['file.spec'], \ 'spice': ['file.sp', 'file.spice'], \ 'spup': ['file.speedup', 'file.spdata', 'file.spd'], @@ -616,6 +621,7 @@ let s:script_checks = { \ 'cpp': [['// Standard iostream objects -*- C++ -*-'], \ ['// -*- C++ -*-']], \ 'yaml': [['%YAML 1.2']], + \ 'pascal': [['#!/path/instantfpc']], \ } " Various forms of "env" optional arguments. @@ -686,5 +692,33 @@ func Test_ts_file() filetype off endfunc +func Test_pp_file() + filetype on + + call writefile(['looks like puppet'], 'Xfile.pp') + split Xfile.pp + call assert_equal('puppet', &filetype) + bwipe! + + let g:filetype_pp = 'pascal' + split Xfile.pp + call assert_equal('pascal', &filetype) + bwipe! + + " Test dist#ft#FTpp() + call writefile(['{ pascal comment'], 'Xfile.pp') + split Xfile.pp + call assert_equal('pascal', &filetype) + bwipe! + + call writefile(['procedure pascal'], 'Xfile.pp') + split Xfile.pp + call assert_equal('pascal', &filetype) + bwipe! + + call delete('Xfile.pp') + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_find_complete.vim b/src/nvim/testdir/test_find_complete.vim index a7bc135d47..0a00d9432f 100644 --- a/src/nvim/testdir/test_find_complete.vim +++ b/src/nvim/testdir/test_find_complete.vim @@ -15,22 +15,22 @@ func Test_find_complete() new set path= - call assert_fails('call feedkeys(":find\t\n", "xt")', 'E345:') + call assert_fails('call feedkeys(":find \t\n", "xt")', 'E471:') close new set path=. - call assert_fails('call feedkeys(":find\t\n", "xt")', 'E32:') + call assert_fails('call feedkeys(":find \t\n", "xt")', 'E471:') close new set path=.,, - call assert_fails('call feedkeys(":find\t\n", "xt")', 'E32:') + call assert_fails('call feedkeys(":find \t\n", "xt")', 'E471:') close new set path=./** - call assert_fails('call feedkeys(":find\t\n", "xt")', 'E32:') + call assert_fails('call feedkeys(":find \t\n", "xt")', 'E471:') close " We shouldn't find any file till this point diff --git a/src/nvim/testdir/test_findfile.vim b/src/nvim/testdir/test_findfile.vim index f5488a6a27..2195bf527e 100644 --- a/src/nvim/testdir/test_findfile.vim +++ b/src/nvim/testdir/test_findfile.vim @@ -184,3 +184,46 @@ func Test_finddir_error() call assert_fails('call finddir("x", "**x")', 'E343:') call assert_fails('call finddir("x", repeat("x", 5000))', 'E854:') endfunc + +" Test for the :find, :sfind and :tabfind commands +func Test_find_cmd() + new + let save_path = &path + let save_dir = getcwd() + set path=.,./**/* + call CreateFiles() + cd Xdir1 + " Test for :find + find foo + call assert_equal('foo', expand('%:.')) + 2find foo + call assert_equal('Xdir2/foo', expand('%:.')) + call assert_fails('3find foo', 'E347:') + " Test for :sfind + enew + sfind barfoo + call assert_equal('Xdir2/Xdir3/barfoo', expand('%:.')) + call assert_equal(3, winnr('$')) + close + call assert_fails('sfind baz', 'E345:') + call assert_equal(2, winnr('$')) + " Test for :tabfind + enew + tabfind foobar + call assert_equal('Xdir2/foobar', expand('%:.')) + call assert_equal(2, tabpagenr('$')) + tabclose + call assert_fails('tabfind baz', 'E345:') + call assert_equal(1, tabpagenr('$')) + " call chdir(save_dir) + exe 'cd ' . save_dir + call CleanFiles() + let &path = save_path + close + + call assert_fails('find', 'E471:') + call assert_fails('sfind', 'E471:') + call assert_fails('tabfind', 'E471:') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim index 6125f9b993..e390bd5cc8 100644 --- a/src/nvim/testdir/test_hardcopy.vim +++ b/src/nvim/testdir/test_hardcopy.vim @@ -1,5 +1,7 @@ " Test :hardcopy +source check.vim + func Test_printoptions() edit test_hardcopy.vim syn on @@ -8,8 +10,10 @@ func Test_printoptions() \ 'left:2in,top:30pt,right:16mm,bottom:3pc', \ 'header:3,syntax:y,number:y,wrap:n', \ 'header:3,syntax:n,number:y,wrap:y', + \ 'header:0,syntax:a,number:y,wrap:y', \ 'duplex:short,collate:n,jobsplit:y,portrait:n', \ 'duplex:long,collate:y,jobsplit:n,portrait:y', + \ 'duplex:off,collate:y,jobsplit:y,portrait:y', \ 'paper:10x14', \ 'paper:A3', \ 'paper:A4', @@ -28,7 +32,7 @@ func Test_printoptions() \ ''] exe 'set printoptions=' .. opt if has('postscript') - hardcopy > Xhardcopy_printoptions + 1,50hardcopy > Xhardcopy_printoptions let lines = readfile('Xhardcopy_printoptions') call assert_true(len(lines) > 20, opt) call assert_true(lines[0] =~ 'PS-Adobe', opt) @@ -44,8 +48,8 @@ func Test_printoptions() endfunc func Test_printmbfont() - " Print a small help page which contains tabs to cover code that expands tabs to spaces. - help help + " Print a help page which contains tabs, underlines (etc) to recover more code. + help syntax.txt syn on for opt in [':WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no', @@ -63,10 +67,39 @@ func Test_printmbfont() bwipe endfunc +func Test_printmbcharset() + CheckFeature postscript + + " digraph.txt has plenty of non-latin1 characters. + help digraph.txt + set printmbcharset=ISO10646 printencoding=utf-8 + for courier in ['yes', 'no'] + for ascii in ['yes', 'no'] + exe 'set printmbfont=r:WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-BoldItalic' + \ .. ',c:' .. courier .. ',a:' .. ascii + hardcopy > Xhardcopy_printmbcharset + let lines = readfile('Xhardcopy_printmbcharset') + call assert_true(len(lines) > 20) + call assert_true(lines[0] =~ 'PS-Adobe') + endfor + endfor + + set printmbcharset=does-not-exist printencoding=utf-8 printmbfont=r:WadaMin-Regular + call assert_fails('hardcopy > Xhardcopy_printmbcharset', 'E456:') + + set printmbcharset=GB_2312-80 printencoding=utf-8 printmbfont=r:WadaMin-Regular + call assert_fails('hardcopy > Xhardcopy_printmbcharset', 'E673:') + + set printmbcharset=ISO10646 printencoding=utf-8 printmbfont= + call assert_fails('hardcopy > Xhardcopy_printmbcharset', 'E675:') + + call delete('Xhardcopy_printmbcharset') + set printmbcharset& printencoding& printmbfont& + bwipe +endfunc + func Test_printexpr() - if !has('unix') - return - endif + CheckFeature postscript " Not a very useful printexpr value, but enough to test " hardcopy with 'printexpr'. @@ -84,7 +117,7 @@ func Test_printexpr() \ readfile('Xhardcopy_printexpr')) call delete('Xhardcopy_printexpr') - " Function return 1 to test print failure. + " Function returns 1 to test print failure. function PrintFails(fname) call delete(a:fname) return 1 @@ -97,12 +130,11 @@ func Test_printexpr() endfunc func Test_errors() - " FIXME: Windows fails differently than Unix. - if has('unix') - edit test_hardcopy.vim - call assert_fails('hardcopy >', 'E324:') - bwipe - endif + CheckFeature postscript + + edit test_hardcopy.vim + call assert_fails('hardcopy >', 'E324:') + bwipe endfunc func Test_dark_background() @@ -126,12 +158,11 @@ func Test_dark_background() endfun func Test_empty_buffer() - " FIXME: Unclear why this fails on Windows. - if has('unix') - new - call assert_equal("\nNo text to be printed", execute('hardcopy')) - bwipe - endif + CheckFeature postscript + + new + call assert_equal("\nNo text to be printed", execute('hardcopy')) + bwipe endfunc func Test_printheader_parsing() @@ -145,9 +176,8 @@ func Test_printheader_parsing() endfunc func Test_fname_with_spaces() - if !has('postscript') - return - endif + CheckFeature postscript + split t\ e\ s\ t.txt call setline(1, ['just', 'some', 'text']) hardcopy > %.ps @@ -157,9 +187,11 @@ func Test_fname_with_spaces() endfunc func Test_illegal_byte() - if !has('postscript') || &enc != 'utf-8' + CheckFeature postscript + if &enc != 'utf-8' return endif + new " conversion of 0xff will fail, this used to cause a crash call setline(1, "\xff") @@ -168,3 +200,5 @@ func Test_illegal_byte() bwipe! call delete('Xpstest') endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim index 66df57ea39..2fd82a4b6d 100644 --- a/src/nvim/testdir/test_marks.vim +++ b/src/nvim/testdir/test_marks.vim @@ -171,6 +171,11 @@ func Test_delmarks() " Deleting an already deleted mark should not fail. delmarks x + " getpos() should return all zeros after deleting a filemark. + norm mA + delmarks A + call assert_equal([0, 0, 0, 0], getpos("'A")) + " Test deleting a range of marks. norm ma norm mb @@ -201,3 +206,28 @@ func Test_mark_error() call assert_fails('mark xx', 'E488:') call assert_fails('mark _', 'E191:') endfunc + +" Test for the getmarklist() function +func Test_getmarklist() + new + " global marks + delmarks A-Z 0-9 \" ^.[] + call assert_equal([], getmarklist()) + call setline(1, ['one', 'two', 'three']) + mark A + call cursor(3, 5) + normal mN + call assert_equal([{'file' : '', 'mark' : "'A", 'pos' : [bufnr(), 1, 1, 0]}, + \ {'file' : '', 'mark' : "'N", 'pos' : [bufnr(), 3, 5, 0]}], + \ getmarklist()) + " buffer local marks + delmarks! + call assert_equal([{'mark' : "''", 'pos' : [bufnr(), 1, 1, 0]}, + \ {'mark' : "'\"", 'pos' : [bufnr(), 1, 1, 0]}], getmarklist(bufnr())) + call cursor(2, 2) + normal mr + call assert_equal({'mark' : "'r", 'pos' : [bufnr(), 2, 2, 0]}, + \ getmarklist(bufnr())[0]) + call assert_equal([], getmarklist({})) + close! +endfunc diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index ccc5e6ffc9..84d99ebb74 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -266,8 +266,14 @@ func Test_set_errors() call assert_fails('set foldmarker=x', 'E536:') call assert_fails('set commentstring=x', 'E537:') call assert_fails('set complete=x', 'E539:') + call assert_fails('set rulerformat=%-', 'E539:') + call assert_fails('set rulerformat=%(', 'E542:') + call assert_fails('set rulerformat=%15(%%', 'E542:') + call assert_fails('set statusline=%$', 'E539:') call assert_fails('set statusline=%{', 'E540:') call assert_fails('set statusline=%(', 'E542:') + call assert_fails('set statusline=%)', 'E542:') + if has('cursorshape') " This invalid value for 'guicursor' used to cause Vim to crash. call assert_fails('set guicursor=i-ci,r-cr:h', 'E545:') @@ -281,6 +287,21 @@ func Test_set_errors() call assert_fails('set winminwidth=10 winwidth=9', 'E592:') call assert_fails("set showbreak=\x01", 'E595:') call assert_fails('set t_foo=', 'E846:') + if has('python') || has('python3') + call assert_fails('set pyxversion=6', 'E474:') + endif + call assert_fails("let &tabstop='ab'", 'E521:') + call assert_fails('set sessionoptions=curdir,sesdir', 'E474:') + call assert_fails('set foldmarker={{{,', 'E474:') + call assert_fails('set sessionoptions=sesdir,curdir', 'E474:') + call assert_fails('set listchars=trail:· ambiwidth=double', 'E834:') + set listchars& + call assert_fails('set fillchars=stl:· ambiwidth=double', 'E835:') + set fillchars& + call assert_fails('set fileencoding=latin1,utf-8', 'E474:') + set nomodifiable + call assert_fails('set fileencoding=latin1', 'E21:') + set modifiable& endfunc " Must be executed before other tests that set 'term'. diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 563dbd90d9..48c0a83053 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -29,7 +29,7 @@ func s:setup_commands(cchar) command! -count -nargs=* -bang Xprev <mods><count>cprev<bang> <args> command! -nargs=* -bang Xfirst <mods>cfirst<bang> <args> command! -nargs=* -bang Xlast <mods>clast<bang> <args> - command! -nargs=* -bang -range Xnfile <mods><count>cnfile<bang> <args> + command! -count -nargs=* -bang Xnfile <mods><count>cnfile<bang> <args> command! -nargs=* -bang Xpfile <mods>cpfile<bang> <args> command! -nargs=* Xexpr <mods>cexpr <args> command! -range -nargs=* Xvimgrep <mods><count>vimgrep <args> @@ -40,6 +40,8 @@ func s:setup_commands(cchar) command! -nargs=0 -count Xcc <count>cc command! -count=1 -nargs=0 Xbelow <mods><count>cbelow command! -count=1 -nargs=0 Xabove <mods><count>cabove + command! -count=1 -nargs=0 Xbefore <mods><count>cbefore + command! -count=1 -nargs=0 Xafter <mods><count>cafter let g:Xgetlist = function('getqflist') let g:Xsetlist = function('setqflist') call setqflist([], 'f') @@ -64,7 +66,7 @@ func s:setup_commands(cchar) command! -count -nargs=* -bang Xprev <mods><count>lprev<bang> <args> command! -nargs=* -bang Xfirst <mods>lfirst<bang> <args> command! -nargs=* -bang Xlast <mods>llast<bang> <args> - command! -nargs=* -bang -range Xnfile <mods><count>lnfile<bang> <args> + command! -count -nargs=* -bang Xnfile <mods><count>lnfile<bang> <args> command! -nargs=* -bang Xpfile <mods>lpfile<bang> <args> command! -nargs=* Xexpr <mods>lexpr <args> command! -range -nargs=* Xvimgrep <mods><count>lvimgrep <args> @@ -75,6 +77,8 @@ func s:setup_commands(cchar) command! -nargs=0 -count Xcc <count>ll command! -count=1 -nargs=0 Xbelow <mods><count>lbelow command! -count=1 -nargs=0 Xabove <mods><count>labove + command! -count=1 -nargs=0 Xbefore <mods><count>lbefore + command! -count=1 -nargs=0 Xafter <mods><count>lafter let g:Xgetlist = function('getloclist', [0]) let g:Xsetlist = function('setloclist', [0]) call setloclist(0, [], 'f') @@ -260,6 +264,9 @@ func XwindowTests(cchar) \ winheight('.') == 7 && \ getline('.') ==# '|| non-error 1') + " :cnext in quickfix window should move to the next entry + Xnext + call assert_equal(2, g:Xgetlist({'idx' : 0}).idx) " Calling cwindow should close the quickfix window with no valid errors Xwindow @@ -431,13 +438,19 @@ func Xtest_browse(cchar) " result in failure if a:cchar == 'c' let err = 'E42:' + let cmd = '$cc' else let err = 'E776:' + let cmd = '$ll' endif call assert_fails('Xnext', err) call assert_fails('Xprev', err) call assert_fails('Xnfile', err) call assert_fails('Xpfile', err) + call assert_fails(cmd, err) + + Xexpr '' + call assert_fails(cmd, 'E42:') call s:create_test_file('Xqftestfile1') call s:create_test_file('Xqftestfile2') @@ -1247,6 +1260,36 @@ func Test_efm2() let &efm = save_efm endfunc +" Test for '%t' (error type) field in 'efm' +func Test_efm_error_type() + let save_efm = &efm + + " error type + set efm=%f:%l:%t:%m + cexpr ["Xfile1:10:E:msg1", "Xfile1:20:W:msg2", "Xfile1:30:I:msg3", + \ "Xfile1:40:N:msg4", "Xfile1:50:R:msg5"] + let output = split(execute('clist'), "\n") + call assert_equal([ + \ ' 1 Xfile1:10 error: msg1', + \ ' 2 Xfile1:20 warning: msg2', + \ ' 3 Xfile1:30 info: msg3', + \ ' 4 Xfile1:40 note: msg4', + \ ' 5 Xfile1:50 R: msg5'], output) + + " error type and a error number + set efm=%f:%l:%t:%n:%m + cexpr ["Xfile1:10:E:2:msg1", "Xfile1:20:W:4:msg2", "Xfile1:30:I:6:msg3", + \ "Xfile1:40:N:8:msg4", "Xfile1:50:R:3:msg5"] + let output = split(execute('clist'), "\n") + call assert_equal([ + \ ' 1 Xfile1:10 error 2: msg1', + \ ' 2 Xfile1:20 warning 4: msg2', + \ ' 3 Xfile1:30 info 6: msg3', + \ ' 4 Xfile1:40 note 8: msg4', + \ ' 5 Xfile1:50 R 3: msg5'], output) + let &efm = save_efm +endfunc + func XquickfixChangedByAutocmd(cchar) call s:setup_commands(a:cchar) if a:cchar == 'c' @@ -1810,14 +1853,27 @@ func s:test_xgrep(cchar) enew! | only set makeef&vim silent Xgrep Grep_Test_Text: test_quickfix.vim - call assert_true(len(g:Xgetlist()) == 3) + call assert_true(len(g:Xgetlist()) == 5) Xopen call assert_true(w:quickfix_title =~ '^:grep') Xclose enew set makeef=Temp_File_## silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim - call assert_true(len(g:Xgetlist()) == 6) + + " Try with 'grepprg' set to 'internal' + set grepprg=internal + silent Xgrep Grep_Test_Text: test_quickfix.vim + silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim + call assert_true(len(g:Xgetlist()) == 9) + set grepprg&vim + + call writefile(['Vim'], 'XtestTempFile') + set makeef=XtestTempFile + silent Xgrep Grep_Test_Text: test_quickfix.vim + call assert_equal(5, len(g:Xgetlist())) + call assert_false(filereadable('XtestTempFile')) + set makeef&vim endfunc func Test_grep() @@ -1914,9 +1970,23 @@ func HistoryTest(cchar) call assert_equal(' error list 2 of 3; 2 ' . common, res[1]) call assert_equal('> error list 3 of 3; 3 ' . common, res[2]) + " Test for changing the quickfix lists + call assert_equal(3, g:Xgetlist({'nr' : 0}).nr) + exe '1' . a:cchar . 'hist' + call assert_equal(1, g:Xgetlist({'nr' : 0}).nr) + exe '3' . a:cchar . 'hist' + call assert_equal(3, g:Xgetlist({'nr' : 0}).nr) + call assert_fails('-2' . a:cchar . 'hist', 'E16:') + call assert_fails('4' . a:cchar . 'hist', 'E16:') + call g:Xsetlist([], 'f') let l = split(execute(a:cchar . 'hist'), "\n") call assert_equal('No entries', l[0]) + if a:cchar == 'c' + call assert_fails('4chist', 'E16:') + else + call assert_fails('4lhist', 'E776:') + endif " An empty list should still show the stack history call g:Xsetlist([]) @@ -2365,14 +2435,28 @@ func Test_Autocmd() silent grepadd GrepAdd_Autocmd_Text test_quickfix.vim silent grep abc123def Xtest silent grepadd abc123def Xtest + set grepprg=internal + silent grep Grep_Autocmd_Text test_quickfix.vim + silent grepadd GrepAdd_Autocmd_Text test_quickfix.vim + silent lgrep Grep_Autocmd_Text test_quickfix.vim + silent lgrepadd GrepAdd_Autocmd_Text test_quickfix.vim + set grepprg&vim let l = ['pregrep', - \ 'postgrep', - \ 'pregrepadd', - \ 'postgrepadd', - \ 'pregrep', - \ 'postgrep', - \ 'pregrepadd', - \ 'postgrepadd'] + \ 'postgrep', + \ 'pregrepadd', + \ 'postgrepadd', + \ 'pregrep', + \ 'postgrep', + \ 'pregrepadd', + \ 'postgrepadd', + \ 'pregrep', + \ 'postgrep', + \ 'pregrepadd', + \ 'postgrepadd', + \ 'prelgrep', + \ 'postlgrep', + \ 'prelgrepadd', + \ 'postlgrepadd'] call assert_equal(l, g:acmds) endif @@ -2491,6 +2575,19 @@ func Test_cwindow_jump() call assert_true(winnr('$') == 2) call assert_true(winnr() == 1) + " Jumping to a file from the location list window should find a usuable + " window by wrapping around the window list. + enew | only + call setloclist(0, [], 'f') + new | new + lgetexpr ["F1%10%Line 10", "F2%20%Line 20", "F3%30%Line 30"] + lopen + 1close + call assert_equal(0, getloclist(3, {'id' : 0}).id) + lnext + call assert_equal(3, winnr()) + call assert_equal(getloclist(1, {'id' : 0}).id, getloclist(3, {'id' : 0}).id) + enew | only set efm&vim endfunc @@ -4201,17 +4298,22 @@ func Test_empty_qfbuf() endfunc " Test for the :cbelow, :cabove, :lbelow and :labove commands. +" And for the :cafter, :cbefore, :lafter and :lbefore commands. func Xtest_below(cchar) call s:setup_commands(a:cchar) " No quickfix/location list call assert_fails('Xbelow', 'E42:') call assert_fails('Xabove', 'E42:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', 'E42:') " Empty quickfix/location list call g:Xsetlist([]) call assert_fails('Xbelow', 'E42:') call assert_fails('Xabove', 'E42:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', 'E42:') call s:create_test_file('X1') call s:create_test_file('X2') @@ -4225,39 +4327,74 @@ func Xtest_below(cchar) call assert_fails('Xabove', 'E42:') call assert_fails('3Xbelow', 'E42:') call assert_fails('4Xabove', 'E42:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', 'E42:') + call assert_fails('3Xbefore', 'E42:') + call assert_fails('4Xafter', 'E42:') " Test the commands with various arguments - Xexpr ["X1:5:L5", "X2:5:L5", "X2:10:L10", "X2:15:L15", "X3:3:L3"] + Xexpr ["X1:5:3:L5", "X2:5:2:L5", "X2:10:3:L10", "X2:15:4:L15", "X3:3:5:L3"] edit +7 X2 Xabove call assert_equal(['X2', 5], [bufname(''), line('.')]) call assert_fails('Xabove', 'E553:') + normal 7G + Xbefore + call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')]) + call assert_fails('Xbefore', 'E553:') + normal 2j Xbelow call assert_equal(['X2', 10], [bufname(''), line('.')]) + normal 7G + Xafter + call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')]) + " Last error in this file Xbelow 99 call assert_equal(['X2', 15], [bufname(''), line('.')]) call assert_fails('Xbelow', 'E553:') + normal gg + Xafter 99 + call assert_equal(['X2', 15, 4], [bufname(''), line('.'), col('.')]) + call assert_fails('Xafter', 'E553:') + " First error in this file Xabove 99 call assert_equal(['X2', 5], [bufname(''), line('.')]) call assert_fails('Xabove', 'E553:') + normal G + Xbefore 99 + call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')]) + call assert_fails('Xbefore', 'E553:') + normal gg Xbelow 2 call assert_equal(['X2', 10], [bufname(''), line('.')]) + normal gg + Xafter 2 + call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')]) + normal G Xabove 2 call assert_equal(['X2', 10], [bufname(''), line('.')]) + normal G + Xbefore 2 + call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')]) + edit X4 call assert_fails('Xabove', 'E42:') call assert_fails('Xbelow', 'E42:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', 'E42:') if a:cchar == 'l' " If a buffer has location list entries from some other window but not " from the current window, then the commands should fail. edit X1 | split | call setloclist(0, [], 'f') call assert_fails('Xabove', 'E776:') call assert_fails('Xbelow', 'E776:') + call assert_fails('Xbefore', 'E776:') + call assert_fails('Xafter', 'E776:') close endif @@ -4268,31 +4405,52 @@ func Xtest_below(cchar) edit +1 X2 Xbelow 2 call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) + normal 1G + Xafter 2 + call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')]) + normal gg Xbelow 99 call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) + normal gg + Xafter 99 + call assert_equal(['X2', 15, 3], [bufname(''), line('.'), col('.')]) + normal G Xabove 2 call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) normal G + Xbefore 2 + call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')]) + + normal G Xabove 99 call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal G + Xbefore 99 + call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal 10G Xabove call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal 10G$ + 2Xbefore + call assert_equal(['X2', 10, 2], [bufname(''), line('.'), col('.')]) + normal 10G Xbelow call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) + normal 9G + 5Xafter + call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')]) " Invalid range if a:cchar == 'c' - call assert_fails('-2cbelow', 'E553:') - " TODO: should go to first error in the current line? - 0cabove + call assert_fails('-2cbelow', 'E16:') + call assert_fails('-2cafter', 'E16:') else - call assert_fails('-2lbelow', 'E553:') - " TODO: should go to first error in the current line? - 0labove + call assert_fails('-2lbelow', 'E16:') + call assert_fails('-2lafter', 'E16:') endif call delete('X1') @@ -4306,6 +4464,42 @@ func Test_cbelow() call Xtest_below('l') endfunc +func Test_quickfix_count() + let commands = [ + \ 'cNext', + \ 'cNfile', + \ 'cabove', + \ 'cbelow', + \ 'cfirst', + \ 'clast', + \ 'cnewer', + \ 'cnext', + \ 'cnfile', + \ 'colder', + \ 'cprevious', + \ 'crewind', + \ + \ 'lNext', + \ 'lNfile', + \ 'labove', + \ 'lbelow', + \ 'lfirst', + \ 'llast', + \ 'lnewer', + \ 'lnext', + \ 'lnfile', + \ 'lolder', + \ 'lprevious', + \ 'lrewind', + \ ] + for cmd in commands + call assert_fails('-1' .. cmd, 'E16:') + call assert_fails('.' .. cmd, 'E16:') + call assert_fails('%' .. cmd, 'E16:') + call assert_fails('$' .. cmd, 'E16:') + endfor +endfunc + " Test for aborting quickfix commands using QuickFixCmdPre func Xtest_qfcmd_abort(cchar) call s:setup_commands(a:cchar) @@ -4461,6 +4655,24 @@ func Test_cquit() call assert_fails('-3cquit', 'E16:') endfunc +" Running :lhelpgrep command more than once in a help window, doesn't jump to +" the help topic +func Test_lhelpgrep_from_help_window() + call mkdir('Xtestdir/doc', 'p') + call writefile(['window'], 'Xtestdir/doc/a.txt') + call writefile(['buffer'], 'Xtestdir/doc/b.txt') + let save_rtp = &rtp + let &rtp = 'Xtestdir' + lhelpgrep window + lhelpgrep buffer + call assert_equal('b.txt', fnamemodify(@%, ":p:t")) + lhelpgrep window + call assert_equal('a.txt', fnamemodify(@%, ":p:t")) + let &rtp = save_rtp + call delete('Xtestdir', 'rf') + new | only! +endfunc + " Test for adding an invalid entry with the quickfix window open and making " sure that the window contents are not changed func Test_add_invalid_entry_with_qf_window() diff --git a/src/nvim/testdir/test_sleep.vim b/src/nvim/testdir/test_sleep.vim new file mode 100644 index 0000000000..f71855fd4b --- /dev/null +++ b/src/nvim/testdir/test_sleep.vim @@ -0,0 +1,26 @@ +" Test for sleep and sleep! commands + +func! s:get_time_ms() + let timestr = reltimestr(reltime()) + let dotidx = stridx(timestr, '.') + let sec = str2nr(timestr[:dotidx]) + let msec = str2nr(timestr[dotidx + 1:]) + return (sec * 1000) + (msec / 1000) +endfunc + +func! s:assert_takes_longer(cmd, time_ms) + let start = s:get_time_ms() + execute a:cmd + let end = s:get_time_ms() + call assert_true(end - start >=# a:time_ms) +endfun + +func! Test_sleep_bang() + call s:assert_takes_longer('sleep 50m', 50) + call s:assert_takes_longer('sleep! 50m', 50) + call s:assert_takes_longer('sl 50m', 50) + call s:assert_takes_longer('sl! 50m', 50) + call s:assert_takes_longer('1sleep', 1000) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim index e7f332bc4c..e6ad92f483 100644 --- a/src/nvim/testdir/test_startup.vim +++ b/src/nvim/testdir/test_startup.vim @@ -735,4 +735,82 @@ func Test_x_arg() call delete('Xtest_x_arg') endfunc +" Test starting vim with various names: vim, ex, view, evim, etc. +func Test_progname() + CheckUnix + + call mkdir('Xprogname', 'p') + call writefile(['silent !date', + \ 'call writefile([mode(1), ' + \ .. '&insertmode, &diff, &readonly, &updatecount, ' + \ .. 'join(split(execute("message"), "\n")[1:])], "Xprogname_out")', + \ 'qall'], 'Xprogname_after') + + " +---------------------------------------------- progname + " | +--------------------------------- mode(1) + " | | +--------------------------- &insertmode + " | | | +---------------------- &diff + " | | | | +----------------- &readonly + " | | | | | +-------- &updatecount + " | | | | | | +--- :messages + " | | | | | | | + " let expectations = { + " \ 'vim': ['n', '0', '0', '0', '200', ''], + " \ 'gvim': ['n', '0', '0', '0', '200', ''], + " \ 'ex': ['ce', '0', '0', '0', '200', ''], + " \ 'exim': ['cv', '0', '0', '0', '200', ''], + " \ 'view': ['n', '0', '0', '1', '10000', ''], + " \ 'gview': ['n', '0', '0', '1', '10000', ''], + " \ 'evim': ['n', '1', '0', '0', '200', ''], + " \ 'eview': ['n', '1', '0', '1', '10000', ''], + " \ 'rvim': ['n', '0', '0', '0', '200', 'line 1: E145: Shell commands and some functionality not allowed in rvim'], + " \ 'rgvim': ['n', '0', '0', '0', '200', 'line 1: E145: Shell commands and some functionality not allowed in rvim'], + " \ 'rview': ['n', '0', '0', '1', '10000', 'line 1: E145: Shell commands and some functionality not allowed in rvim'], + " \ 'rgview': ['n', '0', '0', '1', '10000', 'line 1: E145: Shell commands and some functionality not allowed in rvim'], + " \ 'vimdiff': ['n', '0', '1', '0', '200', ''], + " \ 'gvimdiff': ['n', '0', '1', '0', '200', '']} + let expectations = {'nvim': ['n', '0', '0', '0', '200', '']} + + " let prognames = ['vim', 'gvim', 'ex', 'exim', 'view', 'gview', + " \ 'evim', 'eview', 'rvim', 'rgvim', 'rview', 'rgview', + " \ 'vimdiff', 'gvimdiff'] + let prognames = ['nvim'] + + for progname in prognames + if empty($DISPLAY) + if progname =~# 'g' + " Can't run gvim, gview (etc.) if $DISPLAY is not setup. + continue + endif + if has('gui') && (progname ==# 'evim' || progname ==# 'eview') + " evim or eview will start the GUI if there is gui support. + " So don't try to start them either if $DISPLAY is not setup. + continue + endif + endif + + exe 'silent !ln -s -f ' ..exepath(GetVimProg()) .. ' Xprogname/' .. progname + + let stdout_stderr = '' + if progname =~# 'g' + let stdout_stderr = system('Xprogname/'..progname..' -f --clean --not-a-term -S Xprogname_after') + else + exe 'sil !Xprogname/'..progname..' -f --clean -S Xprogname_after' + endif + + if progname =~# 'g' && !has('gui') + call assert_equal("E25: GUI cannot be used: Not enabled at compile time\n", stdout_stderr, progname) + else + call assert_equal('', stdout_stderr, progname) + call assert_equal(expectations[progname], readfile('Xprogname_out'), progname) + endif + + call delete('Xprogname/' .. progname) + call delete('Xprogname_out') + endfor + + call delete('Xprogname_after') + call delete('Xprogname', 'd') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim index 0a89066a2b..4621207d19 100644 --- a/src/nvim/testdir/test_usercommands.vim +++ b/src/nvim/testdir/test_usercommands.vim @@ -393,9 +393,13 @@ func Test_addr_all() call assert_equal(len(gettabinfo()), g:a2) bwipe - command! -addr=other DoSomething echo 'nothing' + command! -addr=other DoSomething let g:a1 = <line1> | let g:a2 = <line2> DoSomething - call assert_fails('%DoSomething') + call assert_equal(line('.'), g:a1) + call assert_equal(line('.'), g:a2) + %DoSomething + call assert_equal(1, g:a1) + call assert_equal(line('$'), g:a2) delcommand DoSomething endfunc @@ -421,7 +425,7 @@ func Test_command_list() \ execute('command DoCmd')) command! -count=2 DoCmd : call assert_equal("\n Name Args Address Complete Definition" - \ .. "\n DoCmd 0 2c :", + \ .. "\n DoCmd 0 2c ? :", \ execute('command DoCmd')) " Test with various -addr= argument values. diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim index bed39d0741..687b1cb989 100644 --- a/src/nvim/testdir/test_window_cmd.vim +++ b/src/nvim/testdir/test_window_cmd.vim @@ -856,7 +856,7 @@ func Test_window_resize() wincmd l let other_winnr = winnr('h') call assert_notequal(winnr(), other_winnr) - exe 'vert ' .. other_winnr .. 'resize -100' + exe 'vert ' .. other_winnr .. 'resize -' .. &columns call assert_equal(0, winwidth(other_winnr)) %bwipe! diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index d8a9c3b411..4194945645 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -809,4 +809,9 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() command('normal lhs') eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1)) end) + + it("does not crash when setting keymap in a non-existing buffer #13541", function() + pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {}) + helpers.assert_alive() + end) end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index c42d5c34cc..1d8ffc2087 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -972,6 +972,12 @@ describe('API', function() nvim("input", "gu") eq({mode='no', blocking=false}, nvim("get_mode")) end) + + it("at '-- More --' prompt returns blocking=true #11899", function() + command('set more') + feed(':digraphs<cr>') + eq({mode='rm', blocking=true}, nvim("get_mode")) + end) end) describe('RPC (K_EVENT) #6166', function() @@ -1996,4 +2002,63 @@ describe('API', function() }, meths.get_option_info'showcmd') end) end) + + describe('nvim_echo', function() + local screen + + before_each(function() + clear() + screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement + [4] = {foreground = Screen.colors.SlateBlue}, -- Special + }) + command('highlight Statement gui=bold guifg=Brown') + command('highlight Special guifg=SlateBlue') + end) + + it('can show highlighted line', function() + nvim_async("echo", {{"msg_a"}, {"msg_b", "Statement"}, {"msg_c", "Special"}}, true, {}) + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + msg_a{3:msg_b}{4:msg_c} | + ]]} + end) + + it('can show highlighted multiline', function() + nvim_async("echo", {{"msg_a\nmsg_a", "Statement"}, {"msg_b", "Special"}}, true, {}) + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {2: }| + {3:msg_a} | + {3:msg_a}{4:msg_b} | + {1:Press ENTER or type command to continue}^ | + ]]} + end) + + it('can save message history', function() + nvim('command', 'set cmdheight=2') -- suppress Press ENTER + nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {}) + eq("msg\nmsgmsg", meths.exec('messages', true)) + end) + + it('can disable saving message history', function() + nvim('command', 'set cmdheight=2') -- suppress Press ENTER + nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {}) + eq("", meths.exec("messages", true)) + end) + end) end) diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua index 54d2dc960b..9e19568249 100644 --- a/test/functional/eval/environ_spec.lua +++ b/test/functional/eval/environ_spec.lua @@ -3,6 +3,11 @@ local clear = helpers.clear local eq = helpers.eq local environ = helpers.funcs.environ local exists = helpers.funcs.exists +local system = helpers.funcs.system +local nvim_prog = helpers.nvim_prog +local command = helpers.command +local eval = helpers.eval +local setenv = helpers.funcs.setenv describe('environment variables', function() it('environ() handles empty env variable', function() @@ -17,3 +22,59 @@ describe('environment variables', function() eq(0, exists('$DOES_NOT_EXIST')) end) end) + +describe('empty $HOME', function() + local original_home = os.getenv('HOME') + + -- recover $HOME after each test + after_each(function() + if original_home ~= nil then + setenv('HOME', original_home) + end + os.remove('test_empty_home') + os.remove('./~') + end) + + local function tilde_in_cwd() + -- get files in cwd + command("let test_empty_home_cwd_files = split(globpath('.', '*'), '\n')") + -- get the index of the file named '~' + command('let test_empty_home_tilde_index = index(test_empty_home_cwd_files, "./~")') + return eval('test_empty_home_tilde_index') ~= -1 + end + + local function write_and_test_tilde() + system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', + '-c', 'write test_empty_home', '+q'}) + eq(false, tilde_in_cwd()) + end + + it("'~' folder not created in cwd if $HOME and related env not defined", function() + command("unlet $HOME") + write_and_test_tilde() + + command("let $HOMEDRIVE='C:'") + command("let $USERPROFILE='C:\\'") + write_and_test_tilde() + + command("unlet $HOMEDRIVE") + write_and_test_tilde() + + command("unlet $USERPROFILE") + write_and_test_tilde() + + command("let $HOME='%USERPROFILE%'") + command("let $USERPROFILE='C:\\'") + write_and_test_tilde() + end) + + it("'~' folder not created in cwd if writing a file with invalid $HOME", function() + setenv('HOME', '/path/does/not/exist') + write_and_test_tilde() + end) + + it("'~' folder not created in cwd if writing a file with $HOME=''", function() + command("let $HOME=''") + write_and_test_tilde() + end) +end) diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index a30eb748d0..252db88b6b 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -109,6 +109,23 @@ function tests.basic_init() } end +function tests.check_workspace_configuration() + skeleton { + on_init = function(_params) + return { capabilities = {} } + end; + body = function() + notify('start') + notify('workspace/configuration', { items = { + { section = "testSetting1" }; + { section = "testSetting2" }; + } }) + expect_notification('workspace/configuration', { true; vim.NIL}) + notify('shutdown') + end; + } +end + function tests.basic_check_capabilities() skeleton { on_init = function(params) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 0829560b9c..4acb1a7d8d 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -725,6 +725,19 @@ function module.pending_win32(pending_fn) end end +function module.pending_c_parser(pending_fn) + local status, msg = unpack(module.exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]])) + if not status then + if module.isCI() then + error("treesitter C parser not found, required on CI: " .. msg) + else + pending_fn 'no C parser, skipping' + return true + end + end + return false +end + -- Calls pending() and returns `true` if the system is too slow to -- run fragile or expensive tests. Else returns `false`. function module.skip_fragile(pending_fn, cond) diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index d48b8882af..515d6d91b8 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -242,9 +242,9 @@ describe('assert function:', function() -- assert_fails({cmd}, [, {error}]) describe('assert_fails', function() it('should change v:errors when error does not match v:errmsg', function() - eq(1, eval([[assert_fails('xxx', {})]])) - command([[call assert_match("Expected {} but got 'E731:", v:errors[0])]]) - expected_errors({"Expected {} but got 'E731: using Dictionary as a String'"}) + eq(1, eval([[assert_fails('xxx', 'E12345')]])) + command([[call assert_match("Expected 'E12345' but got 'E492:", v:errors[0])]]) + expected_errors({"Expected 'E12345' but got 'E492: Not an editor command: xxx': xxx"}) end) it('should not change v:errors when cmd errors', function() @@ -258,9 +258,9 @@ describe('assert function:', function() end) it('can specify and get a message about what failed', function() - eq(1, eval([[assert_fails('xxx', {}, 'stupid')]])) - command([[call assert_match("stupid: Expected {} but got 'E731:", v:errors[0])]]) - expected_errors({"stupid: Expected {} but got 'E731: using Dictionary as a String'"}) + eq(1, eval([[assert_fails('xxx', 'E9876', 'stupid')]])) + command([[call assert_match("stupid: Expected 'E9876' but got 'E492:", v:errors[0])]]) + expected_errors({"stupid: Expected 'E9876' but got 'E492: Not an editor command: xxx': stupid"}) end) it('can specify and get a message even when cmd succeeds', function() diff --git a/test/functional/legacy/backspace_opt_spec.lua b/test/functional/legacy/backspace_opt_spec.lua deleted file mode 100644 index 90bc6f74f0..0000000000 --- a/test/functional/legacy/backspace_opt_spec.lua +++ /dev/null @@ -1,67 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local call, clear = helpers.call, helpers.clear -local source, eq, nvim = helpers.source, helpers.eq, helpers.meths - -describe("test 'backspace' settings", function() - before_each(function() - clear() - - source([[ - func Exec(expr) - let str='' - try - exec a:expr - catch /.*/ - let str=v:exception - endtry - return str - endfunc - - func Test_backspace_option() - set backspace= - call assert_equal('', &backspace) - set backspace=indent - call assert_equal('indent', &backspace) - set backspace=eol - call assert_equal('eol', &backspace) - set backspace=start - call assert_equal('start', &backspace) - " Add the value - set backspace= - set backspace=indent - call assert_equal('indent', &backspace) - set backspace+=eol - call assert_equal('indent,eol', &backspace) - set backspace+=start - call assert_equal('indent,eol,start', &backspace) - " Delete the value - set backspace-=indent - call assert_equal('eol,start', &backspace) - set backspace-=start - call assert_equal('eol', &backspace) - set backspace-=eol - call assert_equal('', &backspace) - " Check the error - call assert_equal(0, match(Exec('set backspace=ABC'), '.*E474')) - call assert_equal(0, match(Exec('set backspace+=def'), '.*E474')) - " NOTE: Vim doesn't check following error... - "call assert_equal(0, match(Exec('set backspace-=ghi'), '.*E474')) - - " Check backwards compatibility with version 5.4 and earlier - set backspace=0 - call assert_equal('0', &backspace) - set backspace=1 - call assert_equal('1', &backspace) - set backspace=2 - call assert_equal('2', &backspace) - call assert_false(match(Exec('set backspace=3'), '.*E474')) - call assert_false(match(Exec('set backspace=10'), '.*E474')) - endfunc - ]]) - end) - - it('works', function() - call('Test_backspace_option') - eq({}, nvim.get_vvar('errors')) - end) -end) diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index fb0bacc2d2..5f7bbd887f 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -10,6 +10,29 @@ local source = helpers.source local poke_eventloop = helpers.poke_eventloop local uname = helpers.uname local load_adjust = helpers.load_adjust +local isCI = helpers.isCI + +local function isasan() + local version = eval('execute("version")') + return version:match('-fsanitize=[a-z,]*address') +end + +clear() +if isasan() then + pending('ASAN build is difficult to estimate memory usage', function() end) + return +elseif iswin() then + if isCI('github') then + pending('Windows runners in Github Actions do not have a stable environment to estimate memory usage', function() end) + return + elseif eval("executable('wmic')") == 0 then + pending('missing "wmic" command', function() end) + return + end +elseif eval("executable('ps')") == 0 then + pending('missing "ps" command', function() end) + return +end local monitor_memory_usage = { memory_usage = function(self) @@ -71,11 +94,6 @@ describe('memory usage', function() end end - local function isasan() - local version = eval('execute("version")') - return version:match('-fsanitize=[a-z,]*address') - end - before_each(clear) --[[ @@ -83,15 +101,6 @@ describe('memory usage', function() just after it finishes. ]]-- it('function capture vargs', function() - if isasan() then - pending('ASAN build is difficult to estimate memory usage') - end - if iswin() and eval("executable('wmic')") == 0 then - pending('missing "wmic" command') - elseif eval("executable('ps')") == 0 then - pending('missing "ps" command') - end - local pid = eval('getpid()') local before = monitor_memory_usage(pid) source([[ @@ -125,15 +134,6 @@ describe('memory usage', function() increase so much even when rerun Xtest.vim since system memory caches. ]]-- it('function capture lvars', function() - if isasan() then - pending('ASAN build is difficult to estimate memory usage') - end - if iswin() and eval("executable('wmic')") == 0 then - pending('missing "wmic" command') - elseif eval("executable('ps')") == 0 then - pending('missing "ps" command') - end - local pid = eval('getpid()') local before = monitor_memory_usage(pid) local fname = source([[ diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua deleted file mode 100644 index e522c339a9..0000000000 --- a/test/functional/lua/treesitter_spec.lua +++ /dev/null @@ -1,1015 +0,0 @@ --- Test suite for testing interactions with API bindings -local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') - -local clear = helpers.clear -local eq = helpers.eq -local insert = helpers.insert -local exec_lua = helpers.exec_lua -local feed = helpers.feed -local pcall_err = helpers.pcall_err -local matches = helpers.matches - -before_each(clear) - -describe('treesitter API', function() - -- error tests not requiring a parser library - it('handles missing language', function() - eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", - pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')")) - - -- actual message depends on platform - 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) -end) - -describe('treesitter API with C parser', function() - local function check_parser() - local status, msg = unpack(exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]])) - if not status then - if helpers.isCI() then - error("treesitter C parser not found, required on CI: " .. msg) - else - pending('no C parser, skipping') - end - end - return status - end - - it('parses buffer', function() - if helpers.pending_win32(pending) or not check_parser() then return end - - insert([[ - int main() { - int x = 3; - }]]) - - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - root = tree:root() - lang = vim.treesitter.inspect_language('c') - ]]) - - eq("<tree>", exec_lua("return tostring(tree)")) - eq("<node translation_unit>", exec_lua("return tostring(root)")) - eq({0,0,3,0}, exec_lua("return {root:range()}")) - - eq(1, exec_lua("return root:child_count()")) - exec_lua("child = root:child(0)") - eq("<node function_definition>", exec_lua("return tostring(child)")) - eq({0,0,2,1}, exec_lua("return {child:range()}")) - - eq("function_definition", exec_lua("return child:type()")) - eq(true, exec_lua("return child:named()")) - eq("number", type(exec_lua("return child:symbol()"))) - eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]")) - - exec_lua("anon = root:descendant_for_range(0,8,0,9)") - eq("(", exec_lua("return anon:type()")) - eq(false, exec_lua("return anon:named()")) - eq("number", type(exec_lua("return anon:symbol()"))) - eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]")) - - exec_lua("descendant = root:descendant_for_range(1,2,1,12)") - eq("<node declaration>", exec_lua("return tostring(descendant)")) - eq({1,2,1,12}, exec_lua("return {descendant:range()}")) - eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()")) - - feed("2G7|ay") - exec_lua([[ - tree2 = parser:parse()[1] - root2 = tree2:root() - descendant2 = root2:descendant_for_range(1,2,1,13) - ]]) - eq(false, exec_lua("return tree2 == tree1")) - eq(false, exec_lua("return root2 == root")) - eq("<node declaration>", exec_lua("return tostring(descendant2)")) - eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) - - eq(true, exec_lua("return child == child")) - -- separate lua object, but represents same node - eq(true, exec_lua("return child == root:child(0)")) - eq(false, exec_lua("return child == descendant2")) - eq(false, exec_lua("return child == nil")) - eq(false, exec_lua("return child == tree")) - - eq("string", exec_lua("return type(child:id())")) - eq(true, exec_lua("return child:id() == child:id()")) - -- separate lua object, but represents same node - eq(true, exec_lua("return child:id() == root:child(0):id()")) - eq(false, exec_lua("return child:id() == descendant2:id()")) - eq(false, exec_lua("return child:id() == nil")) - eq(false, exec_lua("return child:id() == tree")) - - -- unchanged buffer: return the same tree - eq(true, exec_lua("return parser:parse()[1] == tree2")) - end) - - local test_text = [[ -void ui_refresh(void) -{ - int width = INT_MAX, height = INT_MAX; - bool ext_widgets[kUIExtCount]; - for (UIExtension i = 0; (int)i < kUIExtCount; i++) { - ext_widgets[i] = true; - } - - bool inclusive = ui_override(); - for (size_t i = 0; i < ui_count; i++) { - UI *ui = uis[i]; - width = MIN(ui->width, width); - height = MIN(ui->height, height); - foo = BAR(ui->bazaar, bazaar); - for (UIExtension j = 0; (int)j < kUIExtCount; j++) { - ext_widgets[j] &= (ui->ui_ext[j] || inclusive); - } - } -}]] - - it('allows to iterate over nodes children', function() - if not check_parser() then return end - - insert(test_text); - - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - - func_node = parser:parse()[1]:root():child(0) - - res = {} - for node, field in func_node:iter_children() do - table.insert(res, {node:type(), field}) - end - return res - ]]) - - eq({ - {"primitive_type", "type"}, - {"function_declarator", "declarator"}, - {"compound_statement", "body"} - }, res) - end) - - it('allows to get a child by field', function() - if not check_parser() then return end - - insert(test_text); - - local res = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - - func_node = parser:parse()[1]:root():child(0) - - local res = {} - for _, node in ipairs(func_node:field("type")) do - table.insert(res, {node:type(), node:range()}) - end - return res - ]]) - - eq({{ "primitive_type", 0, 0, 0, 4 }}, res) - - local res_fail = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - - return #func_node:field("foo") == 0 - ]]) - - assert(res_fail) - end) - - local query = [[ - ((call_expression function: (identifier) @minfunc (argument_list (identifier) @min_id)) (eq? @minfunc "MIN")) - "for" @keyword - (primitive_type) @type - (field_expression argument: (identifier) @fieldarg) - ]] - - it("supports runtime queries", function() - if not check_parser() then return end - - local ret = exec_lua [[ - return require"vim.treesitter.query".get_query("c", "highlights").captures[1] - ]] - - eq('variable', ret) - end) - - it('support query and iter by capture', function() - if not check_parser() then return end - - insert(test_text) - - local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - table.insert(res, {cquery.captures[cid], node:type(), node:range()}) - end - return res - ]], query) - - eq({ - { "type", "primitive_type", 8, 2, 8, 6 }, - { "keyword", "for", 9, 2, 9, 5 }, - { "type", "primitive_type", 9, 7, 9, 13 }, - { "minfunc", "identifier", 11, 12, 11, 15 }, - { "fieldarg", "identifier", 11, 16, 11, 18 }, - { "min_id", "identifier", 11, 27, 11, 32 }, - { "minfunc", "identifier", 12, 13, 12, 16 }, - { "fieldarg", "identifier", 12, 17, 12, 19 }, - { "min_id", "identifier", 12, 29, 12, 35 }, - { "fieldarg", "identifier", 13, 14, 13, 16 } - }, res) - end) - - it('support query and iter by match', function() - if not check_parser() then return end - - insert(test_text) - - local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", ...) - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid,node in pairs(match) do - table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()}) - end - table.insert(res, {pattern, mrepr}) - end - return res - ]], query) - - eq({ - { 3, { { "type", "primitive_type", 8, 2, 8, 6 } } }, - { 2, { { "keyword", "for", 9, 2, 9, 5 } } }, - { 3, { { "type", "primitive_type", 9, 7, 9, 13 } } }, - { 4, { { "fieldarg", "identifier", 11, 16, 11, 18 } } }, - { 1, { { "minfunc", "identifier", 11, 12, 11, 15 }, { "min_id", "identifier", 11, 27, 11, 32 } } }, - { 4, { { "fieldarg", "identifier", 12, 17, 12, 19 } } }, - { 1, { { "minfunc", "identifier", 12, 13, 12, 16 }, { "min_id", "identifier", 12, 29, 12, 35 } } }, - { 4, { { "fieldarg", "identifier", 13, 14, 13, 16 } } } - }, res) - end) - - it('allow loading query with escaped quotes and capture them with `lua-match?` and `vim-match?`', function() - if not check_parser() then return end - - insert('char* astring = "Hello World!";') - - local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", '((_) @quote (vim-match? @quote "^\\"$")) ((_) @quote (lua-match? @quote "^\\"$"))') - parser = vim.treesitter.get_parser(0, "c") - tree = parser:parse()[1] - res = {} - for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) do - -- can't transmit node over RPC. just check the name and range - local mrepr = {} - for cid,node in pairs(match) do - table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()}) - end - table.insert(res, {pattern, mrepr}) - end - return res - ]]) - - eq({ - { 1, { { "quote", '"', 0, 16, 0, 17 } } }, - { 2, { { "quote", '"', 0, 16, 0, 17 } } }, - { 1, { { "quote", '"', 0, 29, 0, 30 } } }, - { 2, { { "quote", '"', 0, 29, 0, 30 } } }, - }, res) - end) - - it('allows to add predicates', function() - insert([[ - int main(void) { - return 0; - } - ]]) - - local custom_query = "((identifier) @main (#is-main? @main))" - - local res = exec_lua([[ - local query = require"vim.treesitter.query" - - local function is_main(match, pattern, bufnr, predicate) - local node = match[ predicate[2] ] - - return query.get_node_text(node, bufnr) - end - - local parser = vim.treesitter.get_parser(0, "c") - - query.add_predicate("is-main?", is_main) - - local query = query.parse_query("c", ...) - - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do - table.insert(nodes, {node:range()}) - end - - return nodes - ]], custom_query) - - eq({{0, 4, 0, 8}}, res) - - local res_list = exec_lua[[ - local query = require'vim.treesitter.query' - - local list = query.list_predicates() - - table.sort(list) - - return list - ]] - - eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list) - end) - - local hl_text = [[ -/// Schedule Lua callback on main loop's event queue -static int nlua_schedule(lua_State *const lstate) -{ - if (lua_type(lstate, 1) != LUA_TFUNCTION - || lstate != lstate) { - lua_pushliteral(lstate, "vim.schedule: expected function"); - return lua_error(lstate); - } - - LuaRef cb = nlua_ref(lstate, 1); - - multiqueue_put(main_loop.events, nlua_schedule_event, - 1, (void *)(ptrdiff_t)cb); - return 0; -}]] - -local hl_query = [[ -(ERROR) @ErrorMsg - -"if" @keyword -"else" @keyword -"for" @keyword -"return" @keyword - -"const" @type -"static" @type -"struct" @type -"enum" @type -"extern" @type - -(string_literal) @string - -(number_literal) @number -(char_literal) @string - -(type_identifier) @type -((type_identifier) @Special (#eq? @Special "LuaRef")) - -(primitive_type) @type -(sized_type_specifier) @type - -; Use lua regexes -((identifier) @Identifier (#contains? @Identifier "lua_")) -((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$")) -((identifier) @Normal (#vim-match? @Constant "^lstate$")) - -((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right)) - -(comment) @comment -]] - - describe('when highlighting', function() - local screen - - before_each(function() - screen = Screen.new(65, 18) - screen:attach() - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {foreground = Screen.colors.Blue1}, - [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, - [4] = {bold = true, foreground = Screen.colors.Brown}, - [5] = {foreground = Screen.colors.Magenta}, - [6] = {foreground = Screen.colors.Red}, - [7] = {bold = true, foreground = Screen.colors.SlateBlue}, - [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red}, - [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red}, - [11] = {foreground = Screen.colors.Cyan4}, - }) - end) - - it('supports highlighting', function() - if not check_parser() then return end - - insert(hl_text) - screen:expect{grid=[[ - /// Schedule Lua callback on main loop's event queue | - static int nlua_schedule(lua_State *const lstate) | - { | - if (lua_type(lstate, 1) != LUA_TFUNCTION | - || lstate != lstate) { | - lua_pushliteral(lstate, "vim.schedule: expected function"); | - return lua_error(lstate); | - } | - | - LuaRef cb = nlua_ref(lstate, 1); | - | - multiqueue_put(main_loop.events, nlua_schedule_event, | - 1, (void *)(ptrdiff_t)cb); | - return 0; | - ^} | - {1:~ }| - {1:~ }| - | - ]]} - - exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c") - local highlighter = vim.treesitter.highlighter - local query = ... - test_hl = highlighter.new(parser, {queries = {c = query}}) - ]], hl_query) - screen:expect{grid=[[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - ^} | - {1:~ }| - {1:~ }| - | - ]]} - - feed("5Goc<esc>dd") - - screen:expect{grid=[[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:^lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - } | - {1:~ }| - {1:~ }| - | - ]]} - - feed('7Go*/<esc>') - screen:expect{grid=[[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | - || {6:lstate} != {6:lstate}) { | - {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | - {4:return} {11:lua_error}(lstate); | - {8:*^/} | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - } | - {1:~ }| - | - ]]} - - feed('3Go/*<esc>') - screen:expect{grid=[[ - {2:/// Schedule Lua callback on main loop's event queue} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {2:/^*} | - {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | - {2: || lstate != lstate) {} | - {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | - {2: return lua_error(lstate);} | - {2:*/} | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - {8:}} | - | - ]]} - - feed("gg$") - feed("~") - screen:expect{grid=[[ - {2:/// Schedule Lua callback on main loop's event queu^E} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {2:/*} | - {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | - {2: || lstate != lstate) {} | - {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | - {2: return lua_error(lstate);} | - {2:*/} | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - {8:}} | - | - ]]} - - - feed("re") - screen:expect{grid=[[ - {2:/// Schedule Lua callback on main loop's event queu^e} | - {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | - { | - {2:/*} | - {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | - {2: || lstate != lstate) {} | - {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | - {2: return lua_error(lstate);} | - {2:*/} | - } | - | - {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | - | - multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | - {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | - {4:return} {5:0}; | - {8:}} | - | - ]]} - end) - - it("supports highlighting with custom parser", function() - if not check_parser() then return end - - screen:set_default_attr_ids({ {bold = true, foreground = Screen.colors.SeaGreen4} }) - - insert(test_text) - - screen:expect{ grid= [[ - int width = INT_MAX, height = INT_MAX; | - bool ext_widgets[kUIExtCount]; | - for (UIExtension i = 0; (int)i < kUIExtCount; i++) { | - ext_widgets[i] = true; | - } | - | - bool inclusive = ui_override(); | - for (size_t i = 0; i < ui_count; i++) { | - UI *ui = uis[i]; | - width = MIN(ui->width, width); | - height = MIN(ui->height, height); | - foo = BAR(ui->bazaar, bazaar); | - for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | - ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | - } | - } | - ^} | - | - ]] } - - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.parse_query("c", "(declaration) @decl") - - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do - table.insert(nodes, node) - end - - parser:set_included_regions({nodes}) - - local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}}) - ]]) - - screen:expect{ grid = [[ - int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; | - bool {1:ext_widgets}[{1:kUIExtCount}]; | - for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { | - ext_widgets[i] = true; | - } | - | - bool {1:inclusive} = {1:ui_override}(); | - for (size_t {1:i} = 0; i < ui_count; i++) { | - UI *{1:ui} = {1:uis}[{1:i}]; | - width = MIN(ui->width, width); | - height = MIN(ui->height, height); | - foo = BAR(ui->bazaar, bazaar); | - for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { | - ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | - } | - } | - ^} | - | - ]] } - end) - - it("supports highlighting injected languages", function() - if not check_parser() then return end - - insert([[ - int x = INT_MAX; - #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - #define foo void main() { \ - return 42; \ - } - ]]) - - screen:expect{grid=[[ - int x = INT_MAX; | - #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))| - #define foo void main() { \ | - return 42; \ | - } | - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]} - - exec_lua([[ - local parser = vim.treesitter.get_parser(0, "c", { - queries = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"} - }) - local highlighter = vim.treesitter.highlighter - local query = ... - test_hl = highlighter.new(parser, {queries = {c = query}}) - ]], hl_query) - - screen:expect{grid=[[ - {3:int} x = {5:INT_MAX}; | - #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))| - #define foo {3:void} main() { \ | - {4:return} {5:42}; \ | - } | - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - | - ]]} - end) - end) - - it('inspects language', function() - if not check_parser() then return end - - local keys, fields, symbols = unpack(exec_lua([[ - local lang = vim.treesitter.inspect_language('c') - local keys, symbols = {}, {} - for k,_ in pairs(lang) do - keys[k] = true - end - - -- symbols array can have "holes" and is thus not a valid msgpack array - -- but we don't care about the numbers here (checked in the parser test) - for _, v in pairs(lang.symbols) do - table.insert(symbols, v) - end - return {keys, lang.fields, symbols} - ]])) - - eq({fields=true, symbols=true}, keys) - - local fset = {} - for _,f in pairs(fields) do - eq("string", type(f)) - fset[f] = true - end - eq(true, fset["directive"]) - eq(true, fset["initializer"]) - - local has_named, has_anonymous - for _,s in pairs(symbols) do - eq("string", type(s[1])) - eq("boolean", type(s[2])) - if s[1] == "for_statement" and s[2] == true then - has_named = true - elseif s[1] == "|=" and s[2] == false then - has_anonymous = true - end - end - eq({true,true}, {has_named,has_anonymous}) - end) - it('allows to set simple ranges', function() - if not check_parser() then return end - - insert(test_text) - - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - return { parser:parse()[1]:root():range() } - ]] - - eq({0, 0, 19, 0}, res) - - -- The following sets the included ranges for the current parser - -- As stated here, this only includes the function (thus the whole buffer, without the last line) - local res2 = exec_lua [[ - local root = parser:parse()[1]:root() - parser:set_included_regions({{root:child(0)}}) - parser:invalidate() - return { parser:parse()[1]:root():range() } - ]] - - eq({0, 0, 18, 1}, res2) - - local range = exec_lua [[ - local res = {} - for _, region in ipairs(parser:included_regions()) do - for _, node in ipairs(region) do - table.insert(res, {node:range()}) - end - end - return res - ]] - - eq(range, { { 0, 0, 18, 1 } }) - - local range_tbl = exec_lua [[ - parser:set_included_regions { { { 0, 0, 17, 1 } } } - parser:parse() - return parser:included_regions() - ]] - - eq(range_tbl, { { { 0, 0, 0, 17, 1, 508 } } }) - end) - it("allows to set complex ranges", function() - if not check_parser() then return end - - insert(test_text) - - local res = exec_lua [[ - parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.parse_query("c", "(declaration) @decl") - - local nodes = {} - for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do - table.insert(nodes, node) - end - - parser:set_included_regions({nodes}) - - local root = parser:parse()[1]:root() - - local res = {} - for i=0,(root:named_child_count() - 1) do - table.insert(res, { root:named_child(i):range() }) - end - return res - ]] - - eq({ - { 2, 2, 2, 40 }, - { 3, 2, 3, 32 }, - { 4, 7, 4, 25 }, - { 8, 2, 8, 33 }, - { 9, 7, 9, 20 }, - { 10, 4, 10, 20 }, - { 14, 9, 14, 27 } }, res) - end) - - it("allows to create string parsers", function() - local ret = exec_lua [[ - local parser = vim.treesitter.get_string_parser("int foo = 42;", "c") - return { parser:parse()[1]:root():range() } - ]] - - eq({ 0, 0, 0, 13 }, ret) - end) - - it("allows to run queries with string parsers", function() - local txt = [[ - int foo = 42; - int bar = 13; - ]] - - local ret = exec_lua([[ - local str = ... - local parser = vim.treesitter.get_string_parser(str, "c") - - local nodes = {} - local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))') - - for _, node in query:iter_captures(parser:parse()[1]:root(), str, 0, 2) do - table.insert(nodes, { node:range() }) - end - - return nodes]], txt) - - eq({ {0, 10, 0, 13} }, ret) - end) - - describe("when creating a language tree", function() - local function get_ranges() - return exec_lua([[ - local result = {} - parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end) - return result - ]]) - end - - before_each(function() - insert([[ -int x = INT_MAX; -#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) -#define READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) -#define VALUE 123 -#define VALUE1 123 -#define VALUE2 123 - ]]) - end) - - describe("when parsing regions independently", function() - it("should inject a language", function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { - queries = { - c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}}) - ]]) - - eq("table", exec_lua("return type(parser:children().c)")) - eq(5, exec_lua("return #parser:children().c:trees()")) - eq({ - {0, 0, 7, 0}, -- root tree - {3, 14, 3, 17}, -- VALUE 123 - {4, 15, 4, 18}, -- VALUE1 123 - {5, 15, 5, 18}, -- VALUE2 123 - {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) - }, get_ranges()) - end) - end) - - describe("when parsing regions combined", function() - it("should inject a language", function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { - queries = { - c = "(preproc_def (preproc_arg) @c @combined) (preproc_function_def value: (preproc_arg) @c @combined)"}}) - ]]) - - eq("table", exec_lua("return type(parser:children().c)")) - eq(2, exec_lua("return #parser:children().c:trees()")) - eq({ - {0, 0, 7, 0}, -- root tree - {3, 14, 5, 18}, -- VALUE 123 - -- VALUE1 123 - -- VALUE2 123 - {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) - }, get_ranges()) - end) - end) - - describe("when using the offset directive", function() - it("should shift the range by the directive amount", function() - exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { - queries = { - c = "(preproc_def ((preproc_arg) @c (#offset! @c 0 2 0 -1))) (preproc_function_def value: (preproc_arg) @c)"}}) - ]]) - - eq("table", exec_lua("return type(parser:children().c)")) - eq({ - {0, 0, 7, 0}, -- root tree - {3, 15, 3, 16}, -- VALUE 123 - {4, 16, 4, 17}, -- VALUE1 123 - {5, 16, 5, 17}, -- VALUE2 123 - {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) - }, get_ranges()) - end) - end) - end) - - describe("when getting the language for a range", function() - before_each(function() - insert([[ -int x = INT_MAX; -#define VALUE 123456789 - ]]) - end) - - it("should return the correct language tree", function() - local result = exec_lua([[ - parser = vim.treesitter.get_parser(0, "c", { - queries = { c = "(preproc_def (preproc_arg) @c)"}}) - - local sub_tree = parser:language_for_range({1, 18, 1, 19}) - - return sub_tree == parser:children().c - ]]) - - eq(result, true) - end) - end) - - describe("when getting/setting match data", function() - describe("when setting for the whole match", function() - it("should set/get the data correctly", function() - insert([[ - int x = 3; - ]]) - - local result = exec_lua([[ - local result - - query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") - - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do - result = metadata.key - end - - return result - ]]) - - eq(result, "value") - end) - end) - - describe("when setting for a capture match", function() - it("should set/get the data correctly", function() - insert([[ - int x = 3; - ]]) - - local result = exec_lua([[ - local result - - query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") - - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do - result = metadata[pattern].key - end - - return result - ]]) - - eq(result, "value") - end) - end) - end) -end) diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 92d077ed14..eb5e284385 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -204,9 +204,8 @@ describe('startup defaults', function() end) describe('$NVIM_LOG_FILE', function() - local datasubdir = iswin() and 'nvim-data' or 'nvim' local xdgdir = 'Xtest-startup-xdg-logpath' - local xdgdatadir = xdgdir..'/'..datasubdir + local xdgcachedir = xdgdir..'/nvim' after_each(function() os.remove('Xtest-logpath') rmdir(xdgdir) @@ -218,28 +217,21 @@ describe('startup defaults', function() }}) eq('Xtest-logpath', eval('$NVIM_LOG_FILE')) end) - it('defaults to stdpath("data")/log if empty', function() - eq(true, mkdir(xdgdir) and mkdir(xdgdatadir)) + it('defaults to stdpath("cache")/log if empty', function() + eq(true, mkdir(xdgdir) and mkdir(xdgcachedir)) clear({env={ - XDG_DATA_HOME=xdgdir, + XDG_CACHE_HOME=xdgdir, NVIM_LOG_FILE='', -- Empty is invalid. }}) - eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) - it('defaults to stdpath("data")/log if invalid', function() - eq(true, mkdir(xdgdir) and mkdir(xdgdatadir)) + it('defaults to stdpath("cache")/log if invalid', function() + eq(true, mkdir(xdgdir) and mkdir(xdgcachedir)) clear({env={ - XDG_DATA_HOME=xdgdir, + XDG_CACHE_HOME=xdgdir, NVIM_LOG_FILE='.', -- Any directory is invalid. }}) - eq(xdgdir..'/'..datasubdir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) - end) - it('defaults to .nvimlog if stdpath("data") is invalid', function() - clear({env={ - XDG_DATA_HOME='Xtest-missing-xdg-dir', - NVIM_LOG_FILE='.', -- Any directory is invalid. - }}) - eq('.nvimlog', eval('$NVIM_LOG_FILE')) + eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) end) end) diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 3a676359ab..4705a76465 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -12,41 +12,41 @@ describe('vim.lsp.diagnostic', function() clear() exec_lua [[ - require('vim.lsp') - - make_range = function(x1, y1, x2, y2) - return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } } - end - - make_error = function(msg, x1, y1, x2, y2) - return { - range = make_range(x1, y1, x2, y2), - message = msg, - severity = 1, - } - end - - make_warning = function(msg, x1, y1, x2, y2) - return { - range = make_range(x1, y1, x2, y2), - message = msg, - severity = 2, - } - end - - make_information = function(msg, x1, y1, x2, y2) - return { - range = make_range(x1, y1, x2, y2), - message = msg, - severity = 3, - } - end - - count_of_extmarks_for_client = function(bufnr, client_id) - return #vim.api.nvim_buf_get_extmarks( - bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {} - ) - end + require('vim.lsp') + + make_range = function(x1, y1, x2, y2) + return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } } + end + + make_error = function(msg, x1, y1, x2, y2) + return { + range = make_range(x1, y1, x2, y2), + message = msg, + severity = 1, + } + end + + make_warning = function(msg, x1, y1, x2, y2) + return { + range = make_range(x1, y1, x2, y2), + message = msg, + severity = 2, + } + end + + make_information = function(msg, x1, y1, x2, y2) + return { + range = make_range(x1, y1, x2, y2), + message = msg, + severity = 3, + } + end + + count_of_extmarks_for_client = function(bufnr, client_id) + return #vim.api.nvim_buf_get_extmarks( + bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {} + ) + end ]] fake_uri = "file://fake/uri" @@ -640,6 +640,36 @@ describe('vim.lsp.diagnostic', function() eq(expected_spacing, #spacing) end) + + it('allows filtering via severity limit', function() + local get_extmark_count_with_severity = function(severity_limit) + return exec_lua([[ + PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + underline = false, + virtual_text = { + severity_limit = ... + }, + }) + + PublishDiagnostics(nil, nil, { + uri = fake_uri, + diagnostics = { + make_warning('Delayed Diagnostic', 4, 4, 4, 4), + } + }, 1 + ) + + return count_of_extmarks_for_client(diagnostic_bufnr, 1) + ]], severity_limit) + end + + -- No messages with Error or higher + eq(0, get_extmark_count_with_severity("Error")) + + -- But now we don't filter it + eq(1, get_extmark_count_with_severity("Warning")) + eq(1, get_extmark_count_with_severity("Hint")) + end) end) describe('lsp.util.show_line_diagnostics', function() diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index f01d90bbeb..41fdf845df 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -262,6 +262,63 @@ describe('LSP', function() } end) + it('client should return settings via workspace/configuration handler', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + {NIL, "workspace/configuration", { items = { + { section = "testSetting1" }; + { section = "testSetting2" }; + }}, 1}; + {NIL, "start", {}, 1}; + } + local client + test_rpc_server { + test_name = "check_workspace_configuration"; + on_init = function(_client) + client = _client + end; + on_exit = function(code, signal) + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) + end; + on_callback = function(err, method, params, client_id) + eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback") + if method == 'start' then + exec_lua([=[ + local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID) + client.config.settings = { + testSetting1 = true; + testSetting2 = false; + }]=]) + end + if method == 'workspace/configuration' then + local result = exec_lua([=[ + local method, params = ... + return require'vim.lsp.handlers'['workspace/configuration'](err, method, params, TEST_RPC_CLIENT_ID)]=], method, params) + client.notify('workspace/configuration', result) + end + if method == 'shutdown' then + client.stop() + end + end; + } + end) + it('workspace/configuration returns NIL per section if client was started without config.settings', function() + fake_lsp_server_setup('workspace/configuration no settings') + eq({ + NIL, + NIL, + }, exec_lua [[ + local params = { + items = { + {section = 'foo'}, + {section = 'bar'}, + } + } + return vim.lsp.handlers['workspace/configuration'](nil, nil, params, TEST_RPC_CLIENT_ID) + ]]) + end) + it('should verify capabilities sent', function() local expected_callbacks = { {NIL, "shutdown", {}, 1}; @@ -1003,7 +1060,7 @@ describe('LSP', function() return { edits = { make_edit(0, 0, 0, 3, "First ↥ 🤦 🦄") - }, + }, textDocument = { uri = "file://fake/uri"; version = editVersion @@ -1044,7 +1101,7 @@ describe('LSP', function() local args = {...} local versionedBuf = args[2] vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion - vim.lsp.util.apply_text_document_edit(...) + vim.lsp.util.apply_text_document_edit(args[1]) ]], edit, versionedBuf) end @@ -1067,6 +1124,7 @@ describe('LSP', function() }, buf_lines(target_bufnr)) end) end) + describe('workspace_apply_edit', function() it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function() local expected = { @@ -1082,6 +1140,106 @@ describe('LSP', function() ]]) end) end) + + describe('apply_workspace_edit', function() + local replace_line_edit = function(row, new_line, editVersion) + return { + edits = { + -- NOTE: This is a hack if you have a line longer than 1000 it won't replace it + make_edit(row, 0, row, 1000, new_line) + }, + textDocument = { + uri = "file://fake/uri"; + version = editVersion + } + } + end + + -- Some servers send all the edits separately, but with the same version. + -- We should not stop applying the edits + local make_workspace_edit = function(changes) + return { + documentChanges = changes + } + end + + local target_bufnr, changedtick = nil, nil + + before_each(function() + local ret = exec_lua [[ + local bufnr = vim.uri_to_bufnr("file://fake/uri") + local lines = { + "Original Line #1", + "Original Line #2" + } + + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + + local update_changed_tick = function() + vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick') + end + + update_changed_tick() + vim.api.nvim_buf_attach(bufnr, false, { + on_changedtick = function() + update_changed_tick() + end + }) + + return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')} + ]] + + target_bufnr = ret[1] + changedtick = ret[2] + end) + + it('apply_workspace_edit applies a single edit', function() + local new_lines = { + "First Line", + } + + local edits = {} + for row, line in ipairs(new_lines) do + table.insert(edits, replace_line_edit(row - 1, line, changedtick)) + end + + eq({ + "First Line", + "Original Line #2", + }, exec_lua([[ + local args = {...} + local workspace_edits = args[1] + local target_bufnr = args[2] + + vim.lsp.util.apply_workspace_edit(workspace_edits) + + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + ]], make_workspace_edit(edits), target_bufnr)) + end) + + it('apply_workspace_edit applies multiple edits', function() + local new_lines = { + "First Line", + "Second Line", + } + + local edits = {} + for row, line in ipairs(new_lines) do + table.insert(edits, replace_line_edit(row - 1, line, changedtick)) + end + + eq(new_lines, exec_lua([[ + local args = {...} + local workspace_edits = args[1] + local target_bufnr = args[2] + + vim.lsp.util.apply_workspace_edit(workspace_edits) + + return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false) + ]], make_workspace_edit(edits), target_bufnr)) + end) + end) + describe('completion_list_to_complete_items', function() -- Completion option precedence: -- textEdit.newText > insertText > label diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua index 1d50ce0a56..12efbec326 100644 --- a/test/functional/provider/define_spec.lua +++ b/test/functional/provider/define_spec.lua @@ -136,7 +136,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init) end) it('with nargs/count', function() - call(fn, args..', {"nargs": "1", "range": "5"}') + call(fn, args..', {"nargs": "1", "count": "5"}') local function on_setup() command('5RpcCommand arg') end @@ -152,7 +152,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init) end) it('with nargs/count/bang', function() - call(fn, args..', {"nargs": "1", "range": "5", "bang": ""}') + call(fn, args..', {"nargs": "1", "count": "5", "bang": ""}') local function on_setup() command('5RpcCommand! arg') end @@ -169,7 +169,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init) end) it('with nargs/count/bang/register', function() - call(fn, args..', {"nargs": "1", "range": "5", "bang": "",'.. + call(fn, args..', {"nargs": "1", "count": "5", "bang": "",'.. ' "register": ""}') local function on_setup() command('5RpcCommand! b arg') @@ -188,7 +188,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init) end) it('with nargs/count/bang/register/eval', function() - call(fn, args..', {"nargs": "1", "range": "5", "bang": "",'.. + call(fn, args..', {"nargs": "1", "count": "5", "bang": "",'.. ' "register": "", "eval": "@<reg>"}') local function on_setup() command('let @b = "regb"') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua new file mode 100644 index 0000000000..cb73bfbbe1 --- /dev/null +++ b/test/functional/treesitter/highlight_spec.lua @@ -0,0 +1,475 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') + +local clear = helpers.clear +local insert = helpers.insert +local exec_lua = helpers.exec_lua +local feed = helpers.feed +local pending_c_parser = helpers.pending_c_parser + +before_each(clear) + +local hl_query = [[ + (ERROR) @ErrorMsg + + "if" @keyword + "else" @keyword + "for" @keyword + "return" @keyword + + "const" @type + "static" @type + "struct" @type + "enum" @type + "extern" @type + + (string_literal) @string + + (number_literal) @number + (char_literal) @string + + (type_identifier) @type + ((type_identifier) @Special (#eq? @Special "LuaRef")) + + (primitive_type) @type + (sized_type_specifier) @type + + ; Use lua regexes + ((identifier) @Identifier (#contains? @Identifier "lua_")) + ((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$")) + ((identifier) @Normal (#vim-match? @Constant "^lstate$")) + + ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right)) + + (comment) @comment +]] + +local hl_text = [[ +/// Schedule Lua callback on main loop's event queue +static int nlua_schedule(lua_State *const lstate) +{ + if (lua_type(lstate, 1) != LUA_TFUNCTION + || lstate != lstate) { + lua_pushliteral(lstate, "vim.schedule: expected function"); + return lua_error(lstate); + } + + LuaRef cb = nlua_ref(lstate, 1); + + multiqueue_put(main_loop.events, nlua_schedule_event, + 1, (void *)(ptrdiff_t)cb); + return 0; +}]] + +local test_text = [[ +void ui_refresh(void) +{ + int width = INT_MAX, height = INT_MAX; + bool ext_widgets[kUIExtCount]; + for (UIExtension i = 0; (int)i < kUIExtCount; i++) { + ext_widgets[i] = true; + } + + bool inclusive = ui_override(); + for (size_t i = 0; i < ui_count; i++) { + UI *ui = uis[i]; + width = MIN(ui->width, width); + height = MIN(ui->height, height); + foo = BAR(ui->bazaar, bazaar); + for (UIExtension j = 0; (int)j < kUIExtCount; j++) { + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); + } + } +}]] + +describe('treesitter highlighting', function() + local screen + + before_each(function() + screen = Screen.new(65, 18) + screen:attach() + screen:set_default_attr_ids { + [1] = {bold = true, foreground = Screen.colors.Blue1}; + [2] = {foreground = Screen.colors.Blue1}; + [3] = {bold = true, foreground = Screen.colors.SeaGreen4}; + [4] = {bold = true, foreground = Screen.colors.Brown}; + [5] = {foreground = Screen.colors.Magenta}; + [6] = {foreground = Screen.colors.Red}; + [7] = {bold = true, foreground = Screen.colors.SlateBlue}; + [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}; + [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red}; + [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red}; + [11] = {foreground = Screen.colors.Cyan4}; + } + + exec_lua([[ hl_query = ... ]], hl_query) + end) + + it('is updated with edits', function() + if pending_c_parser(pending) then return end + + insert(hl_text) + screen:expect{grid=[[ + /// Schedule Lua callback on main loop's event queue | + static int nlua_schedule(lua_State *const lstate) | + { | + if (lua_type(lstate, 1) != LUA_TFUNCTION | + || lstate != lstate) { | + lua_pushliteral(lstate, "vim.schedule: expected function"); | + return lua_error(lstate); | + } | + | + LuaRef cb = nlua_ref(lstate, 1); | + | + multiqueue_put(main_loop.events, nlua_schedule_event, | + 1, (void *)(ptrdiff_t)cb); | + return 0; | + ^} | + {1:~ }| + {1:~ }| + | + ]]} + + exec_lua [[ + local parser = vim.treesitter.get_parser(0, "c") + local highlighter = vim.treesitter.highlighter + test_hl = highlighter.new(parser, {queries = {c = hl_query}}) + ]] + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | + || {6:lstate} != {6:lstate}) { | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + ^} | + {1:~ }| + {1:~ }| + | + ]]} + + feed("5Goc<esc>dd") + + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | + || {6:lstate} != {6:lstate}) { | + {11:^lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }| + {1:~ }| + | + ]]} + + feed('7Go*/<esc>') + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} | + || {6:lstate} != {6:lstate}) { | + {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); | + {4:return} {11:lua_error}(lstate); | + {8:*^/} | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + } | + {1:~ }| + | + ]]} + + feed('3Go/*<esc>') + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queue} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {2:/^*} | + {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | + {2: || lstate != lstate) {} | + {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | + {2: return lua_error(lstate);} | + {2:*/} | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + {8:}} | + | + ]]} + + feed("gg$") + feed("~") + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queu^E} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {2:/*} | + {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | + {2: || lstate != lstate) {} | + {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | + {2: return lua_error(lstate);} | + {2:*/} | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + {8:}} | + | + ]]} + + + feed("re") + screen:expect{grid=[[ + {2:/// Schedule Lua callback on main loop's event queu^e} | + {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | + { | + {2:/*} | + {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} | + {2: || lstate != lstate) {} | + {2: lua_pushliteral(lstate, "vim.schedule: expected function");} | + {2: return lua_error(lstate);} | + {2:*/} | + } | + | + {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); | + | + multiqueue_put(main_loop.events, {11:nlua_schedule_event}, | + {5:1}, ({3:void} *)({3:ptrdiff_t})cb); | + {4:return} {5:0}; | + {8:}} | + | + ]]} + end) + + it('is updated with :sort', function() + if pending_c_parser(pending) then return end + + insert(test_text) + exec_lua [[ + local parser = vim.treesitter.get_parser(0, "c") + test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}}) + ]] + screen:expect{grid=[[ + {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | + {3:bool} ext_widgets[kUIExtCount]; | + {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { | + ext_widgets[i] = true; | + } | + | + {3:bool} inclusive = ui_override(); | + {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { | + {3:UI} *ui = uis[i]; | + width = {5:MIN}(ui->width, width); | + height = {5:MIN}(ui->height, height); | + foo = {5:BAR}(ui->bazaar, bazaar); | + {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { | + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + } | + } | + ^} | + | + ]]} + + feed ":sort<cr>" + screen:expect{grid=[[ + ^ | + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + {3:UI} *ui = uis[i]; | + ext_widgets[i] = true; | + foo = {5:BAR}(ui->bazaar, bazaar); | + {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { | + height = {5:MIN}(ui->height, height); | + width = {5:MIN}(ui->width, width); | + } | + {3:bool} ext_widgets[kUIExtCount]; | + {3:bool} inclusive = ui_override(); | + {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { | + {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { | + {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | + } | + } | + {3:void} ui_refresh({3:void}) | + :sort | + ]]} + + feed "u" + + screen:expect{grid=[[ + {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; | + {3:bool} ext_widgets[kUIExtCount]; | + {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { | + ext_widgets[i] = true; | + } | + | + {3:bool} inclusive = ui_override(); | + {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { | + {3:UI} *ui = uis[i]; | + width = {5:MIN}(ui->width, width); | + height = {5:MIN}(ui->height, height); | + foo = {5:BAR}(ui->bazaar, bazaar); | + {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { | + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + } | + } | + ^} | + 19 changes; before #2 {MATCH:.*}| + ]]} + end) + + it("supports with custom parser", function() + if pending_c_parser(pending) then return end + + screen:set_default_attr_ids { + [1] = {bold = true, foreground = Screen.colors.SeaGreen4}; + } + + insert(test_text) + + screen:expect{ grid= [[ + int width = INT_MAX, height = INT_MAX; | + bool ext_widgets[kUIExtCount]; | + for (UIExtension i = 0; (int)i < kUIExtCount; i++) { | + ext_widgets[i] = true; | + } | + | + bool inclusive = ui_override(); | + for (size_t i = 0; i < ui_count; i++) { | + UI *ui = uis[i]; | + width = MIN(ui->width, width); | + height = MIN(ui->height, height); | + foo = BAR(ui->bazaar, bazaar); | + for (UIExtension j = 0; (int)j < kUIExtCount; j++) { | + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + } | + } | + ^} | + | + ]] } + + exec_lua [[ + parser = vim.treesitter.get_parser(0, "c") + query = vim.treesitter.parse_query("c", "(declaration) @decl") + + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do + table.insert(nodes, node) + end + + parser:set_included_regions({nodes}) + + local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}}) + ]] + + screen:expect{ grid = [[ + int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; | + bool {1:ext_widgets}[{1:kUIExtCount}]; | + for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { | + ext_widgets[i] = true; | + } | + | + bool {1:inclusive} = {1:ui_override}(); | + for (size_t {1:i} = 0; i < ui_count; i++) { | + UI *{1:ui} = {1:uis}[{1:i}]; | + width = MIN(ui->width, width); | + height = MIN(ui->height, height); | + foo = BAR(ui->bazaar, bazaar); | + for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { | + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); | + } | + } | + ^} | + | + ]] } + end) + + it("supports injected languages", function() + if pending_c_parser(pending) then return end + + insert([[ + int x = INT_MAX; + #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + #define foo void main() { \ + return 42; \ + } + ]]) + + screen:expect{grid=[[ + int x = INT_MAX; | + #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))| + #define foo void main() { \ | + return 42; \ | + } | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + exec_lua [[ + local parser = vim.treesitter.get_parser(0, "c", { + queries = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"} + }) + local highlighter = vim.treesitter.highlighter + test_hl = highlighter.new(parser, {queries = {c = hl_query}}) + ]] + + screen:expect{grid=[[ + {3:int} x = {5:INT_MAX}; | + #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))| + #define foo {3:void} main() { \ | + {4:return} {5:42}; \ | + } | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) +end) diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua new file mode 100644 index 0000000000..a5801271cb --- /dev/null +++ b/test/functional/treesitter/language_spec.lua @@ -0,0 +1,71 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local pcall_err = helpers.pcall_err +local matches = helpers.matches +local pending_c_parser = helpers.pending_c_parser + +before_each(clear) + +describe('treesitter API', function() + -- error tests not requiring a parser library + it('handles missing language', function() + eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", + pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')")) + + -- actual message depends on platform + 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) + + it('inspects language', function() + if pending_c_parser(pending) then return end + + local keys, fields, symbols = unpack(exec_lua([[ + local lang = vim.treesitter.inspect_language('c') + local keys, symbols = {}, {} + for k,_ in pairs(lang) do + keys[k] = true + end + + -- symbols array can have "holes" and is thus not a valid msgpack array + -- but we don't care about the numbers here (checked in the parser test) + for _, v in pairs(lang.symbols) do + table.insert(symbols, v) + end + return {keys, lang.fields, symbols} + ]])) + + eq({fields=true, symbols=true}, keys) + + local fset = {} + for _,f in pairs(fields) do + eq("string", type(f)) + fset[f] = true + end + eq(true, fset["directive"]) + eq(true, fset["initializer"]) + + local has_named, has_anonymous + for _,s in pairs(symbols) do + eq("string", type(s[1])) + eq("boolean", type(s[2])) + if s[1] == "for_statement" and s[2] == true then + has_named = true + elseif s[1] == "|=" and s[2] == false then + has_anonymous = true + end + end + eq({true,true}, {has_named,has_anonymous}) + end) +end) + diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua new file mode 100644 index 0000000000..f99362fbdf --- /dev/null +++ b/test/functional/treesitter/parser_spec.lua @@ -0,0 +1,599 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local eq = helpers.eq +local insert = helpers.insert +local exec_lua = helpers.exec_lua +local feed = helpers.feed +local pending_c_parser = helpers.pending_c_parser + +before_each(clear) + +describe('treesitter parser API', function() + + it('parses buffer', function() + if helpers.pending_win32(pending) or pending_c_parser(pending) then return end + + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + root = tree:root() + lang = vim.treesitter.inspect_language('c') + ]]) + + eq("<tree>", exec_lua("return tostring(tree)")) + eq("<node translation_unit>", exec_lua("return tostring(root)")) + eq({0,0,3,0}, exec_lua("return {root:range()}")) + + eq(1, exec_lua("return root:child_count()")) + exec_lua("child = root:child(0)") + eq("<node function_definition>", exec_lua("return tostring(child)")) + eq({0,0,2,1}, exec_lua("return {child:range()}")) + + eq("function_definition", exec_lua("return child:type()")) + eq(true, exec_lua("return child:named()")) + eq("number", type(exec_lua("return child:symbol()"))) + eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]")) + + exec_lua("anon = root:descendant_for_range(0,8,0,9)") + eq("(", exec_lua("return anon:type()")) + eq(false, exec_lua("return anon:named()")) + eq("number", type(exec_lua("return anon:symbol()"))) + eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]")) + + exec_lua("descendant = root:descendant_for_range(1,2,1,12)") + eq("<node declaration>", exec_lua("return tostring(descendant)")) + eq({1,2,1,12}, exec_lua("return {descendant:range()}")) + eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()")) + + feed("2G7|ay") + exec_lua([[ + tree2 = parser:parse()[1] + root2 = tree2:root() + descendant2 = root2:descendant_for_range(1,2,1,13) + ]]) + eq(false, exec_lua("return tree2 == tree1")) + eq(false, exec_lua("return root2 == root")) + eq("<node declaration>", exec_lua("return tostring(descendant2)")) + eq({1,2,1,13}, exec_lua("return {descendant2:range()}")) + + eq(true, exec_lua("return child == child")) + -- separate lua object, but represents same node + eq(true, exec_lua("return child == root:child(0)")) + eq(false, exec_lua("return child == descendant2")) + eq(false, exec_lua("return child == nil")) + eq(false, exec_lua("return child == tree")) + + eq("string", exec_lua("return type(child:id())")) + eq(true, exec_lua("return child:id() == child:id()")) + -- separate lua object, but represents same node + eq(true, exec_lua("return child:id() == root:child(0):id()")) + eq(false, exec_lua("return child:id() == descendant2:id()")) + eq(false, exec_lua("return child:id() == nil")) + eq(false, exec_lua("return child:id() == tree")) + + -- unchanged buffer: return the same tree + eq(true, exec_lua("return parser:parse()[1] == tree2")) + end) + + local test_text = [[ +void ui_refresh(void) +{ + int width = INT_MAX, height = INT_MAX; + bool ext_widgets[kUIExtCount]; + for (UIExtension i = 0; (int)i < kUIExtCount; i++) { + ext_widgets[i] = true; + } + + bool inclusive = ui_override(); + for (size_t i = 0; i < ui_count; i++) { + UI *ui = uis[i]; + width = MIN(ui->width, width); + height = MIN(ui->height, height); + foo = BAR(ui->bazaar, bazaar); + for (UIExtension j = 0; (int)j < kUIExtCount; j++) { + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); + } + } +}]] + + it('allows to iterate over nodes children', function() + if pending_c_parser(pending) then return end + + insert(test_text); + + local res = exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") + + func_node = parser:parse()[1]:root():child(0) + + res = {} + for node, field in func_node:iter_children() do + table.insert(res, {node:type(), field}) + end + return res + ]]) + + eq({ + {"primitive_type", "type"}, + {"function_declarator", "declarator"}, + {"compound_statement", "body"} + }, res) + end) + + it('allows to get a child by field', function() + if pending_c_parser(pending) then return end + + insert(test_text); + + local res = exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") + + func_node = parser:parse()[1]:root():child(0) + + local res = {} + for _, node in ipairs(func_node:field("type")) do + table.insert(res, {node:type(), node:range()}) + end + return res + ]]) + + eq({{ "primitive_type", 0, 0, 0, 4 }}, res) + + local res_fail = exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") + + return #func_node:field("foo") == 0 + ]]) + + assert(res_fail) + end) + + local query = [[ + ((call_expression function: (identifier) @minfunc (argument_list (identifier) @min_id)) (eq? @minfunc "MIN")) + "for" @keyword + (primitive_type) @type + (field_expression argument: (identifier) @fieldarg) + ]] + + it("supports runtime queries", function() + if pending_c_parser(pending) then return end + + local ret = exec_lua [[ + return require"vim.treesitter.query".get_query("c", "highlights").captures[1] + ]] + + eq('variable', ret) + end) + + it('support query and iter by capture', function() + if pending_c_parser(pending) then return end + + insert(test_text) + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", ...) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + res = {} + for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + table.insert(res, {cquery.captures[cid], node:type(), node:range()}) + end + return res + ]], query) + + eq({ + { "type", "primitive_type", 8, 2, 8, 6 }, + { "keyword", "for", 9, 2, 9, 5 }, + { "type", "primitive_type", 9, 7, 9, 13 }, + { "minfunc", "identifier", 11, 12, 11, 15 }, + { "fieldarg", "identifier", 11, 16, 11, 18 }, + { "min_id", "identifier", 11, 27, 11, 32 }, + { "minfunc", "identifier", 12, 13, 12, 16 }, + { "fieldarg", "identifier", 12, 17, 12, 19 }, + { "min_id", "identifier", 12, 29, 12, 35 }, + { "fieldarg", "identifier", 13, 14, 13, 16 } + }, res) + end) + + it('support query and iter by match', function() + if pending_c_parser(pending) then return end + + insert(test_text) + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", ...) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid,node in pairs(match) do + table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()}) + end + table.insert(res, {pattern, mrepr}) + end + return res + ]], query) + + eq({ + { 3, { { "type", "primitive_type", 8, 2, 8, 6 } } }, + { 2, { { "keyword", "for", 9, 2, 9, 5 } } }, + { 3, { { "type", "primitive_type", 9, 7, 9, 13 } } }, + { 4, { { "fieldarg", "identifier", 11, 16, 11, 18 } } }, + { 1, { { "minfunc", "identifier", 11, 12, 11, 15 }, { "min_id", "identifier", 11, 27, 11, 32 } } }, + { 4, { { "fieldarg", "identifier", 12, 17, 12, 19 } } }, + { 1, { { "minfunc", "identifier", 12, 13, 12, 16 }, { "min_id", "identifier", 12, 29, 12, 35 } } }, + { 4, { { "fieldarg", "identifier", 13, 14, 13, 16 } } } + }, res) + end) + + it('allow loading query with escaped quotes and capture them with `lua-match?` and `vim-match?`', function() + if pending_c_parser(pending) then return end + + insert('char* astring = "Hello World!";') + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", '((_) @quote (vim-match? @quote "^\\"$")) ((_) @quote (lua-match? @quote "^\\"$"))') + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid,node in pairs(match) do + table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()}) + end + table.insert(res, {pattern, mrepr}) + end + return res + ]]) + + eq({ + { 1, { { "quote", '"', 0, 16, 0, 17 } } }, + { 2, { { "quote", '"', 0, 16, 0, 17 } } }, + { 1, { { "quote", '"', 0, 29, 0, 30 } } }, + { 2, { { "quote", '"', 0, 29, 0, 30 } } }, + }, res) + end) + + it('allows to add predicates', function() + insert([[ + int main(void) { + return 0; + } + ]]) + + local custom_query = "((identifier) @main (#is-main? @main))" + + local res = exec_lua([[ + local query = require"vim.treesitter.query" + + local function is_main(match, pattern, bufnr, predicate) + local node = match[ predicate[2] ] + + return query.get_node_text(node, bufnr) + end + + local parser = vim.treesitter.get_parser(0, "c") + + query.add_predicate("is-main?", is_main) + + local query = query.parse_query("c", ...) + + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, {node:range()}) + end + + return nodes + ]], custom_query) + + eq({{0, 4, 0, 8}}, res) + + local res_list = exec_lua[[ + local query = require'vim.treesitter.query' + + local list = query.list_predicates() + + table.sort(list) + + return list + ]] + + eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list) + end) + + + it('allows to set simple ranges', function() + if pending_c_parser(pending) then return end + + insert(test_text) + + local res = exec_lua [[ + parser = vim.treesitter.get_parser(0, "c") + return { parser:parse()[1]:root():range() } + ]] + + eq({0, 0, 19, 0}, res) + + -- The following sets the included ranges for the current parser + -- As stated here, this only includes the function (thus the whole buffer, without the last line) + local res2 = exec_lua [[ + local root = parser:parse()[1]:root() + parser:set_included_regions({{root:child(0)}}) + parser:invalidate() + return { parser:parse()[1]:root():range() } + ]] + + eq({0, 0, 18, 1}, res2) + + local range = exec_lua [[ + local res = {} + for _, region in ipairs(parser:included_regions()) do + for _, node in ipairs(region) do + table.insert(res, {node:range()}) + end + end + return res + ]] + + eq(range, { { 0, 0, 18, 1 } }) + + local range_tbl = exec_lua [[ + parser:set_included_regions { { { 0, 0, 17, 1 } } } + parser:parse() + return parser:included_regions() + ]] + + eq(range_tbl, { { { 0, 0, 0, 17, 1, 508 } } }) + end) + it("allows to set complex ranges", function() + if pending_c_parser() then return end + + insert(test_text) + + local res = exec_lua [[ + parser = vim.treesitter.get_parser(0, "c") + query = vim.treesitter.parse_query("c", "(declaration) @decl") + + local nodes = {} + for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do + table.insert(nodes, node) + end + + parser:set_included_regions({nodes}) + + local root = parser:parse()[1]:root() + + local res = {} + for i=0,(root:named_child_count() - 1) do + table.insert(res, { root:named_child(i):range() }) + end + return res + ]] + + eq({ + { 2, 2, 2, 40 }, + { 3, 2, 3, 32 }, + { 4, 7, 4, 25 }, + { 8, 2, 8, 33 }, + { 9, 7, 9, 20 }, + { 10, 4, 10, 20 }, + { 14, 9, 14, 27 } }, res) + end) + + it("allows to create string parsers", function() + local ret = exec_lua [[ + local parser = vim.treesitter.get_string_parser("int foo = 42;", "c") + return { parser:parse()[1]:root():range() } + ]] + + eq({ 0, 0, 0, 13 }, ret) + end) + + it("allows to run queries with string parsers", function() + local txt = [[ + int foo = 42; + int bar = 13; + ]] + + local ret = exec_lua([[ + local str = ... + local parser = vim.treesitter.get_string_parser(str, "c") + + local nodes = {} + local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))') + + for _, node in query:iter_captures(parser:parse()[1]:root(), str) do + table.insert(nodes, { node:range() }) + end + + return nodes]], txt) + + eq({ {0, 10, 0, 13} }, ret) + end) + + it("should use node range when omitted", function() + local txt = [[ + int foo = 42; + int bar = 13; + ]] + + local ret = exec_lua([[ + local str = ... + local parser = vim.treesitter.get_string_parser(str, "c") + + local nodes = {} + local query = vim.treesitter.parse_query("c", '((identifier) @foo)') + local first_child = parser:parse()[1]:root():child(1) + + for _, node in query:iter_captures(first_child, str) do + table.insert(nodes, { node:range() }) + end + + return nodes]], txt) + + eq({ {1, 10, 1, 13} }, ret) + end) + + describe("when creating a language tree", function() + local function get_ranges() + return exec_lua([[ + local result = {} + parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end) + return result + ]]) + end + + before_each(function() + insert([[ +int x = INT_MAX; +#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) +#define READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) +#define VALUE 123 +#define VALUE1 123 +#define VALUE2 123 + ]]) + end) + + describe("when parsing regions independently", function() + it("should inject a language", function() + exec_lua([[ + parser = vim.treesitter.get_parser(0, "c", { + queries = { + c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}}) + ]]) + + eq("table", exec_lua("return type(parser:children().c)")) + eq(5, exec_lua("return #parser:children().c:trees()")) + eq({ + {0, 0, 7, 0}, -- root tree + {3, 14, 3, 17}, -- VALUE 123 + {4, 15, 4, 18}, -- VALUE1 123 + {5, 15, 5, 18}, -- VALUE2 123 + {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + }, get_ranges()) + end) + end) + + describe("when parsing regions combined", function() + it("should inject a language", function() + exec_lua([[ + parser = vim.treesitter.get_parser(0, "c", { + queries = { + c = "(preproc_def (preproc_arg) @c @combined) (preproc_function_def value: (preproc_arg) @c @combined)"}}) + ]]) + + eq("table", exec_lua("return type(parser:children().c)")) + eq(2, exec_lua("return #parser:children().c:trees()")) + eq({ + {0, 0, 7, 0}, -- root tree + {3, 14, 5, 18}, -- VALUE 123 + -- VALUE1 123 + -- VALUE2 123 + {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + }, get_ranges()) + end) + end) + + describe("when using the offset directive", function() + it("should shift the range by the directive amount", function() + exec_lua([[ + parser = vim.treesitter.get_parser(0, "c", { + queries = { + c = "(preproc_def ((preproc_arg) @c (#offset! @c 0 2 0 -1))) (preproc_function_def value: (preproc_arg) @c)"}}) + ]]) + + eq("table", exec_lua("return type(parser:children().c)")) + eq({ + {0, 0, 7, 0}, -- root tree + {3, 15, 3, 16}, -- VALUE 123 + {4, 16, 4, 17}, -- VALUE1 123 + {5, 16, 5, 17}, -- VALUE2 123 + {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + }, get_ranges()) + end) + end) + end) + + describe("when getting the language for a range", function() + before_each(function() + insert([[ +int x = INT_MAX; +#define VALUE 123456789 + ]]) + end) + + it("should return the correct language tree", function() + local result = exec_lua([[ + parser = vim.treesitter.get_parser(0, "c", { + queries = { c = "(preproc_def (preproc_arg) @c)"}}) + + local sub_tree = parser:language_for_range({1, 18, 1, 19}) + + return sub_tree == parser:children().c + ]]) + + eq(result, true) + end) + end) + + describe("when getting/setting match data", function() + describe("when setting for the whole match", function() + it("should set/get the data correctly", function() + insert([[ + int x = 3; + ]]) + + local result = exec_lua([[ + local result + + query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! "key" "value"))') + parser = vim.treesitter.get_parser(0, "c") + + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do + result = metadata.key + end + + return result + ]]) + + eq(result, "value") + end) + end) + + describe("when setting for a capture match", function() + it("should set/get the data correctly", function() + insert([[ + int x = 3; + ]]) + + local result = exec_lua([[ + local result + + query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))') + parser = vim.treesitter.get_parser(0, "c") + + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do + result = metadata[pattern].key + end + + return result + ]]) + + eq(result, "value") + end) + end) + end) +end) |