diff options
65 files changed, 664 insertions, 724 deletions
diff --git a/contrib/flake.lock b/contrib/flake.lock index 521b7629d9..b9e074db52 100644 --- a/contrib/flake.lock +++ b/contrib/flake.lock @@ -2,11 +2,11 @@ "nodes": { "flake-utils": { "locked": { - "lastModified": 1610051610, - "narHash": "sha256-U9rPz/usA1/Aohhk7Cmc2gBrEEKRzcW4nwPWMPwja4Y=", + "lastModified": 1623875721, + "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=", "owner": "numtide", "repo": "flake-utils", - "rev": "3982c9903e93927c2164caa727cd3f6a0e6d14cc", + "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772", "type": "github" }, "original": { @@ -17,11 +17,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1613226215, - "narHash": "sha256-3rA5cGIrBHD6yeKhNhsF7/t461ww25oJY8KyBb0IhjU=", + "lastModified": 1625697353, + "narHash": "sha256-/v85RkZ0Z+lxipkG2sjYNRINktc8VySbLQmPbirY0hQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "ff96a0fa5635770390b184ae74debea75c3fd534", + "rev": "87807e64a5ef5206b745a40af118c7be8db73681", "type": "github" }, "original": { diff --git a/contrib/flake.nix b/contrib/flake.nix index e75ff0356b..c601377cd0 100644 --- a/contrib/flake.nix +++ b/contrib/flake.nix @@ -16,14 +16,6 @@ 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 @@ -42,16 +34,10 @@ disallowedReferences = []; })); - # for neovim developers, builds a slow binary - # huge closure size but aims at covering all scripts - # brings development tools as well + # for neovim developers, beware of the slow binary neovim-developer = let lib = nixpkgs.lib; - pythonEnv = pkgs.python3.withPackages(ps: [ - ps.msgpack - ps.flake8 # for 'make pylint' - ]); luacheck = pkgs.luaPackages.luacheck; in (neovim-debug.override ({ doCheck = pkgs.stdenv.isLinux; })).overrideAttrs (oa: { @@ -59,29 +45,11 @@ "-DLUACHECK_PRG=${luacheck}/bin/luacheck" "-DMIN_LOG_LEVEL=0" "-DENABLE_LTO=OFF" - "-DUSE_BUNDLED=OFF" ] ++ pkgs.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 - shellcheck # for `make shlint` - doxygen # for script/gen_vimdoc.py - clang-tools # for clangd to find the correct headers - ]); - - 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 - ''; }); }; } // @@ -91,6 +59,11 @@ overlays = [ self.overlay ]; inherit system; }; + + pythonEnv = pkgs.python3.withPackages(ps: [ + ps.msgpack + ps.flake8 # for 'make pylint' + ]); in rec { @@ -98,6 +71,18 @@ inherit neovim neovim-debug neovim-developer; }; + checks = { + pylint = pkgs.runCommandNoCC "pylint" { + nativeBuildInputs = [ pythonEnv ]; + preferLocalBuild = true; + } "make -C ${./..} pylint > $out"; + + shlint = pkgs.runCommandNoCC "shlint" { + nativeBuildInputs = [ pkgs.shellcheck ]; + preferLocalBuild = true; + } "make -C ${./..} shlint > $out"; + }; + defaultPackage = pkgs.neovim; apps = { @@ -107,6 +92,33 @@ defaultApp = apps.nvim; - devShell = pkgs.neovim-developer; + devShell = let + in + pkgs.neovim-developer.overrideAttrs(oa: { + + buildInputs = with pkgs; oa.buildInputs ++ [ + cmake + pythonEnv + include-what-you-use # for scripts/check-includes.py + jq # jq for scripts/vim-patch.sh -r + shellcheck # for `make shlint` + doxygen # for script/gen_vimdoc.py + clang-tools # for clangd to find the correct headers + ]; + + shellHook = '' + export NVIM_PYTHON_LOG_LEVEL=DEBUG + export NVIM_LOG_FILE=/tmp/nvim.log + + # ASAN_OPTIONS=detect_leaks=1 + export ASAN_OPTIONS="log_path=./test.log:abort_on_error=1" + export UBSAN_OPTIONS=print_stacktrace=1 + mkdir -p build/runtime/parser + # nvim looks into CMAKE_INSTALL_DIR. Hack to avoid errors + # when running the functionaltests + mkdir -p outputs/out/share/nvim/syntax + touch outputs/out/share/nvim/syntax/syntax.vim + ''; + }); }); } diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim index 0687abd4dc..991bed6bbd 100644 --- a/runtime/autoload/provider/clipboard.vim +++ b/runtime/autoload/provider/clipboard.vim @@ -158,7 +158,9 @@ function! s:clipboard.get(reg) abort end let clipboard_data = s:try_cmd(s:paste[a:reg]) - if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0 && get(s:selections[a:reg].data, 0, []) ==# clipboard_data + if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0 + \ && type(clipboard_data) == v:t_list + \ && get(s:selections[a:reg].data, 0, []) ==# clipboard_data " When system clipboard return is same as our cache return the cache " as it contains regtype information return s:selections[a:reg].data diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 07c45c9298..4dcf5b7bbc 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -1104,7 +1104,7 @@ nvim_input_mouse({button}, {action}, {modifier}, {grid}, {row}, {col}) intermediate mouse positions will be ignored. It should be used to implement real-time mouse input in a GUI. The deprecated pseudokey form ("<LeftMouse><col,row>") of - |nvim_input()| has the same limitiation. + |nvim_input()| has the same limitation. Attributes: ~ {fast} @@ -1183,7 +1183,7 @@ nvim_notify({msg}, {log_level}, {opts}) *nvim_notify()* Notify the user with a message Relays the call to vim.notify . By default forwards your - message in the echo area but can be overriden to trigger + message in the echo area but can be overridden to trigger desktop notifications. Parameters: ~ @@ -1197,7 +1197,7 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()* By default (and currently the only option) the terminal will not be connected to an external process. Instead, input send on the channel will be echoed directly by the terminal. This - is useful to disply ANSI terminal sequences returned as part + is useful to display ANSI terminal sequences returned as part of a rpc message, or similar. Note: to directly initiate the terminal using the right size, @@ -1419,8 +1419,9 @@ nvim_parse_expression({expr}, {flags}, {highlight}) • "len": Amount of bytes successfully parsed. With flags equal to "" that should be equal to the length of expr - string. (“Sucessfully parsed” here means “participated - in AST creation”, not “till the first error”.) + string. (“Successfully parsed” here means + “participated in AST creation”, not “till the first + error”.) • "ast": AST, either nil or a dictionary with these keys: • "type": node type, one of the value names from @@ -1681,7 +1682,7 @@ nvim_set_decoration_provider({ns_id}, {opts}) Note: this function should not be called often. Rather, the callbacks themselves can be used to throttle unneeded callbacks. the `on_start` callback can return `false` to - disable the provider until the next redraw. Similarily, return + disable the provider until the next redraw. Similarly, return `false` in `on_win` will skip the `on_lines` calls for that window (but any extmarks set in `on_win` will still be used). A plugin managing multiple sources of decoration should @@ -1721,7 +1722,7 @@ nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()* Parameters: ~ {ns_id} number of namespace for this highlight {name} highlight group name, like ErrorMsg - {val} highlight definiton map, like + {val} highlight definition map, like |nvim_get_hl_by_name|. in addition the following keys are also recognized: `default` : don't override existing definition, like `hi default` diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 7a63a89986..6be87af8a9 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -568,9 +568,7 @@ with ".". Vim does not recognize a comment (starting with '"') after the option is empty (this is the default), use the internal formatting function |C-indenting| and |'lisp'|. But when 'indentexpr' is not empty, it will - be used instead |indent-expression|. When Vim was - compiled without internal formatting then the "indent" - program is used as a last resort. + be used instead |indent-expression|. *==* == Filter [count] lines like with ={motion}. @@ -1011,9 +1009,7 @@ inside of strings can change! Also see 'softtabstop' option. > with `zp`. (for {Visual} see |Visual-mode|) *:y* *:yank* *E850* -:[range]y[ank] [x] Yank [range] lines [into register x]. Yanking to the - "* or "+ registers is possible only when the - |+clipboard| feature is included. +:[range]y[ank] [x] Yank [range] lines [into register x]. :[range]y[ank] [x] {count} Yank {count} lines, starting with last line number @@ -1802,8 +1798,7 @@ found here: |sort()|, |uniq()|. With [f] sorting is done on the Float in the line. The value of Float is determined similar to passing the text (after or inside a {pattern} match) to - str2float() function. This option is available only - if Vim was compiled with Floating point support. + str2float() function. With [x] sorting is done on the first hexadecimal number in the line (after or inside a {pattern} diff --git a/runtime/doc/digraph.txt b/runtime/doc/digraph.txt index b7dc16341d..dd7e9a331a 100644 --- a/runtime/doc/digraph.txt +++ b/runtime/doc/digraph.txt @@ -165,7 +165,7 @@ ROUBLE The rouble sign was added in 2014 as 0x20bd. Vim supports the digraphs =R and =P for this. Note that R= and P= are other characters. - *digraph-table* + *digraph-table* *digraph-table-mbyte* char digraph hex dec official name ~ ^@ NU 0x00 0 NULL (NUL) ^A SH 0x01 1 START OF HEADING (SOH) @@ -341,12 +341,6 @@ $ DO 0x24 36 DOLLAR SIGN ý y' 0xfd 253 LATIN SMALL LETTER Y WITH ACUTE þ th 0xfe 254 LATIN SMALL LETTER THORN (Icelandic) ÿ y: 0xff 255 LATIN SMALL LETTER Y WITH DIAERESIS - -If your Vim is compiled with |multibyte| support and you are using a multibyte -'encoding', Vim provides this enhanced set of additional digraphs: - - *digraph-table-mbyte* -char digraph hex dec official name ~ Ā A- 0100 0256 LATIN CAPITAL LETTER A WITH MACRON ā a- 0101 0257 LATIN SMALL LETTER A WITH MACRON Ă A( 0102 0258 LATIN CAPITAL LETTER A WITH BREVE diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index bf7f2b21de..8c360b1778 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -3252,8 +3252,7 @@ count({comp}, {expr} [, {ic} [, {start}]]) *count()* cscope_connection([{num} , {dbpath} [, {prepend}]]) Checks for the existence of a |cscope| connection. If no parameters are specified, then the function returns: - 0, if cscope was not available (not compiled in), or - if there are no cscope connections; + 0, if there are no cscope connections; 1, if there is at least one cscope connection. If parameters are specified, then the value of {num} @@ -5299,9 +5298,6 @@ iconv({expr}, {from}, {to}) *iconv()* are replaced with "?". The encoding names are whatever the iconv() library function can accept, see ":!man 3 iconv". - Most conversions require Vim to be compiled with the |+iconv| - feature. Otherwise only UTF-8 to latin1 conversion and back - can be done. Note that Vim uses UTF-8 for all Unicode encodings, conversion from/to UCS-2 is automatically changed to use UTF-8. You cannot use UCS-2 in a string anyway, because of the NUL bytes. @@ -5641,6 +5637,9 @@ jobstart({cmd}[, {opts}]) *jobstart()* before invoking `on_stderr`. |channel-buffered| stdout_buffered: (boolean) Collect data until EOF (stream closed) before invoking `on_stdout`. |channel-buffered| + stdin: (string) Either "pipe" (default) to connect the + job's stdin to a channel or "null" to disconnect + stdin. width: (number) Width of the `pty` terminal. {opts} is passed as |self| dictionary to the callback; the @@ -5830,8 +5829,7 @@ lispindent({lnum}) *lispindent()* indenting rules, as with 'lisp'. The indent is counted in spaces, the value of 'tabstop' is relevant. {lnum} is used just like in |getline()|. - When {lnum} is invalid or Vim was not compiled the - |+lispindent| feature, -1 is returned. + When {lnum} is invalid, -1 is returned. list2str({list} [, {utf8}]) *list2str()* Convert each number in {list} to a character string can @@ -7150,7 +7148,6 @@ rubyeval({expr}) *rubyeval()* Hashes are represented as Vim |Dictionary| type. Other objects are represented as strings resulted from their "Object#to_s" method. - {only available when compiled with the |+ruby| feature} screenattr({row}, {col}) *screenattr()* Like |screenchar()|, but return the attribute. This is a rather @@ -9139,8 +9136,6 @@ undofile({name}) *undofile()* If {name} is empty undofile() returns an empty string, since a buffer without a file name will not write an undo file. Useful in combination with |:wundo| and |:rundo|. - When compiled without the |+persistent_undo| option this always - returns an empty string. undotree() *undotree()* Return the current state of the undo tree in a dictionary with diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt index 0f1fa2b7a7..812259741f 100644 --- a/runtime/doc/gui.txt +++ b/runtime/doc/gui.txt @@ -175,7 +175,6 @@ system. To do this, put these commands in your vimrc file: > :map <F4> :emenu <C-Z> Pressing <F4> will start the menu. You can now use the cursor keys to select a menu entry. Hit <Enter> to execute it. Hit <Esc> if you want to cancel. -This does require the |+menu| feature enabled at compile time. Creating New Menus *creating-menus* @@ -473,9 +472,8 @@ Executing Menus *execute-menus* insert-mode menu Eg: > :emenu File.Exit -If the console-mode vim has been compiled with WANT_MENU defined, you can -use :emenu to access useful menu items you may have got used to from GUI -mode. See 'wildmenu' for an option that works well with this. See +You can use :emenu to access useful menu items you may have got used to from +GUI mode. See 'wildmenu' for an option that works well with this. See |console-menus| for an example. When using a range, if the lines match with '<,'>, then the menu is executed diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt index 7643d84017..4a94701b2e 100644 --- a/runtime/doc/helphelp.txt +++ b/runtime/doc/helphelp.txt @@ -249,7 +249,6 @@ command: > It is possible to add translated help files, next to the original English help files. Vim will search for all help in "doc" directories in 'runtimepath'. -This is only available when compiled with the |+multi_lang| feature. At this moment translations are available for: Chinese - multiple authors diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt index 02edd50ae8..47305c65fb 100644 --- a/runtime/doc/if_ruby.txt +++ b/runtime/doc/if_ruby.txt @@ -32,10 +32,6 @@ downloading Ruby there. This form of the |:ruby| command is mainly useful for including ruby code in vim scripts. - Note: This command doesn't work when the Ruby feature - wasn't compiled in. To avoid errors, see - |script-here|. - Example Vim script: > function! RedGem() diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 2aafc075a6..69a13557d1 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -699,8 +699,7 @@ tag char note action in Normal mode ~ tag char note action in Normal mode ~ ------------------------------------------------------------------------------ -|g_CTRL-A| g CTRL-A only when compiled with MEM_PROFILE - defined: dump a memory profile +|g_CTRL-A| g CTRL-A dump a memory profile |g_CTRL-G| g CTRL-G show information about current cursor position |g_CTRL-H| g CTRL-H start Select block mode diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index d6ef761bcb..111c3ee7f7 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -528,6 +528,18 @@ LspCodeLens Used to color the virtual text of the codelens. See |nvim_buf_set_virtual_text()|. +LspCodeLensSeparator *hl-LspCodeLensSeparator* + Used to color the seperator between two or more code lens. + + *lsp-highlight-signature* + +Highlight groups related to |vim.lsp.handlers.signature_help()|. + + *hl-LspSignatureActiveParameter* +LspSignatureActiveParameter + Used to highlight the active parameter in the signature help. See + |vim.lsp.handlers.signature_help()|. + ============================================================================== AUTOCOMMANDS *lsp-autocommands* @@ -1418,6 +1430,11 @@ reset({client_id}, {buffer_client_map}) *vim.lsp.diagnostic.reset()* {buffer_client_map} table map of buffers to active clients + *vim.lsp.diagnostic.restore_extmarks()* +restore_extmarks({bufnr}, {last}) + Parameters: ~ + {last} number last line that was changed + save({diagnostics}, {bufnr}, {client_id}) *vim.lsp.diagnostic.save()* Save diagnostics to the current buffer. @@ -1429,6 +1446,10 @@ save({diagnostics}, {bufnr}, {client_id}) *vim.lsp.diagnostic.save()* {bufnr} number {client_id} number + *vim.lsp.diagnostic.save_extmarks()* +save_extmarks({bufnr}, {client_id}) + TODO: Documentation + set_loclist({opts}) *vim.lsp.diagnostic.set_loclist()* Sets the location list @@ -1615,7 +1636,7 @@ progress_handler({_}, {_}, {params}, {client_id}) https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand *vim.lsp.handlers.signature_help()* -signature_help({_}, {method}, {result}, {_}, {bufnr}, {config}) +signature_help({_}, {method}, {result}, {client_id}, {bufnr}, {config}) Parameters: ~ {config} table Configuration table. • border: (default=nil) @@ -1623,7 +1644,9 @@ signature_help({_}, {method}, {result}, {_}, {bufnr}, {config}) • See |vim.api.nvim_open_win()| See also: ~ - https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation|lsp-handler| for the method "textDocument/signatureHelp"> + https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation|lsp-handler| for the method "textDocument/signatureHelp" + The active parameter is highlighted with + |hl-LspSignatureActiveParameter|> vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with( vim.lsp.handlers.signature_help, { @@ -1756,7 +1779,7 @@ convert_input_to_markdown_lines({input}, {contents}) https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover *vim.lsp.util.convert_signature_help_to_markdown_lines()* -convert_signature_help_to_markdown_lines({signature_help}, {ft}) +convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers}) Converts `textDocument/SignatureHelp` response to markdown lines. @@ -1765,6 +1788,9 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft}) {ft} optional filetype that will be use as the `lang` for the label markdown code block + {triggers} optional list of trigger characters from + the lsp server. used to better determine + parameter offsets Return: ~ list of lines of converted markdown. @@ -1834,6 +1860,9 @@ get_lines({uri}, {rows}) *vim.lsp.util.get_lines()* Return: ~ table<number string> a table mapping rows to lines +get_markdown_fences() *vim.lsp.util.get_markdown_fences()* + TODO: Documentation + get_progress_messages() *vim.lsp.util.get_progress_messages()* TODO: Documentation diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index 5885b20ab7..6dbc54463c 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -324,12 +324,10 @@ This works slightly differently: mode with <Esc>, then you can move around in the buffer, copy/paste, etc. Go back to editing the gdb command with any command that starts Insert mode, such as `a` or `i`. -- The program being debugged will run in a separate window. On MS-Windows - this is a new console window. On Unix, if the |+terminal| feature is - available a Terminal window will be opened to run the debugged program in. +- A separate :terminal window will be opened to run the debugged program in. *termdebug_use_prompt* -Prompt mode can be used even when the |+terminal| feature is present with: > +Prompt mode can be used with: > let g:termdebug_use_prompt = 1 < diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 791fb8664e..6aa508956b 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2138,8 +2138,7 @@ A jump table for the options with a short description can be found at |Q_op|. global or local to buffer |global-local| External program to use for "=" command. When this option is empty the internal formatting functions are used; either 'lisp', 'cindent' - or 'indentexpr'. When Vim was compiled without internal formatting, - the "indent" program is used. + or 'indentexpr'. Environment variables are expanded |:set_env|. See |option-backslash| about including spaces and backslashes. This option cannot be set from a |modeline| or in the |sandbox|, for @@ -7093,8 +7092,7 @@ A jump table for the options with a short description can be found at |Q_op|. Allows writing to any file with no need for "!" override. *'writebackup'* *'wb'* *'nowritebackup'* *'nowb'* -'writebackup' 'wb' boolean (default on with |+writebackup| feature, off - otherwise) +'writebackup' 'wb' boolean (default on) global Make a backup before overwriting a file. The backup is removed after the file was successfully written, unless the 'backup' option is diff --git a/runtime/doc/print.txt b/runtime/doc/print.txt index e7de5b9ee3..d9320ad315 100644 --- a/runtime/doc/print.txt +++ b/runtime/doc/print.txt @@ -103,10 +103,9 @@ will use the "latin1" print character encoding file. When 'encoding' is set to a multibyte encoding, Vim will try to convert characters to the printing encoding for printing (if 'printencoding' is empty -then the conversion will be to latin1). Conversion to a printing encoding -other than latin1 will require Vim to be compiled with the |+iconv| feature. -If no conversion is possible then printing will fail. Any characters that -cannot be converted will be replaced with upside down question marks. +then the conversion will be to latin1). If no conversion is possible then +printing will fail. Any characters that cannot be converted will be replaced +with upside down question marks. Two print character encoding files are provided to support default Mac and HPUX character encodings and are used by default on these platforms. Code page @@ -176,9 +175,7 @@ the font. When omitted, the point size is 10. 'printheader' 'pheader' string (default "%<%f%h%m%=Page %N") global This defines the format of the header produced in |:hardcopy| output. The -option is defined in the same way as the 'statusline' option. If Vim has not -been compiled with the |+statusline| feature, this option has no effect and a -simple default header is used, which shows the page number. The same simple +option is defined in the same way as the 'statusline' option. The same simple header is used when this option is empty. *pmbcs-option* diff --git a/runtime/doc/remote.txt b/runtime/doc/remote.txt deleted file mode 100644 index 6c2ceb45be..0000000000 --- a/runtime/doc/remote.txt +++ /dev/null @@ -1,189 +0,0 @@ -*remote.txt* Nvim - - - VIM REFERENCE MANUAL by Bram Moolenaar - - -Vim client-server communication *client-server* - - Type |gO| to see the table of contents. - -============================================================================== -1. Common functionality *clientserver* - -When compiled with the |+clientserver| option, Vim can act as a command -server. It accepts messages from a client and executes them. At the same -time, Vim can function as a client and send commands to a Vim server. - -The following command line arguments are available: - - argument meaning ~ - - --remote [+{cmd}] {file} ... *--remote* - Open the file list in a remote Vim. When - there is no Vim server, execute locally. - There is one optional init command: +{cmd}. - This must be an Ex command that can be - followed by "|". - The rest of the command line is taken as the - file list. Thus any non-file arguments must - come before this. - You cannot edit stdin this way |--|. - The remote Vim is raised. If you don't want - this use > - vim --remote-send "<C-\><C-N>:n filename<CR>" -< - --remote-silent [+{cmd}] {file} ... *--remote-silent* - As above, but don't complain if there is no - server and the file is edited locally. - --remote-wait [+{cmd}] {file} ... *--remote-wait* - As --remote, but wait for files to complete - (unload) in remote Vim. - --remote-wait-silent [+{cmd}] {file} ... *--remote-wait-silent* - As --remote-wait, but don't complain if there - is no server. - *--remote-tab* - --remote-tab Like --remote but open each file in a new - tabpage. - *--remote-tab-silent* - --remote-tab-silent Like --remote-silent but open each file in a - new tabpage. - *--remote-tab-wait* - --remote-tab-wait Like --remote-wait but open each file in a new - tabpage. - - *--remote-tab-wait-silent* - --remote-tab-wait-silent Like --remote-wait-silent but open each file - in a new tabpage. - *--remote-send* - --remote-send {keys} Send {keys} to server and exit. The {keys} - are not mapped. Special key names are - recognized, e.g., "<CR>" results in a CR - character. - *--remote-expr* - --remote-expr {expr} Evaluate {expr} in server and print the result - on stdout. - -Examples ~ - -Edit "file.txt" in an already running GVIM server: > - gvim --remote file.txt - -Edit "file.txt" in an already running server called FOOBAR: > - gvim --servername FOOBAR --remote file.txt - -Edit "file.txt" in server "FILES" if it exists, become server "FILES" -otherwise: > - gvim --servername FILES --remote-silent file.txt - -This doesn't work, all arguments after --remote will be used as file names: > - gvim --remote --servername FOOBAR file.txt - -Edit file "+foo" in a remote server (note the use of "./" to avoid the special -meaning of the leading plus): > - vim --remote ./+foo - -Tell the remote server "BLA" to write all files and exit: > - vim --servername BLA --remote-send '<C-\><C-N>:wqa<CR>' - - -SERVER NAME *client-server-name* - -By default Vim will try to register the name under which it was invoked (gvim, -egvim ...). This can be overridden with the --servername argument. If the -specified name is not available, a postfix is applied until a free name is -encountered, i.e. "gvim1" for the second invocation of gvim on a particular -X-server. The resulting name is available in the servername builtin variable -|v:servername|. The case of the server name is ignored, thus "gvim" and -"GVIM" are considered equal. - -When Vim is invoked with --remote, --remote-wait or --remote-send it will try -to locate the server name determined by the invocation name and --servername -argument as described above. If an exact match is not available, the first -server with the number postfix will be used. If a name with the number -postfix is specified with the --servername argument, it must match exactly. - -If no server can be located and --remote or --remote-wait was used, Vim will -start up according to the rest of the command line and do the editing by -itself. This way it is not necessary to know whether gvim is already started -when sending command to it. - -The --serverlist argument will cause Vim to print a list of registered command -servers on the standard output (stdout) and exit. - -Win32 Note: Making the Vim server go to the foreground doesn't always work, -because MS-Windows doesn't allow it. The client will move the server to the -foreground when using the --remote or --remote-wait argument and the server -name starts with "g". - - -REMOTE EDITING - -The --remote argument will cause a |:drop| command to be constructed from the -rest of the command line and sent as described above. -The --remote-wait argument does the same thing and additionally sets up to -wait for each of the files to have been edited. This uses the BufUnload -event, thus as soon as a file has been unloaded, Vim assumes you are done -editing it. -Note that the --remote and --remote-wait arguments will consume the rest of -the command line. I.e. all remaining arguments will be regarded as filenames. -You can not put options there! - - -FUNCTIONS - *E240* *E573* -There are a number of Vim functions for scripting the command server. See -the description in |eval.txt| or use CTRL-] on the function name to jump to -the full explanation. - - synopsis explanation ~ - remote_startserver( name) run a server - remote_expr( server, string, idvar) send expression - remote_send( server, string, idvar) send key sequence - serverlist() get a list of available servers - remote_peek( serverid, retvar) check for reply string - remote_read( serverid) read reply string - server2client( serverid, string) send reply string - remote_foreground( server) bring server to the front - -See also the explanation of |CTRL-\_CTRL-N|. Very useful as a leading key -sequence. -The {serverid} for server2client() can be obtained with expand("<client>") - -============================================================================== -2. X11 specific items *x11-clientserver* - *E247* *E248* *E251* *E258* *E277* - -The communication between client and server goes through the X server. The -display of the Vim server must be specified. The usual protection of the X -server is used, you must be able to open a window on the X server for the -communication to work. It is possible to communicate between different -systems. - -By default, a GUI Vim will register a name on the X-server by which it can be -addressed for subsequent execution of injected strings. Vim can also act as -a client and send strings to other instances of Vim on the same X11 display. - -When an X11 GUI Vim (gvim) is started, it will try to register a send-server -name on the 'VimRegistry' property on the root window. - -An empty --servername argument will cause the command server to be disabled. - -To send commands to a Vim server from another application, read the source -file src/if_xcmdsrv.c, it contains some hints about the protocol used. - -============================================================================== -3. Win32 specific items *w32-clientserver* - -Every Win32 Vim can work as a server, also in the console. You do not need a -version compiled with OLE. Windows messages are used, this works on any -version of MS-Windows. But only communication within one system is possible. - -Since MS-Windows messages are used, any other application should be able to -communicate with a Vim server. - -When using gvim, the --remote-wait only works properly this way: > - - start /w gvim --remote-wait file.txt -< - vim:tw=78:sw=4:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 9add4d6460..a91aa4d2a0 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -903,11 +903,9 @@ OBSCURE Profiling *profile* *profiling* Profiling means that Vim measures the time that is spent on executing -functions and/or scripts. The |+profile| feature is required for this. -It is only included when Vim was compiled with "huge" features. +functions and/or scripts. -You can also use the |reltime()| function to measure time. This only requires -the |+reltime| feature, which is present more often. +You can also use the |reltime()| function to measure time. For profiling syntax highlighting see |:syntime|. diff --git a/runtime/doc/russian.txt b/runtime/doc/russian.txt index 776630a52b..a2bc9f3b5e 100644 --- a/runtime/doc/russian.txt +++ b/runtime/doc/russian.txt @@ -47,10 +47,6 @@ different codepages from http://www.sourceforge.net/projects/ruvim/ -Make sure that your Vim is at least 6.2.506 and use ruvim 0.5 or later for -automatic installs. Vim also needs to be compiled with |+gettext| feature for -user interface items translations to work. - After downloading an archive from RuVim project, unpack it into your $VIMRUNTIME directory. We recommend using UTF-8 archive. diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 1b6291f279..80b8dd52ea 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -480,7 +480,6 @@ accordingly. Vim proceeds in this order: - The |--noplugin| command line argument is used. - The |--clean| command line argument is used. - The "-u NONE" command line argument is used |-u|. - - When Vim was compiled without the |+eval| feature. Note that using "-c 'set noloadplugins'" doesn't work, because the commands from the command line have not been executed yet. You can use "--cmd 'set noloadplugins'" or "--cmd 'set loadplugins'" |--cmd|. diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index bf649b5940..6c51f37ae5 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -371,9 +371,6 @@ the desired value, or restored to their default by removing the variable using Remarks: - Some truly ancient browsers may not show the background colors. - From most browsers you can also print the file (in color)! -- The latest TOhtml may actually work with older versions of Vim, but some - features such as conceal support will not function, and the colors may be - incorrect for an old Vim without GUI support compiled in. Here is an example how to run the script over all .c and .h files from a Unix shell: > @@ -4745,8 +4742,7 @@ in their own color. This is basically the same as > :echo g:colors_name < In case g:colors_name has not been defined :colo will - output "default". When compiled without the |+eval| - feature it will output "unknown". + output "default". :colo[rscheme] {name} Load color scheme {name}. This searches 'runtimepath' for the file "colors/{name}.(vim|lua)". The first one that @@ -5404,9 +5400,6 @@ If your syntax causes redrawing to be slow, here are a few hints on making it faster. To see slowness switch on some features that usually interfere, such as 'relativenumber' and |folding|. -Note: this is only available when compiled with the |+profile| feature. -You many need to build Vim with "huge" features. - To find out what patterns are consuming most time, get an overview with this sequence: > :syntime on diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index 2c1b927e5a..4d938c4a23 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -367,11 +367,11 @@ be a bug. If you really want the old Vi behavior, set the 't' flag in 'cpoptions'. *tag-binary-search* -Vim uses binary searching in the tags file to find the desired tag quickly -(when enabled at compile time |+tag_binary|). But this only works if the -tags file was sorted on ASCII byte value. Therefore, if no match was found, -another try is done with a linear search. If you only want the linear search, -reset the 'tagbsearch' option. Or better: Sort the tags file! +Vim uses binary searching in the tags file to find the desired tag quickly. +But this only works if the tags file was sorted on ASCII byte value. +Therefore, if no match was found, another try is done with a linear search. +If you only want the linear search, reset the 'tagbsearch' option. Or better: +Sort the tags file! Note that the binary searching is disabled when not looking for a tag with a specific name. This happens when ignoring case and when a regular expression @@ -666,9 +666,6 @@ included files (recursively). This can be used to find the definition of a variable, function or macro. If you only want to search in the current buffer, use the commands listed at |pattern-searches|. -These commands are not available when the |+find_in_path| feature was disabled -at compile time. - When a line is encountered that includes another file, that file is searched before continuing in the current buffer. Files included by included files are also searched. When an include file could not be found it is silently diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt index b2ce6d670d..ef8d6b5ea9 100644 --- a/runtime/doc/testing.txt +++ b/runtime/doc/testing.txt @@ -30,8 +30,7 @@ New tests should be added as new style tests. These use functions such as |assert_equal()| to keep the test commands and the expected result in one place. *old-style-testing* -In some cases an old style test needs to be used. E.g. when testing Vim -without the |+eval| feature. +In some cases an old style test needs to be used. Find more information in the file src/testdir/README.txt. diff --git a/runtime/doc/usr_45.txt b/runtime/doc/usr_45.txt index bc95f3405e..3199c4d8ea 100644 --- a/runtime/doc/usr_45.txt +++ b/runtime/doc/usr_45.txt @@ -31,13 +31,6 @@ this command: > If it replies with "C", this means the default is being used, which is English. - Note: - Using different languages only works when Vim was compiled to handle - it. To find out if it works, use the ":version" command and check the - output for "+gettext" and "+multi_lang". If they are there, you are - OK. If you see "-gettext" or "-multi_lang" you will have to find - another Vim. - What if you would like your messages in a different language? There are several ways. Which one you should use depends on the capabilities of your system. diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index b13d662ccb..ced1747ee0 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -126,7 +126,7 @@ local function select_client(method) if #clients > 1 then local choices = {} - for k,v in ipairs(clients) do + for k,v in pairs(clients) do table.insert(choices, string.format("%d %s", k, v.name)) end local user_choice = vim.fn.confirm( @@ -204,9 +204,9 @@ function M.formatting_seq_sync(options, timeout_ms, order) local clients = vim.tbl_values(vim.lsp.buf_get_clients()); -- sort the clients according to `order` - for _, client_name in ipairs(order or {}) do + for _, client_name in pairs(order or {}) do -- if the client exists, move to the end of the list - for i, client in ipairs(clients) do + for i, client in pairs(clients) do if client.name == client_name then table.insert(clients, table.remove(clients, i)) break @@ -215,7 +215,7 @@ function M.formatting_seq_sync(options, timeout_ms, order) end -- loop through the clients and make synchronous formatting requests - for _, client in ipairs(clients) do + for _, client in pairs(clients) do if client.resolved_capabilities.document_formatting then local params = util.make_formatting_params(options) local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) @@ -286,7 +286,7 @@ local function pick_call_hierarchy_item(call_hierarchy_items) return call_hierarchy_items[1] end local items = {} - for i, item in ipairs(call_hierarchy_items) do + for i, item in pairs(call_hierarchy_items) do local entry = item.detail or item.name table.insert(items, string.format("%d. %s", i, entry)) end @@ -328,8 +328,8 @@ end --- function M.list_workspace_folders() local workspace_folders = {} - for _, client in ipairs(vim.lsp.buf_get_clients()) do - for _, folder in ipairs(client.workspaceFolders) do + for _, client in pairs(vim.lsp.buf_get_clients()) do + for _, folder in pairs(client.workspaceFolders) do table.insert(workspace_folders, folder.name) end end @@ -347,9 +347,9 @@ function M.add_workspace_folder(workspace_folder) return end local params = util.make_workspace_params({{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}, {{}}) - for _, client in ipairs(vim.lsp.buf_get_clients()) do + for _, client in pairs(vim.lsp.buf_get_clients()) do local found = false - for _, folder in ipairs(client.workspaceFolders) do + for _, folder in pairs(client.workspaceFolders) do if folder.name == workspace_folder then found = true print(workspace_folder, "is already part of this workspace") @@ -371,8 +371,8 @@ function M.remove_workspace_folder(workspace_folder) vim.api.nvim_command("redraw") if not (workspace_folder and #workspace_folder > 0) then return end local params = util.make_workspace_params({{}}, {{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}) - for _, client in ipairs(vim.lsp.buf_get_clients()) do - for idx, folder in ipairs(client.workspaceFolders) do + for _, client in pairs(vim.lsp.buf_get_clients()) do + for idx, folder in pairs(client.workspaceFolders) do if folder.name == workspace_folder then vim.lsp.buf_notify(0, 'workspace/didChangeWorkspaceFolders', params) client.workspaceFolders[idx] = nil diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index fbd37e3830..46e2078507 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -111,12 +111,16 @@ function M.display(lenses, bufnr, client_id) local ns = namespaces[client_id] local num_lines = api.nvim_buf_line_count(bufnr) for i = 0, num_lines do - local line_lenses = lenses_by_lnum[i] + local line_lenses = lenses_by_lnum[i] or {} api.nvim_buf_clear_namespace(bufnr, ns, i, i + 1) local chunks = {} - for _, lens in pairs(line_lenses or {}) do + local num_line_lenses = #line_lenses + for j, lens in ipairs(line_lenses) do local text = lens.command and lens.command.title or 'Unresolved lens ...' table.insert(chunks, {text, 'LspCodeLens' }) + if j < num_line_lenses then + table.insert(chunks, {' | ', 'LspCodeLensSeparator' }) + end end if #chunks > 0 then api.nvim_buf_set_virtual_text(bufnr, ns, i, chunks, {}) diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index c67ea0c07a..1342df529f 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -1042,16 +1042,17 @@ function M.on_publish_diagnostics(_, _, params, client_id, _, config) end -- restores the extmarks set by M.display +--- @param last number last line that was changed -- @private -local function restore_extmarks(bufnr) - local lcount = api.nvim_buf_line_count(bufnr) +local function restore_extmarks(bufnr, last) for client_id, extmarks in pairs(diagnostic_cache_extmarks[bufnr]) do local ns = M._get_diagnostic_namespace(client_id) local extmarks_current = api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {details = true}) local found = {} for _, extmark in ipairs(extmarks_current) do - -- HACK: the missing extmarks seem to still exist, but at the line after the last - if extmark[2] < lcount then + -- nvim_buf_set_lines will move any extmark to the line after the last + -- nvim_buf_set_text will move any extmark to the last line + if extmark[2] ~= last + 1 then found[extmark[1]] = true end end @@ -1076,8 +1077,8 @@ local function save_extmarks(bufnr, client_id) bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr if not diagnostic_attached_buffers[bufnr] then api.nvim_buf_attach(bufnr, false, { - on_lines = function() - restore_extmarks(bufnr) + on_lines = function(_, _, _, _, _, last) + restore_extmarks(bufnr, last - 1) end, on_detach = function() diagnostic_cache_extmarks[bufnr] = nil @@ -1210,7 +1211,7 @@ function M.show_line_diagnostics(opts, bufnr, line_nr, client_id) table.insert(lines, prefix..message_lines[1]) table.insert(highlights, {#prefix, hiname}) for j = 2, #message_lines do - table.insert(lines, message_lines[j]) + table.insert(lines, string.rep(' ', #prefix) .. message_lines[j]) table.insert(highlights, {0, hiname}) end end diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 41852b9d88..797ff762cb 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -18,10 +18,8 @@ local function err_message(...) end --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand -M['workspace/executeCommand'] = function(err, _) - if err then - error("Could not execute code action: "..err.message) - end +M['workspace/executeCommand'] = function() + -- Error handling is done implicitly by wrapping all handlers; see end of this file end -- @msg of type ProgressParams @@ -158,13 +156,12 @@ 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) +M['workspace/configuration'] = function(_, _, 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 @@ -191,30 +188,33 @@ M['textDocument/codeLens'] = function(...) return require('vim.lsp.codelens').on_codelens(...) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references -M['textDocument/references'] = function(_, _, result) - if not result then return end - util.set_qflist(util.locations_to_items(result)) - api.nvim_command("copen") -end ---@private ---- Prints given list of symbols to the quickfix list. ---@param _ (not used) ---@param _ (not used) ---@param result (list of Symbols) LSP method name ---@param result (table) result of LSP method; a location or a list of locations. ----(`textDocument/definition` can return `Location` or `Location[]` -local symbol_handler = function(_, _, result, _, bufnr) - if not result or vim.tbl_isempty(result) then return end - util.set_qflist(util.symbols_to_items(result, bufnr)) - api.nvim_command("copen") +--@private +--- Return a function that converts LSP responses to quickfix items and opens the qflist +-- +--@param map_result function `((resp, bufnr) -> list)` to convert the response +--@param entity name of the resource used in a `not found` error message +local function response_to_qflist(map_result, entity) + return function(_, _, result, _, bufnr) + if not result or vim.tbl_isempty(result) then + vim.notify('No ' .. entity .. ' found') + else + util.set_qflist(map_result(result, bufnr)) + api.nvim_command("copen") + end + end end + + +--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references +M['textDocument/references'] = response_to_qflist(util.locations_to_items, 'references') + --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol -M['textDocument/documentSymbol'] = symbol_handler +M['textDocument/documentSymbol'] = response_to_qflist(util.symbols_to_items, 'document symbols') + --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol -M['workspace/symbol'] = symbol_handler +M['workspace/symbol'] = response_to_qflist(util.symbols_to_items, 'symbols') --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename M['textDocument/rename'] = function(_, _, result) @@ -223,15 +223,15 @@ M['textDocument/rename'] = function(_, _, result) end --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting -M['textDocument/rangeFormatting'] = function(_, _, result) +M['textDocument/rangeFormatting'] = function(_, _, result, _, bufnr) if not result then return end - util.apply_text_edits(result) + util.apply_text_edits(result, bufnr) end --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting -M['textDocument/formatting'] = function(_, _, result) +M['textDocument/formatting'] = function(_, _, result, _, bufnr) if not result then return end - util.apply_text_edits(result) + util.apply_text_edits(result, bufnr) end --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion @@ -316,6 +316,7 @@ M['textDocument/typeDefinition'] = location_handler M['textDocument/implementation'] = location_handler --- |lsp-handler| for the method "textDocument/signatureHelp" +--- The active parameter is highlighted with |hl-LspSignatureActiveParameter| --- <pre> --- vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with( --- vim.lsp.handlers.signature_help, { @@ -328,23 +329,33 @@ M['textDocument/implementation'] = location_handler --- - border: (default=nil) --- - Add borders to the floating window --- - See |vim.api.nvim_open_win()| -function M.signature_help(_, method, result, _, bufnr, config) +function M.signature_help(_, method, result, client_id, bufnr, config) config = config or {} config.focus_id = method -- When use `autocmd CompleteDone <silent><buffer> lua vim.lsp.buf.signature_help()` to call signatureHelp handler -- If the completion item doesn't have signatures It will make noise. Change to use `print` that can use `<silent>` to ignore if not (result and result.signatures and result.signatures[1]) then - print('No signature help available') + if config.silent ~= true then + print('No signature help available') + end return end + local client = vim.lsp.get_client_by_id(client_id) + local triggers = client.resolved_capabilities.signature_help_trigger_characters local ft = api.nvim_buf_get_option(bufnr, 'filetype') - local lines = util.convert_signature_help_to_markdown_lines(result, ft) + local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers) lines = util.trim_empty_lines(lines) if vim.tbl_isempty(lines) then - print('No signature help available') + if config.silent ~= true then + print('No signature help available') + end return end - return util.open_floating_preview(lines, "markdown", config) + local fbuf, fwin = util.open_floating_preview(lines, "markdown", config) + if hl then + api.nvim_buf_add_highlight(fbuf, -1, "LspSignatureActiveParameter", 0, unpack(hl)) + end + return fbuf, fwin end --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp @@ -436,7 +447,12 @@ for k, fn in pairs(M) do }) if err then - return err_message(tostring(err)) + -- LSP spec: + -- interface ResponseError: + -- code: integer; + -- message: string; + -- data?: string | number | boolean | array | object | null; + return err_message(tostring(err.code) .. ': ' .. err.message) end return fn(err, method, params, client_id, bufnr, config) diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 471a311c16..73fafb9715 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -17,7 +17,7 @@ local current_log_level = log.levels.WARN local log_date_format = "%FT%H:%M:%S%z" do - local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/" + local path_sep = vim.loop.os_uname().version:match("Windows") and "\\" or "/" --@private local function path_join(...) return table.concat(vim.tbl_flatten{...}, path_sep) diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 7e43eb84de..6d02b9ba74 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -691,10 +691,11 @@ function protocol.make_client_capabilities() signatureHelp = { dynamicRegistration = false; signatureInformation = { + activeParameterSupport = true; documentationFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText }; - -- parameterInformation = { - -- labelOffsetSupport = false; - -- }; + parameterInformation = { + labelOffsetSupport = true; + }; }; }; references = { diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 06afc2c5e2..f047a12dff 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -845,9 +845,10 @@ end --- --@param signature_help Response of `textDocument/SignatureHelp` --@param ft optional filetype that will be use as the `lang` for the label markdown code block +--@param triggers optional list of trigger characters from the lsp server. used to better determine parameter offsets --@returns list of lines of converted markdown. --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp -function M.convert_signature_help_to_markdown_lines(signature_help, ft) +function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers) if not signature_help.signatures then return end @@ -856,6 +857,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft) --=== 0`. Whenever possible implementors should make an active decision about --the active signature and shouldn't rely on a default value. local contents = {} + local active_hl local active_signature = signature_help.activeSignature or 0 -- If the activeSignature is not inside the valid range, then clip it. if active_signature >= #signature_help.signatures then @@ -875,11 +877,17 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft) M.convert_input_to_markdown_lines(signature.documentation, contents) end if signature.parameters and #signature.parameters > 0 then - local active_parameter = signature_help.activeParameter or 0 - -- If the activeParameter is not inside the valid range, then clip it. + local active_parameter = (signature.activeParameter or signature_help.activeParameter or 0) + if active_parameter < 0 + then active_parameter = 0 + end + + -- If the activeParameter is > #parameters, then set it to the last + -- NOTE: this is not fully according to the spec, but a client-side interpretation if active_parameter >= #signature.parameters then - active_parameter = 0 + active_parameter = #signature.parameters - 1 end + local parameter = signature.parameters[active_parameter + 1] if parameter then --[=[ @@ -900,13 +908,35 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft) documentation?: string | MarkupContent; } --]=] - -- TODO highlight parameter + if parameter.label then + if type(parameter.label) == "table" then + active_hl = parameter.label + else + local offset = 1 + -- try to set the initial offset to the first found trigger character + for _, t in ipairs(triggers or {}) do + local trigger_offset = signature.label:find(t, 1, true) + if trigger_offset and (offset == 1 or trigger_offset < offset) then + offset = trigger_offset + end + end + for p, param in pairs(signature.parameters) do + offset = signature.label:find(param.label, offset, true) + if not offset then break end + if p == active_parameter + 1 then + active_hl = {offset - 1, offset + #parameter.label - 1} + break + end + offset = offset + #param.label + 1 + end + end + end if parameter.documentation then M.convert_input_to_markdown_lines(parameter.documentation, contents) end end end - return contents + return contents, active_hl end --- Creates a table with sensible default options for a floating window. The diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py index 18a2839702..2efa544c2e 100755 --- a/scripts/gen_vimdoc.py +++ b/scripts/gen_vimdoc.py @@ -950,6 +950,8 @@ def main(config, args): os.remove(mpack_file) output_dir = out_dir.format(target=target) + log.info("Generating documentation for %s in folder %s", + target, output_dir) debug = args.log_level >= logging.DEBUG p = subprocess.Popen( ['doxygen', '-'], @@ -1105,7 +1107,8 @@ def filter_source(filename): def parse_args(): targets = ', '.join(CONFIG.keys()) - ap = argparse.ArgumentParser() + ap = argparse.ArgumentParser( + description="Generate helpdoc from source code") ap.add_argument( "--log-level", "-l", choices=LOG_LEVELS.keys(), default=logging.getLevelName(logging.ERROR), help="Set log verbosity" @@ -1159,6 +1162,7 @@ if __name__ == "__main__": print("Setting log level to %s" % args.log_level) args.log_level = LOG_LEVELS[args.log_level] log.setLevel(args.log_level) + log.addHandler(logging.StreamHandler()) if len(args.source_filter) > 0: filter_source(args.source_filter[0]) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 2abd4827b3..3b4fc6c3df 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -55,7 +55,6 @@ #include "nvim/mark.h" #include "nvim/extmark.h" #include "nvim/mbyte.h" -#include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" @@ -139,7 +138,7 @@ read_buffer( if (read_stdin) { // Set or reset 'modified' before executing autocommands, so that // it can be changed there. - if (!readonlymode && !BUFEMPTY()) { + if (!readonlymode && !buf_is_empty(curbuf)) { changed(); } else if (retval != FAIL) { unchanged(curbuf, false, true); @@ -1921,7 +1920,7 @@ bool curbuf_reusable(void) return (curbuf != NULL && curbuf->b_ffname == NULL && curbuf->b_nwindows <= 1 - && (curbuf->b_ml.ml_mfp == NULL || BUFEMPTY()) + && (curbuf->b_ml.ml_mfp == NULL || buf_is_empty(curbuf)) && !bt_quickfix(curbuf) && !curbufIsChanged()); } @@ -2061,7 +2060,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) // If 'switchbuf' contains "split", "vsplit" or "newtab" and the // current buffer isn't empty: open new tab or window if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB)) - && !BUFEMPTY()) { + && !buf_is_empty(curbuf)) { if (swb_flags & SWB_NEWTAB) { tabpage_new(); } else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0) @@ -4951,7 +4950,7 @@ do_arg_all( win_enter(lastwin, false); // ":tab drop file" should re-use an empty window to avoid "--remote-tab" // leaving an empty tab page when executed locally. - if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 + if (keep_tabs && buf_is_empty(curbuf) && curbuf->b_nwindows == 1 && curbuf->b_ffname == NULL && !curbuf->b_changed) { use_firstwin = true; tab_drop_empty_window = true; @@ -5696,3 +5695,4 @@ void buf_open_scratch(handle_T bufnr, char *bufname) set_option_value("swf", 0L, NULL, OPT_LOCAL); RESET_BINDING(curwin); } + diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h index ac7ead5f92..02a2ac36f7 100644 --- a/src/nvim/buffer.h +++ b/src/nvim/buffer.h @@ -9,6 +9,7 @@ #include "nvim/func_attr.h" #include "nvim/eval.h" #include "nvim/macros.h" +#include "nvim/memline.h" // Values for buflist_getfile() enum getf_values { @@ -128,4 +129,10 @@ static inline void buf_inc_changedtick(buf_T *const buf) buf_set_changedtick(buf, buf_get_changedtick(buf) + 1); } +static inline bool buf_is_empty(buf_T *buf) +{ + return buf->b_ml.ml_line_count == 1 + && *ml_get_buf(buf, (linenr_T)1, false) == '\0'; +} + #endif // NVIM_BUFFER_H diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 17bd81b230..2fe85e0543 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -525,6 +525,8 @@ struct file_buffer { int b_flags; // various BF_ flags int b_locked; // Buffer is being closed or referenced, don't // let autocommands wipe it out. + int b_ro_locked; // Non-zero when the buffer can't be changed. + // Used for FileChangedRO // // b_ffname has the full path of the file (NULL for no name). diff --git a/src/nvim/change.c b/src/nvim/change.c index 9880ffa447..ca1ca756bb 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -40,18 +40,18 @@ /// "col" is the column for the message; non-zero when in insert mode and /// 'showmode' is on. /// Careful: may trigger autocommands that reload the buffer. -void change_warning(int col) +void change_warning(buf_T *buf, int col) { static char *w_readonly = N_("W10: Warning: Changing a readonly file"); - if (curbuf->b_did_warn == false + if (buf->b_did_warn == false && curbufIsChanged() == 0 && !autocmd_busy - && curbuf->b_p_ro) { - curbuf_lock++; - apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, false, curbuf); - curbuf_lock--; - if (!curbuf->b_p_ro) { + && buf->b_p_ro) { + buf->b_ro_locked++; + apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, false, buf); + buf->b_ro_locked--; + if (!buf->b_p_ro) { return; } // Do what msg() does, but with a column offset if the warning should @@ -70,7 +70,7 @@ void change_warning(int col) ui_flush(); os_delay(1002L, true); // give the user time to think about it } - curbuf->b_did_warn = true; + buf->b_did_warn = true; redraw_cmdline = false; // don't redraw and erase the message if (msg_row < Rows - 1) { showmode(); @@ -91,7 +91,7 @@ void changed(void) // Give a warning about changing a read-only file. This may also // check-out the file, thus change "curbuf"! - change_warning(0); + change_warning(curbuf, 0); // Create a swap file if that is wanted. // Don't do this for "nofile" and "nowrite" buffer types. diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 60af11e94b..a0db1bcdfd 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -289,6 +289,9 @@ static void close_cb(Stream *stream, void *data) /// `on_stdout` is ignored /// @param[in] detach True if the job should not be killed when nvim exits, /// ignored if `pty` is true +/// @param[in] stdin_mode Stdin mode. Either kChannelStdinPipe to open a +/// channel for stdin or kChannelStdinNull to leave +/// stdin disconnected. /// @param[in] cwd Initial working directory for the job. Nvim's working /// directory if `cwd` is NULL /// @param[in] pty_width Width of the pty, ignored if `pty` is false @@ -302,7 +305,7 @@ static void close_cb(Stream *stream, void *data) Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader on_stderr, Callback on_exit, bool pty, bool rpc, bool overlapped, bool detach, - const char *cwd, + ChannelStdinMode stdin_mode, const char *cwd, uint16_t pty_width, uint16_t pty_height, dict_T *env, varnumber_T *status_out) { @@ -345,7 +348,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, proc->overlapped = overlapped; char *cmd = xstrdup(proc->argv[0]); - bool has_out, has_err; + bool has_in, has_out, has_err; if (proc->type == kProcessTypePty) { has_out = true; has_err = false; @@ -353,7 +356,17 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, has_out = rpc || callback_reader_set(chan->on_data); has_err = callback_reader_set(chan->on_stderr); } - int status = process_spawn(proc, true, has_out, has_err); + + switch (stdin_mode) { + case kChannelStdinPipe: + has_in = true; + break; + case kChannelStdinNull: + has_in = false; + break; + } + + int status = process_spawn(proc, has_in, has_out, has_err); if (status) { EMSG3(_(e_jobspawn), os_strerror(status), cmd); xfree(cmd); @@ -369,7 +382,9 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout, tv_dict_free(proc->env); } - wstream_init(&proc->in, 0); + if (has_in) { + wstream_init(&proc->in, 0); + } if (has_out) { rstream_init(&proc->out, 0); } diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 9d26852ce5..df858e1602 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -28,6 +28,10 @@ typedef enum { kChannelPartAll } ChannelPart; +typedef enum { + kChannelStdinPipe, + kChannelStdinNull, +} ChannelStdinMode; typedef struct { Stream in; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 961615dc9d..299175b28c 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1334,9 +1334,9 @@ static void set_diff_option(win_T *wp, int value) curwin = wp; curbuf = curwin->w_buffer; - curbuf_lock++; + curbuf->b_ro_locked++; set_option_value("diff", (long)value, NULL, OPT_LOCAL); - curbuf_lock--; + curbuf->b_ro_locked--; curwin = old_curwin; curbuf = curwin->w_buffer; } @@ -2603,7 +2603,7 @@ void ex_diffgetput(exarg_T *eap) // FileChangedRO autocommand, which may do nasty things and mess // everything up. if (!curbuf->b_changed) { - change_warning(0); + change_warning(curbuf, 0); if (diff_buf_idx(curbuf) != idx_to) { EMSG(_("E787: Buffer changed unexpectedly")); goto theend; @@ -2669,7 +2669,7 @@ void ex_diffgetput(exarg_T *eap) } } - buf_empty = BUFEMPTY(); + buf_empty = buf_is_empty(curbuf); added = 0; for (i = 0; i < count; ++i) { diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 38ddd3af12..2305faa20c 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -467,7 +467,7 @@ static void insert_enter(InsertState *s) } if (!p_im && did_restart_edit == 0) { - change_warning(s->i == 0 ? 0 : s->i + 1); + change_warning(curbuf, s->i == 0 ? 0 : s->i + 1); } ui_cursor_shape(); // may show different cursor shape @@ -8047,7 +8047,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // can't backup past first character in buffer // can't backup past starting point unless 'backspace' > 1 // can backup to a previous line if 'backspace' == 0 - if (BUFEMPTY() + if (buf_is_empty(curbuf) || (!revins_on && ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) || (!can_bs(BS_START) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1ba31bfe68..8960cac9c5 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1078,10 +1078,11 @@ static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - /* Check for undo allowed here, because if something was already inserted - * the line was already saved for undo and this check isn't done. */ - if (!undo_allowed()) + // Check for undo allowed here, because if something was already inserted + // the line was already saved for undo and this check isn't done. + if (!undo_allowed(curbuf)) { return; + } if (argvars[1].v_type != VAR_LIST) { EMSG(_(e_invarg)); @@ -5181,6 +5182,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) bool pty = false; bool clear_env = false; bool overlapped = false; + ChannelStdinMode stdin_mode = kChannelStdinPipe; CallbackReader on_stdout = CALLBACK_READER_INIT, on_stderr = CALLBACK_READER_INIT; Callback on_exit = CALLBACK_NONE; @@ -5195,6 +5197,17 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) clear_env = tv_dict_get_number(job_opts, "clear_env") != 0; overlapped = tv_dict_get_number(job_opts, "overlapped") != 0; + char *s = tv_dict_get_string(job_opts, "stdin", false); + if (s) { + if (!strncmp(s, "null", NUMBUFLEN)) { + stdin_mode = kChannelStdinNull; + } else if (!strncmp(s, "pipe", NUMBUFLEN)) { + // Nothing to do, default value + } else { + EMSG3(_(e_invargNval), "stdin", s); + } + } + if (pty && rpc) { EMSG2(_(e_invarg2), "job cannot have both 'pty' and 'rpc' options set"); shell_free_argv(argv); @@ -5251,8 +5264,8 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) env = create_environment(job_env, clear_env, pty, term_name); Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty, - rpc, overlapped, detach, cwd, width, height, - env, &rettv->vval.v_number); + rpc, overlapped, detach, stdin_mode, cwd, + width, height, env, &rettv->vval.v_number); if (chan) { channel_create_event(chan, NULL); } @@ -7732,8 +7745,9 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr) Channel *chan = channel_job_start(argv, CALLBACK_READER_INIT, CALLBACK_READER_INIT, CALLBACK_NONE, - false, true, false, false, NULL, 0, 0, - NULL, &rettv->vval.v_number); + false, true, false, false, + kChannelStdinPipe, NULL, 0, 0, NULL, + &rettv->vval.v_number); if (chan) { channel_create_event(chan, NULL); } @@ -10849,10 +10863,11 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) const bool rpc = false; const bool overlapped = false; const bool detach = false; + ChannelStdinMode stdin_mode = kChannelStdinPipe; uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin)); Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, - pty, rpc, overlapped, detach, cwd, - term_width, curwin->w_height_inner, + pty, rpc, overlapped, detach, stdin_mode, + cwd, term_width, curwin->w_height_inner, env, &rettv->vval.v_number); if (rettv->vval.v_number <= 0) { return; diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index d522e72a99..f14a93eb44 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3459,54 +3459,54 @@ dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, /// Set "copyID + 1" in previous_funccal and callers. bool set_ref_in_previous_funccal(int copyID) { - bool abort = false; - - for (funccall_T *fc = previous_funccal; !abort && fc != NULL; + for (funccall_T *fc = previous_funccal; fc != NULL; fc = fc->caller) { fc->fc_copyID = copyID + 1; - abort = abort - || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL) - || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL) - || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL); + if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL) + || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL) + || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL)) { + return true; + } } - return abort; + return false; } static bool set_ref_in_funccal(funccall_T *fc, int copyID) { - bool abort = false; - if (fc->fc_copyID != copyID) { fc->fc_copyID = copyID; - abort = abort - || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL) - || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL) - || set_ref_in_list(&fc->l_varlist, copyID, NULL) - || set_ref_in_func(NULL, fc->func, copyID); + if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL) + || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL) + || set_ref_in_list(&fc->l_varlist, copyID, NULL) + || set_ref_in_func(NULL, fc->func, copyID)) { + return true; + } } - return abort; + return false; } /// Set "copyID" in all local vars and arguments in the call stack. bool set_ref_in_call_stack(int copyID) { - bool abort = false; - - for (funccall_T *fc = current_funccal; !abort && fc != NULL; + for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->caller) { - abort = abort || set_ref_in_funccal(fc, copyID); + if (set_ref_in_funccal(fc, copyID)) { + return true; + } } // Also go through the funccal_stack. - for (funccal_entry_T *entry = funccal_stack; !abort && entry != NULL; + for (funccal_entry_T *entry = funccal_stack; entry != NULL; entry = entry->next) { - for (funccall_T *fc = entry->top_funccal; !abort && fc != NULL; + for (funccall_T *fc = entry->top_funccal; fc != NULL; fc = fc->caller) { - abort = abort || set_ref_in_funccal(fc, copyID); + if (set_ref_in_funccal(fc, copyID)) { + return true; + } } } - return abort; + return false; } /// Set "copyID" in all functions available by name. @@ -3514,7 +3514,6 @@ bool set_ref_in_functions(int copyID) { int todo; hashitem_T *hi = NULL; - bool abort = false; ufunc_T *fp; todo = (int)func_hashtab.ht_used; @@ -3522,24 +3521,25 @@ bool set_ref_in_functions(int copyID) if (!HASHITEM_EMPTY(hi)) { todo--; fp = HI2UF(hi); - if (!func_name_refcount(fp->uf_name)) { - abort = abort || set_ref_in_func(NULL, fp, copyID); + if (!func_name_refcount(fp->uf_name) + && set_ref_in_func(NULL, fp, copyID)) { + return true; } } } - return abort; + return false; } /// Set "copyID" in all function arguments. bool set_ref_in_func_args(int copyID) { - bool abort = false; - for (int i = 0; i < funcargs.ga_len; i++) { - abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i], - copyID, NULL, NULL); + if (set_ref_in_item(((typval_T **)funcargs.ga_data)[i], + copyID, NULL, NULL)) { + return true; + } } - return abort; + return false; } /// Mark all lists and dicts referenced through function "name" with "copyID". diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 3fb81dbd9f..0e7d7c2dc2 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2607,7 +2607,7 @@ int do_ecmd( && (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)) { // Sync first so that this is a separate undo-able action. u_sync(false); - if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, true) + if (u_savecommon(curbuf, 0, curbuf->b_ml.ml_line_count + 1, 0, true) == FAIL) { xfree(new_name); goto theend; @@ -5159,9 +5159,9 @@ void fix_help_buffer(void) // Set filetype to "help". if (STRCMP(curbuf->b_p_ft, "help") != 0) { - curbuf_lock++; + curbuf->b_ro_locked++; set_option_value("ft", 0L, "help", OPT_LOCAL); - curbuf_lock--; + curbuf->b_ro_locked--; } if (!syntax_present(curwin)) { diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index f928c61ea4..d64b14c9c5 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -58,7 +58,7 @@ #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 + // current buffer is locked #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 diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a50c5527ca..83472fe146 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1518,7 +1518,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, goto doend; } - // Disallow editing another buffer when "curbuf_lock" is set. + // Disallow editing another buffer when "curbuf->b_ro_locked" is set. // 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). @@ -1601,7 +1601,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, else ea.arg = skipwhite(p); - // ":file" cannot be run with an argument when "curbuf_lock" is set + // ":file" cannot be run with an argument when "curbuf->b_ro_locked" is set if (ea.cmdidx == CMD_file && *ea.arg != NUL && curbuf_locked()) { goto doend; } @@ -7345,16 +7345,18 @@ do_exedit( old_curwin == NULL ? curwin : NULL); } else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit) || *eap->arg != NUL) { - /* Can't edit another file when "curbuf_lock" is set. Only ":edit" - * can bring us here, others are stopped earlier. */ - if (*eap->arg != NUL && curbuf_locked()) + // Can't edit another file when "curbuf->b_ro_lockec" is set. Only ":edit" + // can bring us here, others are stopped earlier. + if (*eap->arg != NUL && curbuf_locked()) { return; + } n = readonlymode; - if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview) - readonlymode = TRUE; - else if (eap->cmdidx == CMD_enew) - readonlymode = FALSE; /* 'readonly' doesn't make sense in an - empty buffer */ + if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview) { + readonlymode = true; + } else if (eap->cmdidx == CMD_enew) { + readonlymode = false; // 'readonly' doesn't make sense + // in an empty buffer + } if (eap->cmdidx != CMD_balt && eap->cmdidx != CMD_badd) { setpcmark(); } @@ -8008,16 +8010,16 @@ static void ex_wundo(exarg_T *eap) { char_u hash[UNDO_HASH_SIZE]; - u_compute_hash(hash); - u_write_undo((char *) eap->arg, eap->forceit, curbuf, hash); + u_compute_hash(curbuf, hash); + u_write_undo((char *)eap->arg, eap->forceit, curbuf, hash); } static void ex_rundo(exarg_T *eap) { char_u hash[UNDO_HASH_SIZE]; - u_compute_hash(hash); - u_read_undo((char *) eap->arg, hash, NULL); + u_compute_hash(curbuf, hash); + u_read_undo((char *)eap->arg, hash, NULL); } /// ":redo". diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index f63987136f..4ebd384ae0 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2412,13 +2412,11 @@ char_u * get_text_locked_msg(void) { } } -/* - * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is - * and give an error message. - */ +/// Check if "curbuf->b_ro_locked" or "allbuf_lock" is set and +/// return TRUE when it is and give an error message. int curbuf_locked(void) { - if (curbuf_lock > 0) { + if (curbuf->b_ro_locked > 0) { EMSG(_("E788: Not allowed to edit another buffer now")); return TRUE; } @@ -6513,7 +6511,7 @@ static int open_cmdwin(void) curwin->w_p_fen = false; // Don't allow switching to another buffer. - curbuf_lock++; + curbuf->b_ro_locked++; // Showing the prompt may have set need_wait_return, reset it. need_wait_return = false; @@ -6526,7 +6524,7 @@ static int open_cmdwin(void) } set_option_value("ft", 0L, "vim", OPT_LOCAL); } - curbuf_lock--; + curbuf->b_ro_locked--; // Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin // sets 'textwidth' to 78). diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 29c29a2884..ecea3fc01e 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -4687,7 +4687,7 @@ check_timestamps( } if (!stuff_empty() || global_busy || !typebuf_typed() - || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0 + || autocmd_busy || curbuf->b_ro_locked > 0 || allbuf_lock > 0 ) { need_check_timestamps = true; // check later } else { @@ -4967,13 +4967,10 @@ int buf_check_timestamp(buf_T *buf) buf_reload(buf, orig_mode); if (buf->b_p_udf && buf->b_ffname != NULL) { char_u hash[UNDO_HASH_SIZE]; - buf_T *save_curbuf = curbuf; - /* Any existing undo file is unusable, write it now. */ - curbuf = buf; - u_compute_hash(hash); - u_write_undo(NULL, FALSE, buf, hash); - curbuf = save_curbuf; + // Any existing undo file is unusable, write it now. + u_compute_hash(buf, hash); + u_write_undo(NULL, false, buf, hash); } } @@ -5015,10 +5012,10 @@ void buf_reload(buf_T *buf, int orig_mode) old_topline = curwin->w_topline; if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) { - /* Save all the text, so that the reload can be undone. - * Sync first so that this is a separate undo-able action. */ - u_sync(FALSE); - saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE); + // Save all the text, so that the reload can be undone. + // Sync first so that this is a separate undo-able action. + u_sync(false); + saved = u_savecommon(curbuf, 0, curbuf->b_ml.ml_line_count + 1, 0, true); flags |= READ_KEEP_UNDO; } @@ -5027,7 +5024,7 @@ void buf_reload(buf_T *buf, int orig_mode) // buffer contents. But if reading the file fails we should keep // the old contents. Can't use memory only, the file might be // too big. Use a hidden buffer to move the buffer contents to. - if (BUFEMPTY() || saved == FAIL) { + if (buf_is_empty(curbuf) || saved == FAIL) { savebuf = NULL; } else { // Allocate a buffer without putting it in the buffer list. @@ -5060,7 +5057,7 @@ void buf_reload(buf_T *buf, int orig_mode) if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf) { // Put the text back from the save buffer. First // delete any lines that readfile() added. - while (!BUFEMPTY()) { + while (!buf_is_empty(curbuf)) { if (ml_delete(buf->b_ml.ml_line_count, false) == FAIL) { break; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index d14066c747..9fd5ccf324 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -508,9 +508,6 @@ EXTERN int secure INIT(= false); /// allowed. EXTERN int textlock INIT(= 0); -/// Non-zero when the current buffer can't be changed. Used for FileChangedRO. -EXTERN int curbuf_lock INIT(= 0); - /// Non-zero when no buffer name can be changed, no buffer can be deleted and /// current directory can't be changed. Used for SwapExists et al. EXTERN int allbuf_lock INIT(= 0); diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index 164430b911..1b1735c991 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -2398,8 +2398,16 @@ static int prt_add_resource(struct prt_ps_resource_S *resource) EMSG2(_("E456: Can't open file \"%s\""), resource->filename); return FALSE; } - prt_dsc_resources("BeginResource", prt_resource_types[resource->type], - (char *)resource->title); + switch (resource->type) { + case PRT_RESOURCE_TYPE_PROCSET: + case PRT_RESOURCE_TYPE_ENCODING: + case PRT_RESOURCE_TYPE_CMAP: + prt_dsc_resources("BeginResource", prt_resource_types[resource->type], + (char *)resource->title); + break; + default: + return FALSE; + } prt_dsc_textline("BeginDocument", (char *)resource->filename); diff --git a/src/nvim/macros.h b/src/nvim/macros.h index 48a16ed42a..e1aa1b7704 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -34,10 +34,6 @@ /// LINEEMPTY() - return TRUE if the line is empty #define LINEEMPTY(p) (*ml_get(p) == NUL) -/// BUFEMPTY() - return TRUE if the current buffer is empty -#define BUFEMPTY() (curbuf->b_ml.ml_line_count == 1 && *ml_get((linenr_T)1) == \ - NUL) - // toupper() and tolower() that use the current locale. // Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the // range 0 - 255. toupper()/tolower() on some systems can't handle others. diff --git a/src/nvim/main.c b/src/nvim/main.c index 2cb562b558..16700d20ab 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1444,11 +1444,9 @@ static void read_stdin(void) no_wait_return = true; int save_msg_didany = msg_didany; set_buflisted(true); - // Create memfile and read from stdin. (void)open_buffer(true, NULL, 0); - - if (BUFEMPTY() && curbuf->b_next != NULL) { + if (buf_is_empty(curbuf) && curbuf->b_next != NULL) { // stdin was empty, go to buffer 2 (e.g. "echo file1 | xargs nvim"). #8561 do_cmdline_cmd("silent! bnext"); // Delete the empty stdin buffer. diff --git a/src/nvim/move.c b/src/nvim/move.c index 1210a3365a..293f51f2d9 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -17,6 +17,7 @@ #include <stdbool.h> #include "nvim/ascii.h" +#include "nvim/buffer.h" #include "nvim/move.h" #include "nvim/charset.h" #include "nvim/cursor.h" @@ -172,7 +173,7 @@ void update_topline(win_T *wp) old_topfill = wp->w_topfill; // If the buffer is empty, always set topline to 1. - if (BUFEMPTY()) { // special case - file is empty + if (buf_is_empty(curbuf)) { // special case - file is empty if (wp->w_topline != 1) { redraw_later(wp, NOT_VALID); } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 4921054bfc..c51dd09d40 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -3069,7 +3069,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) } // In an empty buffer the empty line is going to be replaced, include // it in the saved lines. - if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL) { + if ((buf_is_empty(curbuf) ? + u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL) { goto end; } if (dir == FORWARD) { diff --git a/src/nvim/option.c b/src/nvim/option.c index fd15114999..0a8a60701a 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -880,7 +880,7 @@ void set_init_3(void) xfree(p); } - if (BUFEMPTY()) { + if (buf_is_empty(curbuf)) { int idx_ffs = findoption_len(S_LEN("ffs")); // Apply the first entry of 'fileformats' to the initial buffer. @@ -3837,22 +3837,19 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, // any changes in between. if (curbuf->b_p_udf || p_udf) { char_u hash[UNDO_HASH_SIZE]; - buf_T *save_curbuf = curbuf; FOR_ALL_BUFFERS(bp) { - curbuf = bp; // When 'undofile' is set globally: for every buffer, otherwise // only for the current buffer: Try to read in the undofile, // if one exists, the buffer wasn't changed and the buffer was // loaded - if ((curbuf == save_curbuf + if ((curbuf == bp || (opt_flags & OPT_GLOBAL) || opt_flags == 0) - && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL) { - u_compute_hash(hash); - u_read_undo(NULL, hash, curbuf->b_fname); + && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) { + u_compute_hash(bp, hash); + u_read_undo(NULL, hash, bp->b_fname); } } - curbuf = save_curbuf; } } else if ((int *)varp == &curbuf->b_p_ro) { // when 'readonly' is reset globally, also reset readonlymode diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index f620517aff..1705ea0c12 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -9,6 +9,7 @@ #include <inttypes.h> #include <stdbool.h> +#include "nvim/buffer.h" #include "nvim/vim.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" @@ -735,7 +736,7 @@ static int pum_set_selected(int n, int repeat) && (curbuf->b_p_bt[2] == 'f') && (curbuf->b_p_bh[0] == 'w')) { // Already a "wipeout" buffer, make it empty. - while (!BUFEMPTY()) { + while (!buf_is_empty(curbuf)) { ml_delete((linenr_T)1, false); } } else { diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index f5963daed9..7c7b790d5c 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4180,7 +4180,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, // Set the 'filetype' to "qf" each time after filling the buffer. This // resembles reading a file into a buffer, it's more logical when using // autocommands. - curbuf_lock++; + curbuf->b_ro_locked++; set_option_value("ft", 0L, "qf", OPT_LOCAL); curbuf->b_p_ma = false; @@ -4190,7 +4190,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, false, curbuf); keep_filetype = false; - curbuf_lock--; + curbuf->b_ro_locked--; // make sure it will be redrawn redraw_curbuf_later(NOT_VALID); diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 35c3285cda..039f9b4675 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -1161,8 +1161,6 @@ static int nfa_regatom(void) int emit_range; int negated; int startc = -1; - int endc = -1; - int oldstartc = -1; int save_prev_at_start = prev_at_start; c = getchr(); @@ -1572,7 +1570,7 @@ collection: * Failed to recognize a character class. Use the simple * version that turns [abc] into 'a' OR 'b' OR 'c' */ - startc = endc = oldstartc = -1; + startc = -1; negated = false; if (*regparse == '^') { // negated range negated = true; @@ -1589,7 +1587,7 @@ collection: // Emit the OR branches for each character in the [] emit_range = false; while (regparse < endp) { - oldstartc = startc; + int oldstartc = startc; startc = -1; got_coll_char = false; if (*regparse == '[') { @@ -1729,7 +1727,7 @@ collection: /* Previous char was '-', so this char is end of range. */ if (emit_range) { - endc = startc; + int endc = startc; startc = oldstartc; if (startc > endc) { EMSG_RET_FAIL(_(e_reverse_range)); diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 771c2106db..28276884b0 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -6672,7 +6672,7 @@ void ex_spelldump(exarg_T *eap) set_option_value("spl", dummy, (char *)spl, OPT_LOCAL); xfree(spl); - if (!BUFEMPTY()) { + if (!buf_is_empty(curbuf)) { return; } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 6bd64caa6c..c0b9dd7696 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -2965,7 +2965,7 @@ func Test_cclose_in_autocmd() " call test_override('starting', 0) endfunc -" Check that ":file" without an argument is possible even when "curbuf_lock" +" Check that ":file" without an argument is possible even when curbuf is locked " is set. func Test_file_from_copen() " Works without argument. diff --git a/src/nvim/undo.c b/src/nvim/undo.c index ffd613cec2..7afabc7913 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -234,7 +234,7 @@ int u_save(linenr_T top, linenr_T bot) if (top + 2 == bot) u_saveline((linenr_T)(top + 1)); - return u_savecommon(top, bot, (linenr_T)0, FALSE); + return u_savecommon(curbuf, top, bot, (linenr_T)0, false); } /* @@ -245,7 +245,7 @@ int u_save(linenr_T top, linenr_T bot) */ int u_savesub(linenr_T lnum) { - return u_savecommon(lnum - 1, lnum + 1, lnum + 1, false); + return u_savecommon(curbuf, lnum - 1, lnum + 1, lnum + 1, false); } /* @@ -256,7 +256,7 @@ int u_savesub(linenr_T lnum) */ int u_inssub(linenr_T lnum) { - return u_savecommon(lnum - 1, lnum, lnum + 1, false); + return u_savecommon(curbuf, lnum - 1, lnum, lnum + 1, false); } /* @@ -268,18 +268,19 @@ int u_inssub(linenr_T lnum) */ int u_savedel(linenr_T lnum, long nlines) { - return u_savecommon(lnum - 1, lnum + nlines, - nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, FALSE); + return u_savecommon( + curbuf, lnum - 1, lnum + nlines, + nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, false); } /// Return true when undo is allowed. Otherwise print an error message and /// return false. /// /// @return true if undo is allowed. -bool undo_allowed(void) +bool undo_allowed(buf_T *buf) { - /* Don't allow changes when 'modifiable' is off. */ - if (!MODIFIABLE(curbuf)) { + // Don't allow changes when 'modifiable' is off. + if (!MODIFIABLE(buf)) { EMSG(_(e_modifiable)); return false; } @@ -301,12 +302,12 @@ bool undo_allowed(void) } /// Get the 'undolevels' value for the current buffer. -static long get_undolevel(void) +static long get_undolevel(buf_T *buf) { - if (curbuf->b_p_ul == NO_LOCAL_UNDOLEVEL) { + if (buf->b_p_ul == NO_LOCAL_UNDOLEVEL) { return p_ul; } - return curbuf->b_p_ul; + return buf->b_p_ul; } static inline void zero_fmark_additional_data(fmark_T *fmarks) @@ -326,7 +327,9 @@ static inline void zero_fmark_additional_data(fmark_T *fmarks) * Careful: may trigger autocommands that reload the buffer. * Returns FAIL when lines could not be saved, OK otherwise. */ -int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) +int u_savecommon(buf_T *buf, + linenr_T top, linenr_T bot, + linenr_T newbot, int reload) { linenr_T lnum; long i; @@ -337,22 +340,23 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) long size; if (!reload) { - /* When making changes is not allowed return FAIL. It's a crude way - * to make all change commands fail. */ - if (!undo_allowed()) + // When making changes is not allowed return FAIL. It's a crude way + // to make all change commands fail. + if (!undo_allowed(buf)) { return FAIL; + } + // Saving text for undo means we are going to make a change. Give a + // warning for a read-only file before making the change, so that the + // FileChangedRO event can replace the buffer with a read-write version + // (e.g., obtained from a source control system). + if (buf == curbuf) { + change_warning(buf, 0); + } - /* - * Saving text for undo means we are going to make a change. Give a - * warning for a read-only file before making the change, so that the - * FileChangedRO event can replace the buffer with a read-write version - * (e.g., obtained from a source control system). - */ - change_warning(0); - if (bot > curbuf->b_ml.ml_line_count + 1) { - /* This happens when the FileChangedRO autocommand changes the - * file in a way it becomes shorter. */ + if (bot > buf->b_ml.ml_line_count + 1) { + // This happens when the FileChangedRO autocommand changes the + // file in a way it becomes shorter. EMSG(_("E881: Line count changed unexpectedly")); return FAIL; } @@ -364,18 +368,14 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) size = bot - top - 1; - /* - * If curbuf->b_u_synced == true make a new header. - */ - if (curbuf->b_u_synced) { - /* Need to create new entry in b_changelist. */ - curbuf->b_new_change = true; - - if (get_undolevel() >= 0) { - /* - * Make a new header entry. Do this first so that we don't mess - * up the undo info when out of memory. - */ + // If curbuf->b_u_synced == true make a new header. + if (buf->b_u_synced) { + // Need to create new entry in b_changelist. + buf->b_new_change = true; + + if (get_undolevel(buf) >= 0) { + // Make a new header entry. Do this first so that we don't mess + // up the undo info when out of memory. uhp = xmalloc(sizeof(u_header_T)); kv_init(uhp->uh_extmark); #ifdef U_DEBUG @@ -388,63 +388,73 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) * If we undid more than we redid, move the entry lists before and * including curbuf->b_u_curhead to an alternate branch. */ - old_curhead = curbuf->b_u_curhead; + old_curhead = buf->b_u_curhead; if (old_curhead != NULL) { - curbuf->b_u_newhead = old_curhead->uh_next.ptr; - curbuf->b_u_curhead = NULL; + buf->b_u_newhead = old_curhead->uh_next.ptr; + buf->b_u_curhead = NULL; } /* * free headers to keep the size right */ - while (curbuf->b_u_numhead > get_undolevel() - && curbuf->b_u_oldhead != NULL) { - u_header_T *uhfree = curbuf->b_u_oldhead; - - if (uhfree == old_curhead) - /* Can't reconnect the branch, delete all of it. */ - u_freebranch(curbuf, uhfree, &old_curhead); - else if (uhfree->uh_alt_next.ptr == NULL) - /* There is no branch, only free one header. */ - u_freeheader(curbuf, uhfree, &old_curhead); - else { - /* Free the oldest alternate branch as a whole. */ - while (uhfree->uh_alt_next.ptr != NULL) + while (buf->b_u_numhead > get_undolevel(buf) + && buf->b_u_oldhead != NULL) { + u_header_T *uhfree = buf->b_u_oldhead; + + if (uhfree == old_curhead) { + // Can't reconnect the branch, delete all of it. + u_freebranch(buf, uhfree, &old_curhead); + } else if (uhfree->uh_alt_next.ptr == NULL) { + // There is no branch, only free one header. + u_freeheader(buf, uhfree, &old_curhead); + } else { + // Free the oldest alternate branch as a whole. + while (uhfree->uh_alt_next.ptr != NULL) { uhfree = uhfree->uh_alt_next.ptr; - u_freebranch(curbuf, uhfree, &old_curhead); + } + u_freebranch(buf, uhfree, &old_curhead); } #ifdef U_DEBUG u_check(TRUE); #endif } - if (uhp == NULL) { /* no undo at all */ - if (old_curhead != NULL) - u_freebranch(curbuf, old_curhead, NULL); - curbuf->b_u_synced = false; + if (uhp == NULL) { // no undo at all + if (old_curhead != NULL) { + u_freebranch(buf, old_curhead, NULL); + } + buf->b_u_synced = false; return OK; } uhp->uh_prev.ptr = NULL; - uhp->uh_next.ptr = curbuf->b_u_newhead; + uhp->uh_next.ptr = buf->b_u_newhead; uhp->uh_alt_next.ptr = old_curhead; if (old_curhead != NULL) { uhp->uh_alt_prev.ptr = old_curhead->uh_alt_prev.ptr; - if (uhp->uh_alt_prev.ptr != NULL) + + if (uhp->uh_alt_prev.ptr != NULL) { uhp->uh_alt_prev.ptr->uh_alt_next.ptr = uhp; + } + old_curhead->uh_alt_prev.ptr = uhp; - if (curbuf->b_u_oldhead == old_curhead) - curbuf->b_u_oldhead = uhp; - } else + + if (buf->b_u_oldhead == old_curhead) { + buf->b_u_oldhead = uhp; + } + } else { uhp->uh_alt_prev.ptr = NULL; - if (curbuf->b_u_newhead != NULL) - curbuf->b_u_newhead->uh_prev.ptr = uhp; + } + + if (buf->b_u_newhead != NULL) { + buf->b_u_newhead->uh_prev.ptr = uhp; + } - uhp->uh_seq = ++curbuf->b_u_seq_last; - curbuf->b_u_seq_cur = uhp->uh_seq; + uhp->uh_seq = ++buf->b_u_seq_last; + buf->b_u_seq_cur = uhp->uh_seq; uhp->uh_time = time(NULL); uhp->uh_save_nr = 0; - curbuf->b_u_time_cur = uhp->uh_time + 1; + buf->b_u_time_cur = uhp->uh_time + 1; uhp->uh_walk = 0; uhp->uh_entry = NULL; @@ -455,23 +465,26 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) else uhp->uh_cursor_vcol = -1; - /* save changed and buffer empty flag for undo */ - uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) + - ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); + // save changed and buffer empty flag for undo + uhp->uh_flags = (buf->b_changed ? UH_CHANGED : 0) + + ((buf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); + + // save named marks and Visual marks for undo + zero_fmark_additional_data(buf->b_namedm); + memmove(uhp->uh_namedm, buf->b_namedm, + sizeof(buf->b_namedm[0]) * NMARKS); + uhp->uh_visual = buf->b_visual; - /* save named marks and Visual marks for undo */ - zero_fmark_additional_data(curbuf->b_namedm); - memmove(uhp->uh_namedm, curbuf->b_namedm, - sizeof(curbuf->b_namedm[0]) * NMARKS); - uhp->uh_visual = curbuf->b_visual; + buf->b_u_newhead = uhp; - curbuf->b_u_newhead = uhp; - if (curbuf->b_u_oldhead == NULL) - curbuf->b_u_oldhead = uhp; - ++curbuf->b_u_numhead; + if (buf->b_u_oldhead == NULL) { + buf->b_u_oldhead = uhp; + } + buf->b_u_numhead++; } else { - if (get_undolevel() < 0) /* no undo at all */ + if (get_undolevel(buf) < 0) { // no undo at all return OK; + } /* * When saving a single line, and it has been saved just before, it @@ -483,7 +496,7 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) * long. */ if (size == 1) { - uep = u_get_headentry(); + uep = u_get_headentry(buf); prev_uep = NULL; for (i = 0; i < 10; ++i) { if (uep == NULL) @@ -491,16 +504,17 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) /* If lines have been inserted/deleted we give up. * Also when the line was included in a multi-line save. */ - if ((curbuf->b_u_newhead->uh_getbot_entry != uep + if ((buf->b_u_newhead->uh_getbot_entry != uep ? (uep->ue_top + uep->ue_size + 1 != (uep->ue_bot == 0 - ? curbuf->b_ml.ml_line_count + 1 + ? buf->b_ml.ml_line_count + 1 : uep->ue_bot)) - : uep->ue_lcount != curbuf->b_ml.ml_line_count) + : uep->ue_lcount != buf->b_ml.ml_line_count) || (uep->ue_size > 1 && top >= uep->ue_top - && top + 2 <= uep->ue_top + uep->ue_size + 1)) + && top + 2 <= uep->ue_top + uep->ue_size + 1)) { break; + } /* If it's the same line we can skip saving it again. */ if (uep->ue_size == 1 && uep->ue_top == top) { @@ -508,8 +522,8 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) /* It's not the last entry: get ue_bot for the last * entry now. Following deleted/inserted lines go to * the re-used entry. */ - u_getbot(); - curbuf->b_u_synced = false; + u_getbot(buf); + buf->b_u_synced = false; /* Move the found entry to become the last entry. The * order of undo/redo doesn't matter for the entries @@ -518,18 +532,18 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) * for the found entry if the line count is changed by * the executed command. */ prev_uep->ue_next = uep->ue_next; - uep->ue_next = curbuf->b_u_newhead->uh_entry; - curbuf->b_u_newhead->uh_entry = uep; + uep->ue_next = buf->b_u_newhead->uh_entry; + buf->b_u_newhead->uh_entry = uep; } - /* The executed command may change the line count. */ - if (newbot != 0) + // The executed command may change the line count. + if (newbot != 0) { uep->ue_bot = newbot; - else if (bot > curbuf->b_ml.ml_line_count) + } else if (bot > buf->b_ml.ml_line_count) { uep->ue_bot = 0; - else { - uep->ue_lcount = curbuf->b_ml.ml_line_count; - curbuf->b_u_newhead->uh_getbot_entry = uep; + } else { + uep->ue_lcount = buf->b_ml.ml_line_count; + buf->b_u_newhead->uh_getbot_entry = uep; } return OK; } @@ -538,8 +552,8 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) } } - /* find line number for ue_bot for previous u_save() */ - u_getbot(); + // find line number for ue_bot for previous u_save() + u_getbot(buf); } /* @@ -553,17 +567,15 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) uep->ue_size = size; uep->ue_top = top; - if (newbot != 0) + if (newbot != 0) { uep->ue_bot = newbot; - /* - * Use 0 for ue_bot if bot is below last line. - * Otherwise we have to compute ue_bot later. - */ - else if (bot > curbuf->b_ml.ml_line_count) + // Use 0 for ue_bot if bot is below last line. + // Otherwise we have to compute ue_bot later. + } else if (bot > buf->b_ml.ml_line_count) { uep->ue_bot = 0; - else { - uep->ue_lcount = curbuf->b_ml.ml_line_count; - curbuf->b_u_newhead->uh_getbot_entry = uep; + } else { + uep->ue_lcount = buf->b_ml.ml_line_count; + buf->b_u_newhead->uh_getbot_entry = uep; } if (size > 0) { @@ -574,17 +586,19 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) u_freeentry(uep, i); return FAIL; } - uep->ue_array[i] = u_save_line(lnum++); + uep->ue_array[i] = u_save_line_buf(buf, lnum++); } - } else + } else { uep->ue_array = NULL; - uep->ue_next = curbuf->b_u_newhead->uh_entry; - curbuf->b_u_newhead->uh_entry = uep; + } + + uep->ue_next = buf->b_u_newhead->uh_entry; + buf->b_u_newhead->uh_entry = uep; if (reload) { // buffer was reloaded, notify text change subscribers curbuf->b_u_newhead->uh_flags |= UH_RELOAD; } - curbuf->b_u_synced = false; + buf->b_u_synced = false; undo_undoes = false; #ifdef U_DEBUG @@ -617,18 +631,20 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload) static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s"); -/* - * Compute the hash for the current buffer text into hash[UNDO_HASH_SIZE]. - */ -void u_compute_hash(char_u *hash) +/// Compute the hash for a buffer text into hash[UNDO_HASH_SIZE]. +/// +/// @param[in] buf The buffer used to compute the hash +/// @param[in] hash Array of size UNDO_HASH_SIZE in which to store the value of +/// the hash +void u_compute_hash(buf_T *buf, char_u *hash) { context_sha256_T ctx; linenr_T lnum; char_u *p; sha256_start(&ctx); - for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) { - p = ml_get(lnum); + for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { + p = ml_get_buf(buf, lnum, false); sha256_update(&ctx, p, (uint32_t)(STRLEN(p) + 1)); } sha256_finish(&ctx, hash); @@ -1846,8 +1862,9 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event) { int count = startcount; - if (!undo_allowed()) + if (!undo_allowed(curbuf)) { return; + } u_newcount = 0; u_oldcount = 0; @@ -1858,15 +1875,16 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event) * needed. This may cause the file to be reloaded, that must happen * before we do anything, because it may change curbuf->b_u_curhead * and more. */ - change_warning(0); + change_warning(curbuf, 0); if (undo_undoes) { - if (curbuf->b_u_curhead == NULL) /* first undo */ + if (curbuf->b_u_curhead == NULL) { // first undo curbuf->b_u_curhead = curbuf->b_u_newhead; - else if (get_undolevel() > 0) /* multi level undo */ - /* get next undo */ + } else if (get_undolevel(curbuf) > 0) { // multi level undo + // get next undo curbuf->b_u_curhead = curbuf->b_u_curhead->uh_next.ptr; - /* nothing to undo */ + } + // nothing to undo if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL) { /* stick curbuf->b_u_curhead at end */ curbuf->b_u_curhead = curbuf->b_u_oldhead; @@ -1880,8 +1898,8 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event) u_undoredo(true, do_buf_event); } else { - if (curbuf->b_u_curhead == NULL || get_undolevel() <= 0) { - beep_flush(); /* nothing to redo */ + if (curbuf->b_u_curhead == NULL || get_undolevel(curbuf) <= 0) { + beep_flush(); // nothing to redo if (count == startcount - 1) { MSG(_("Already at newest change")); return; @@ -2122,8 +2140,8 @@ target_zero: if (uhp != NULL || target == 0) { // First go up the tree as much as needed. while (!got_int) { - /* Do the change warning now, for the same reason as above. */ - change_warning(0); + // Do the change warning now, for the same reason as above. + change_warning(curbuf, 0); uhp = curbuf->b_u_curhead; if (uhp == NULL) @@ -2147,7 +2165,7 @@ target_zero: // And now go down the tree (redo), branching off where needed. while (!got_int) { // Do the change warning now, for the same reason as above. - change_warning(0); + change_warning(curbuf, 0); uhp = curbuf->b_u_curhead; if (uhp == NULL) { @@ -2414,7 +2432,7 @@ static void u_undoredo(int undo, bool do_buf_event) curhead->uh_entry = newlist; curhead->uh_flags = new_flags; - if ((old_flags & UH_EMPTYBUF) && BUFEMPTY()) { + if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) { curbuf->b_ml.ml_flags |= ML_EMPTY; } if (old_flags & UH_CHANGED) { @@ -2591,13 +2609,15 @@ u_sync( int force // Also sync when no_u_sync is set. ) { - /* Skip it when already synced or syncing is disabled. */ - if (curbuf->b_u_synced || (!force && no_u_sync > 0)) + // Skip it when already synced or syncing is disabled. + if (curbuf->b_u_synced || (!force && no_u_sync > 0)) { return; - if (get_undolevel() < 0) - curbuf->b_u_synced = true; /* no entries, nothing to do */ - else { - u_getbot(); /* compute ue_bot of previous u_save */ + } + + if (get_undolevel(curbuf) < 0) { + curbuf->b_u_synced = true; // no entries, nothing to do + } else { + u_getbot(curbuf); // compute ue_bot of previous u_save curbuf->b_u_curhead = NULL; } } @@ -2708,7 +2728,7 @@ void ex_undojoin(exarg_T *eap) if (!curbuf->b_u_synced) { return; // already unsynced } - if (get_undolevel() < 0) { + if (get_undolevel(curbuf) < 0) { return; // no entries, nothing to do } else { curbuf->b_u_synced = false; // Append next change to last entry @@ -2792,38 +2812,39 @@ static void u_unch_branch(u_header_T *uhp) * Get pointer to last added entry. * If it's not valid, give an error message and return NULL. */ -static u_entry_T *u_get_headentry(void) +static u_entry_T *u_get_headentry(buf_T *buf) { - if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL) { + if (buf->b_u_newhead == NULL || buf->b_u_newhead->uh_entry == NULL) { IEMSG(_("E439: undo list corrupt")); return NULL; } - return curbuf->b_u_newhead->uh_entry; + return buf->b_u_newhead->uh_entry; } /* * u_getbot(): compute the line number of the previous u_save * It is called only when b_u_synced is false. */ -static void u_getbot(void) +static void u_getbot(buf_T *buf) { u_entry_T *uep; linenr_T extra; - uep = u_get_headentry(); /* check for corrupt undo list */ - if (uep == NULL) + uep = u_get_headentry(buf); // check for corrupt undo list + if (uep == NULL) { return; + } - uep = curbuf->b_u_newhead->uh_getbot_entry; + uep = buf->b_u_newhead->uh_getbot_entry; if (uep != NULL) { /* * the new ue_bot is computed from the number of lines that has been * inserted (0 - deleted) since calling u_save. This is equal to the * old line count subtracted from the current line count. */ - extra = curbuf->b_ml.ml_line_count - uep->ue_lcount; + extra = buf->b_ml.ml_line_count - uep->ue_lcount; uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra; - if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count) { + if (uep->ue_bot < 1 || uep->ue_bot > buf->b_ml.ml_line_count) { IEMSG(_("E440: undo line missing")); uep->ue_bot = uep->ue_top + 1; // assume all lines deleted, will // get all the old lines back @@ -2831,10 +2852,10 @@ static void u_getbot(void) // ones } - curbuf->b_u_newhead->uh_getbot_entry = NULL; + buf->b_u_newhead->uh_getbot_entry = NULL; } - curbuf->b_u_synced = true; + buf->b_u_synced = true; } /* @@ -3014,10 +3035,12 @@ void u_undoline(void) return; } - /* first save the line for the 'u' command */ - if (u_savecommon(curbuf->b_u_line_lnum - 1, - curbuf->b_u_line_lnum + 1, (linenr_T)0, FALSE) == FAIL) + // first save the line for the 'u' command + if (u_savecommon(curbuf, curbuf->b_u_line_lnum - 1, + curbuf->b_u_line_lnum + 1, (linenr_T)0, false) == FAIL) { return; + } + oldp = u_save_line(curbuf->b_u_line_lnum); ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, true); changed_bytes(curbuf->b_u_line_lnum, 0); @@ -3048,12 +3071,21 @@ void u_blockfree(buf_T *buf) xfree(buf->b_u_line_ptr); } -/* - * u_save_line(): allocate memory and copy line 'lnum' into it. - */ +/// Allocate memory and copy curbuf line into it. +/// +/// @param lnum the line to copy static char_u *u_save_line(linenr_T lnum) { - return vim_strsave(ml_get(lnum)); + return u_save_line_buf(curbuf, lnum); +} + +/// Allocate memory and copy line into it +/// +/// @param lnum line to copy +/// @param buf buffer to copy from +static char_u *u_save_line_buf(buf_T *buf, linenr_T lnum) +{ + return vim_strsave(ml_get_buf(buf, lnum, false)); } /// Check if the 'modified' flag is set, or 'ff' has changed (only need to @@ -3143,18 +3175,16 @@ u_header_T *u_force_get_undo_header(buf_T *buf) if (!uhp) { // Undo is normally invoked in change code, which already has swapped // curbuf. - buf_T *save_curbuf = curbuf; - curbuf = buf; // Args are tricky: this means replace empty range by empty range.. - u_savecommon(0, 1, 1, true); + u_savecommon(curbuf, 0, 1, 1, true); + uhp = buf->b_u_curhead; if (!uhp) { uhp = buf->b_u_newhead; - if (get_undolevel() > 0 && !uhp) { + if (get_undolevel(curbuf) > 0 && !uhp) { abort(); } } - curbuf = save_curbuf; } return uhp; } diff --git a/src/nvim/version.c b/src/nvim/version.c index f3a30630f8..48ef71613e 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -13,6 +13,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/vim.h" #include "nvim/ascii.h" +#include "nvim/buffer.h" #include "nvim/iconv.h" #include "nvim/version.h" #include "nvim/charset.h" @@ -2190,7 +2191,7 @@ void list_version(void) /// Show the intro message when not editing a file. void maybe_intro_message(void) { - if (BUFEMPTY() + if (buf_is_empty(curbuf) && (curbuf->b_fname == NULL) && (firstwin->w_next == NULL) && (vim_strchr(p_shm, SHM_INTRO) == NULL)) { diff --git a/src/nvim/window.c b/src/nvim/window.c index d051e8e467..d0bee83db1 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -4666,7 +4666,8 @@ win_free ( // If there already is an entry with "wi_win" set to NULL it // must be removed, it would never be used. for (wip2 = buf->b_wininfo; wip2 != NULL; wip2 = wip2->wi_next) { - if (wip2->wi_win == NULL) { + // `wip2 != wip` to satisfy Coverity. #14884 + if (wip2 != wip && wip2->wi_win == NULL) { if (wip2->wi_next != NULL) { wip2->wi_next->wi_prev = wip2->wi_prev; } diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 34ab90d760..c4745e636f 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -348,6 +348,12 @@ describe('jobs', function() eq(false, pcall(function() nvim('command', 'call jobsend(j, ["some data"])') end)) + + command("let g:job_opts.stdin = 'null'") + nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") + eq(false, pcall(function() + nvim('command', 'call jobsend(j, ["some data"])') + end)) end) it('disallows jobsend on a non-existent job', function() diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua index 0f2d77093a..d86caca0e9 100644 --- a/test/functional/legacy/memory_usage_spec.lua +++ b/test/functional/legacy/memory_usage_spec.lua @@ -168,6 +168,9 @@ describe('memory usage', function() end) it('releases memory when closing windows when folds exist', function() + if helpers.is_os('mac') then + pending('macOS memory compression causes flakiness') + end local pid = eval('getpid()') source([[ new diff --git a/test/unit/undo_spec.lua b/test/unit/undo_spec.lua index 616c6fbe3d..f7f8d26d58 100644 --- a/test/unit/undo_spec.lua +++ b/test/unit/undo_spec.lua @@ -38,7 +38,7 @@ child_call_once(function() -- -- compute a hash for this undofile buffer_hash = ffi.new('char_u[32]') - undo.u_compute_hash(buffer_hash) + undo.u_compute_hash(file_buffer, buffer_hash) end) diff --git a/third-party/cmake/DownloadAndExtractFile.cmake b/third-party/cmake/DownloadAndExtractFile.cmake index e008fa8a8a..abb1ddc81a 100644 --- a/third-party/cmake/DownloadAndExtractFile.cmake +++ b/third-party/cmake/DownloadAndExtractFile.cmake @@ -59,41 +59,48 @@ string(REPLACE ";" "-" fname "${fname}") set(file ${DOWNLOAD_DIR}/${fname}) message(STATUS "file: ${file}") -message(STATUS "downloading... - src='${URL}' - dst='${file}' - timeout='${timeout_msg}'") - -file(DOWNLOAD ${URL} ${file} - ${timeout_args} - ${hash_args} - STATUS status - LOG log) - -list(GET status 0 status_code) -list(GET status 1 status_string) - -if(NOT status_code EQUAL 0) - # Retry on certain errors, e.g. CURLE_COULDNT_RESOLVE_HOST, which is often - # seen with libtermkey (www.leonerd.org.uk). - if((status_code EQUAL 6) # "Couldn't resolve host name" - OR (status_code EQUAL 7)) # "Couldn't connect to server" - message(STATUS "warning: retrying '${URL}' (${status_string}, status ${status_code})") - execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10) - file(DOWNLOAD ${URL} ${file} - ${timeout_args} - ${hash_args} - STATUS status - LOG log) - list(GET status 0 status_code) - list(GET status 1 status_string) - endif() +set(EXISTING_SHA256 "") +if(EXISTS ${file}) + file(SHA256 ${file} EXISTING_SHA256) +endif() + +if(NOT EXISTING_SHA256 STREQUAL ${EXPECTED_SHA256}) + message(STATUS "downloading... + src='${URL}' + dst='${file}' + timeout='${timeout_msg}'") + + file(DOWNLOAD ${URL} ${file} + ${timeout_args} + ${hash_args} + STATUS status + LOG log) + + list(GET status 0 status_code) + list(GET status 1 status_string) + if(NOT status_code EQUAL 0) - message(FATAL_ERROR "error: downloading '${URL}' failed - status_code: ${status_code} - status_string: ${status_string} - log: ${log} -") + # Retry on certain errors, e.g. CURLE_COULDNT_RESOLVE_HOST, which is often + # seen with libtermkey (www.leonerd.org.uk). + if((status_code EQUAL 6) # "Couldn't resolve host name" + OR (status_code EQUAL 7)) # "Couldn't connect to server" + message(STATUS "warning: retrying '${URL}' (${status_string}, status ${status_code})") + execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10) + file(DOWNLOAD ${URL} ${file} + ${timeout_args} + ${hash_args} + STATUS status + LOG log) + list(GET status 0 status_code) + list(GET status 1 status_string) + endif() + if(NOT status_code EQUAL 0) + message(FATAL_ERROR "error: downloading '${URL}' failed + status_code: ${status_code} + status_string: ${status_string} + log: ${log} + ") + endif() endif() endif() |