diff options
83 files changed, 1385 insertions, 1185 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index ae30f00f31..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: Bug report -about: Report a problem in Nvim -title: '' -labels: bug - ---- - -<!-- Before reporting: search existing issues and check the FAQ. --> - -- `nvim --version`: -- Operating system/version: -- Terminal name/version: -- `$TERM`: - -<!-- -If this report is about different behaviour between Nvim and Vim, make sure to -read `:h vim-differences` first. Otherwise remove the next line. ---> -[ ] `vim -u DEFAULTS` (version: ) behaves differently - -### Steps to reproduce using `nvim -u NORC` - -``` -nvim -u NORC -# Alternative for shell-related problems: -# env -i TERM=ansi-256color "$(which nvim)" - -``` - -### Actual behaviour - -### Expected behaviour - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..474fce0167 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,60 @@ +name: Bug Report +description: Report a problem in Neovim +labels: [bug] +body: + + - type: markdown + attributes: + value: | + Before reporting: search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). + + - type: input + attributes: + label: "Neovim Version" + description: "`nvim --version`:" + validations: + required: true + - type: input + attributes: + label: "Operating system/version:" + validations: + required: true + - type: input + attributes: + label: "Terminal name/version:" + validations: + required: true + - type: input + attributes: + label: "TERM environment variable" + description: "echo `$TERM`:" + validations: + required: true + + - type: input + attributes: + label: "Installation" + description: "How did you install neovim: build from repo / system package manager / appimage / homebrew / snap / chocolatey / other (please specify)?" + placeholder: "Arch User Repository (AUR)" + validations: + required: true + + - type: textarea + attributes: + label: "Steps to reproduce" + description: | + Steps to reproduce using `nvim -u NORC` and/or `nvim -u NONE` (please test both). + If you are reporting build failures, please list the exact sequence of steps including all CMake flags (if any). + + - type: input + attributes: + label: "Vim" + description: "Does Vim behave differently when called with `vim -u DEFAULTS`? If yes, which version of Vim are you using (`vim --version`):" + + - type: textarea + attributes: + label: "Expected behavior" + description: "A description of the behavior you expected. May optionally include logs, images, or videos." + - type: textarea + attributes: + label: "Actual behavior" diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 928cde894c..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Feature request -about: Request an enhancement for Nvim -title: '' -labels: enhancement - ---- - -<!-- Before reporting: search existing issues and check the FAQ. --> - -- `nvim --version`: -- `vim -u DEFAULTS` (version: ) behaves differently? -- Operating system/version: -- Terminal name/version: -- `$TERM`: - -### Steps to reproduce using `nvim -u NORC` - -``` -nvim -u NORC - -``` - -### Actual behaviour - -### Expected behaviour - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000..a9ed2824cb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,20 @@ +name: Feature request +description: Request an enhancement for Neovim +labels: [enhancement] +body: + + - type: markdown + attributes: + value: | + Before requesting: search [existing issues](https://github.com/neovim/neovim/labels/enhancement) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). + + - type: input + attributes: + label: "Feature already in Vim?" + description: "Does the feature already exist in Vim? If possible, please specify which version of Vim it was introduced in." + + - type: textarea + attributes: + label: "Feature description" + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/lsp_bug_report.md b/.github/ISSUE_TEMPLATE/lsp_bug_report.md deleted file mode 100644 index d2488a14e8..0000000000 --- a/.github/ISSUE_TEMPLATE/lsp_bug_report.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: Language server client bug report -about: Report a built-in lsp problem in Nvim -title: '' -labels: bug, lsp - ---- - -<!-- -Before reporting: search existing issues and check the FAQ. Usage questions -such as "How do I...?" or "Why isn't X language server/feature working?" belong -on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will -be closed. ---> - -- `nvim --version`: -- language server name/version: -- Operating system/version: - -<details> -<summary>nvim -c ":checkhealth nvim lspconfig"</summary> - -<!-- Paste the results from `nvim -c ":checkhealth nvim lspconfig"` here. --> - -</details> - -<details> -<summary>lsp.log</summary> - -<!-- -Please paste the lsp log before and after the problem. - -You can set log level like this. -`:lua vim.lsp.set_log_level("debug")` - -You can find the location of the log with the following command. -`:lua print(vim.lsp.get_log_path())` ---> - -</details> - -### Steps to reproduce using nvim -u minimal_init.lua -<!-- - Note, if the issue is with an autocompletion or other LSP plugin, please - report to the upstream tracker. Download the minmal config with - wget https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua - and modify it to include any specific commands or servers pertaining to your issues. ---> - - -``` -nvim -u minimal_init.lua -``` - -### Actual behaviour - -### Expected behaviour - diff --git a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml new file mode 100644 index 0000000000..ba1905329b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml @@ -0,0 +1,69 @@ +name: Language server client bug report +description: Report a built-in lsp problem in Neovim +labels: [bug, lsp] +body: + + - type: markdown + attributes: + value: | + Before reporting: search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage questions such as "How do I...?" or "Why isn't X language server/feature working?" belong on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will be closed. + + - type: input + attributes: + label: "Neovim Version" + description: "`nvim --version`:" + validations: + required: true + - type: input + attributes: + label: "Language server name/version:" + validations: + required: true + - type: input + attributes: + label: "Operating system/version:" + validations: + required: true + + - type: textarea + attributes: + label: Checkhealth + description: | + Paste the results from `nvim -c ":checkhealth nvim lspconfig"` here: + render: markdown + + - type: markdown + attributes: + value: | + Note: if the issue is with an autocompletion or other LSP plugin, please report it at that plugin's issue tracker. Download the minimal config with `wget https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua` and modify it to include any specific commands or servers pertaining to your issues. + - type: textarea + attributes: + label: "Steps to reproduce" + description: | + Steps to reproduce using `nvim -u minimal_init.lua`: + validations: + required: true + + - type: textarea + attributes: + label: "Expected behavior" + description: "A description of the behavior you expected. May optionally include logs, images, or videos." + - type: textarea + attributes: + label: "Actual behavior" + + - type: markdown + attributes: + value: | + Please upload `lsp.log` before and after the problem in a [secret gist](https://gist.github.com/). Paste the url to the gist in the text field below. + + You can set the log level by adding the Lua command + `vim.lsp.set_log_level("debug")` + after setting up LSP in your config. + + You can find the location of the log with the command + `:lua print(vim.lsp.get_log_path())` + + - type: input + attributes: + label: "Link to uploaded log file" diff --git a/.github/labeler.yml b/.github/labeler.yml index 282c6b1e7c..2de3904314 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -17,33 +17,33 @@ "dependencies": - third-party/**/* -"topic: spell": +"spell": - src/nvim/spell* -"topic: :terminal": +"terminal": - src/nvim/terminal.* -"topic: column": +"column": - src/nvim/mark.h - src/nvim/mark.c - src/nvim/sign* -"topic: folds": +"folds": - src/nvim/fold* -"topic: mouse": +"mouse": - src/nvim/mouse* -"topic: documentation": +"documentation": - runtime/doc/* -"topic: clipboard": +"clipboard": - runtime/autoload/provider/clipboard.vim -"topic: diff": +"diff": - src/nvim/diff.* -"topic: build": +"build": - CMakeLists.txt - "**/CMakeLists.txt" - "**/*.cmake" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca850c577b..3b89730434 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,7 @@ jobs: runner: ubuntu-20.04 os: linux runs-on: ${{ matrix.runner }} + timeout-minutes: 45 if: github.event.pull_request.draft == false env: CC: ${{ matrix.cc }} @@ -64,8 +65,6 @@ jobs: # Workaround brew issues rm -f /usr/local/bin/2to3 brew update >/dev/null - # remove broken mongodb-community package - brew remove mongodb-community brew upgrade brew install automake ccache perl cpanminus ninja diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 909e197b57..67ad4c0552 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -1,6 +1,7 @@ name: "Pull Request Labeler" on: -- pull_request_target + pull_request_target: + types: opened jobs: triage: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 163140c6e1..e07ce4906e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ compile_commands.json /tmp/ /.clangd/ /.cache/clangd/ +/.ccls-cache/ .DS_Store *.mo diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 8c360b1778..83e10d649d 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2203,9 +2203,11 @@ getbufline({expr}, {lnum} [, {end}]) getbufvar({expr}, {varname} [, {def}]) any variable {varname} in buffer {expr} getchangelist({expr}) List list of change list items -getchar([expr]) Number get one character from the user +getchar([expr]) Number or String + get one character from the user getcharmod() Number modifiers for the last typed character getcharsearch() Dict last character search +getcharstr([expr]) String get one character from the user getcmdline() String return the current command-line getcmdpos() Number return cursor position in command-line getcmdtype() String return current command-line type @@ -4308,6 +4310,7 @@ getchar([expr]) *getchar()* Return zero otherwise. If [expr] is 1, only check if a character is available, it is not consumed. Return zero if no character available. + If you prefer always getting a string use |getcharstr()|. Without [expr] and when [expr] is 0 a whole character or special key is returned. If it is a single character, the @@ -4399,6 +4402,20 @@ getcharsearch() *getcharsearch()* :nnoremap <expr> , getcharsearch().forward ? ',' : ';' < Also see |setcharsearch()|. + +getcharstr([expr]) *getcharstr()* + Get a single character from the user or input stream as a + string. + If [expr] is omitted, wait until a character is available. + If [expr] is 0 or false, only get a character when one is + available. Return an empty string otherwise. + If [expr] is 1 or true, only check if a character is + available, it is not consumed. Return an empty string + if no character is available. + Otherwise this works like |getchar()|, except that a number + result is converted to a string. + + getcmdline() *getcmdline()* Return the current command-line. Only works when the command line is being edited, thus requires use of |c_CTRL-\_e| or @@ -6350,6 +6367,10 @@ mode([expr]) Return a string that indicates the current mode. s Select by character S Select by line CTRL-S Select blockwise + vs Visual by character using |v_CTRL-O| from + Select mode + Vs Visual by line using |v_CTRL-O| from Select mode + CTRL-Vs Visual blockwise using |v_CTRL-O| from Select mode i Insert ic Insert mode completion |compl-generic| ix Insert mode |i_CTRL-X| completion @@ -6358,8 +6379,7 @@ mode([expr]) Return a string that indicates the current mode. Rv Virtual Replace |gR| Rx Replace mode |i_CTRL-X| completion c Command-line editing - cv Vim Ex mode |gQ| - ce Normal Ex mode |Q| + cv Vim Ex mode |Q| or |gQ| r Hit-enter prompt rm The -- more -- prompt r? |:confirm| query of some sort diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index dacc0c4138..7daab4d6f1 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -322,6 +322,18 @@ To configure the behavior of a builtin |lsp-handler|, the convenient method } } < + Some handlers do not have an explicitly named handler function (such as + |on_publish_diagnostics()|). To override these, first create a reference + to the existing handler: > + + local on_references = vim.lsp.handlers["textDocument/references"] + vim.lsp.handlers["textDocument/references"] = vim.lsp.with( + on_references, { + -- Use location list instead of quickfix list + loclist = true, + } + ) +< *lsp-handler-resolution* Handlers can be set by: @@ -816,109 +828,117 @@ start_client({config}) *vim.lsp.start_client()* table. Parameters: ~ - {root_dir} (required, string) Directory where the - LSP server will base its rootUri on - initialization. - {cmd} (required, string or list treated like - |jobstart()|) Base command that - initiates the LSP client. - {cmd_cwd} (string, default=|getcwd()|) Directory - to launch the `cmd` process. Not - related to `root_dir` . - {cmd_env} (table) Environment flags to pass to - the LSP on spawn. Can be specified - using keys like a map or as a list with `k=v` pairs or both. Non-string values are - coerced to string. Example: > + {root_dir} (required, string) Directory where + the LSP server will base its rootUri + on initialization. + {cmd} (required, string or list treated + like |jobstart()|) Base command that + initiates the LSP client. + {cmd_cwd} (string, default=|getcwd()|) + Directory to launch the `cmd` + process. Not related to `root_dir` . + {cmd_env} (table) Environment flags to pass to + the LSP on spawn. Can be specified + using keys like a map or as a list + with `k=v` pairs or both. Non-string values are + coerced to string. Example: > { "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; } < - {capabilities} Map overriding the default capabilities - defined by - |vim.lsp.protocol.make_client_capabilities()|, - passed to the language server on - initialization. Hint: use - make_client_capabilities() and modify - its result. - • Note: To send an empty dictionary use - `{[vim.type_idx]=vim.types.dictionary}` - , else it will be encoded as an - array. - {handlers} Map of language server method names to - |lsp-handler| - {settings} Map with language server specific - settings. These are returned to the - language server if requested via - `workspace/configuration` . Keys are - case-sensitive. - {init_options} Values to pass in the initialization - request as `initializationOptions` . - See `initialize` in the LSP spec. - {name} (string, default=client-id) Name in log - messages. - {get_language_id} function(bufnr, filetype) -> language - ID as string. Defaults to the filetype. - {offset_encoding} (default="utf-16") One of "utf-8", - "utf-16", or "utf-32" which is the - encoding that the LSP server expects. - Client does not verify this is correct. - {on_error} Callback with parameters (code, ...), - invoked when the client operation - throws an error. `code` is a number - describing the error. Other arguments - may be passed depending on the error - kind. See |vim.lsp.client_errors| for - possible errors. Use - `vim.lsp.client_errors[code]` to get - human-friendly name. - {before_init} Callback with parameters - (initialize_params, config) invoked - before the LSP "initialize" phase, - where `params` contains the parameters - being sent to the server and `config` - is the config that was passed to - |vim.lsp.start_client()|. You can use - this to modify parameters before they - are sent. - {on_init} Callback (client, initialize_result) - invoked after LSP "initialize", where - `result` is a table of `capabilities` - and anything else the server may send. - For example, clangd sends - `initialize_result.offsetEncoding` if - `capabilities.offsetEncoding` was sent - to it. You can only modify the - `client.offset_encoding` here before - any notifications are sent. Most - language servers expect to be sent - client specified settings after - initialization. Neovim does not make - this assumption. A - `workspace/didChangeConfiguration` - notification should be sent to the - server during on_init. - {on_exit} Callback (code, signal, client_id) - invoked on client exit. - • code: exit code of the process - • signal: number describing the signal - used to terminate (if any) - • client_id: client handle - {on_attach} Callback (client, bufnr) invoked when - client attaches to a buffer. - {trace} "off" | "messages" | "verbose" | nil - passed directly to the language server - in the initialize request. - Invalid/empty values will default to - "off" - {flags} A table with flags for the client. The - current (experimental) flags are: - • allow_incremental_sync (bool, default - true): Allow using incremental sync - for buffer edits - • debounce_text_changes (number, - default nil): Debounce didChange - notifications to the server by the - given number in milliseconds. No - debounce occurs if nil + {capabilities} Map overriding the default + capabilities defined by + |vim.lsp.protocol.make_client_capabilities()|, + passed to the language server on + initialization. Hint: use + make_client_capabilities() and modify + its result. + • Note: To send an empty dictionary + use + `{[vim.type_idx]=vim.types.dictionary}` + , else it will be encoded as an + array. + {handlers} Map of language server method names + to |lsp-handler| + {settings} Map with language server specific + settings. These are returned to the + language server if requested via + `workspace/configuration` . Keys are + case-sensitive. + {init_options} Values to pass in the initialization + request as `initializationOptions` . + See `initialize` in the LSP spec. + {name} (string, default=client-id) Name in + log messages. + {workspace_folders} (table) List of workspace folders + passed to the language server. + Defaults to root_dir if not set. See + `workspaceFolders` in the LSP spec + {get_language_id} function(bufnr, filetype) -> language + ID as string. Defaults to the + filetype. + {offset_encoding} (default="utf-16") One of "utf-8", + "utf-16", or "utf-32" which is the + encoding that the LSP server expects. + Client does not verify this is + correct. + {on_error} Callback with parameters (code, ...), + invoked when the client operation + throws an error. `code` is a number + describing the error. Other arguments + may be passed depending on the error + kind. See |vim.lsp.client_errors| for + possible errors. Use + `vim.lsp.client_errors[code]` to get + human-friendly name. + {before_init} Callback with parameters + (initialize_params, config) invoked + before the LSP "initialize" phase, + where `params` contains the + parameters being sent to the server + and `config` is the config that was + passed to |vim.lsp.start_client()|. + You can use this to modify parameters + before they are sent. + {on_init} Callback (client, initialize_result) + invoked after LSP "initialize", where + `result` is a table of `capabilities` + and anything else the server may + send. For example, clangd sends + `initialize_result.offsetEncoding` if + `capabilities.offsetEncoding` was + sent to it. You can only modify the + `client.offset_encoding` here before + any notifications are sent. Most + language servers expect to be sent + client specified settings after + initialization. Neovim does not make + this assumption. A + `workspace/didChangeConfiguration` + notification should be sent to the + server during on_init. + {on_exit} Callback (code, signal, client_id) + invoked on client exit. + • code: exit code of the process + • signal: number describing the + signal used to terminate (if any) + • client_id: client handle + {on_attach} Callback (client, bufnr) invoked when + client attaches to a buffer. + {trace} "off" | "messages" | "verbose" | nil + passed directly to the language + server in the initialize request. + Invalid/empty values will default to + "off" + {flags} A table with flags for the client. + The current (experimental) flags are: + • allow_incremental_sync (bool, + default true): Allow using + incremental sync for buffer edits + • debounce_text_changes (number, + default nil): Debounce didChange + notifications to the server by the + given number in milliseconds. No + debounce occurs if nil Return: ~ Client id. |vim.lsp.get_client_by_id()| Note: client may @@ -1188,6 +1208,34 @@ workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()* ============================================================================== Lua module: vim.lsp.diagnostic *lsp-diagnostic* + *vim.lsp.diagnostic.apply_to_diagnostic_items()* +apply_to_diagnostic_items({item_handler}, {command}, {opts}) + Gets diagnostics, converts them to quickfix/location list + items, and applies the item_handler callback to the items. + + Parameters: ~ + {item_handler} function Callback to apply to the + diagnostic items + {command} string|nil Command to execute after + applying the item_handler + {opts} table|nil Configuration table. Keys: + • {client_id}: (number) + • If nil, will consider all clients + attached to buffer. + + • {severity}: (DiagnosticSeverity) + • Exclusive severity to consider. + Overrides {severity_limit} + + • {severity_limit}: (DiagnosticSeverity) + • Limit severity of diagnostics found. + E.g. "Warning" means { "Error", + "Warning" } will be valid. + + • {workspace}: (boolean, default false) + • Set the list with workspace + diagnostics + *vim.lsp.diagnostic.clear()* clear({bufnr}, {client_id}, {diagnostic_ns}, {sign_ns}) Clears the currently displayed diagnostics @@ -1199,6 +1247,26 @@ clear({bufnr}, {client_id}, {diagnostic_ns}, {sign_ns}) namespace {sign_ns} number|nil Associated sign namespace +disable({bufnr}, {client_id}) *vim.lsp.diagnostic.disable()* + Disable diagnostics for the given buffer and client + + Parameters: ~ + {bufnr} (optional, number): Buffer handle, defaults + to current + {client_id} (optional, number): Disable diagnostics for + the given client. The default is to disable + diagnostics for all attached clients. + +enable({bufnr}, {client_id}) *vim.lsp.diagnostic.enable()* + Enable diagnostics for the given buffer and client + + Parameters: ~ + {bufnr} (optional, number): Buffer handle, defaults + to current + {client_id} (optional, number): Enable diagnostics for + the given client. The default is to enable + diagnostics for all attached clients. + get({bufnr}, {client_id}) *vim.lsp.diagnostic.get()* Return associated diagnostics for bufnr @@ -1419,6 +1487,22 @@ on_publish_diagnostics({_}, {_}, {params}, {client_id}, {_}, {config}) • Sort diagnostics (and thus signs and virtual text) +redraw({bufnr}, {client_id}) *vim.lsp.diagnostic.redraw()* + Redraw diagnostics for the given buffer and client + + This calls the "textDocument/publishDiagnostics" handler + manually using the cached diagnostics already received from + the server. This can be useful for redrawing diagnostics after + making changes in diagnostics configuration. + |lsp-handler-configuration| + + Parameters: ~ + {bufnr} (optional, number): Buffer handle, defaults + to current + {client_id} (optional, number): Redraw diagnostics for + the given client. The default is to redraw + diagnostics for all attached clients. + reset({client_id}, {buffer_client_map}) *vim.lsp.diagnostic.reset()* Clear diagnotics and diagnostic cache @@ -1455,7 +1539,7 @@ set_loclist({opts}) *vim.lsp.diagnostic.set_loclist()* Parameters: ~ {opts} table|nil Configuration table. Keys: - • {open_loclist}: (boolean, default true) + • {open}: (boolean, default true) • Open loclist after set • {client_id}: (number) @@ -1474,6 +1558,30 @@ set_loclist({opts}) *vim.lsp.diagnostic.set_loclist()* • {workspace}: (boolean, default false) • Set the list with workspace diagnostics +set_qflist({opts}) *vim.lsp.diagnostic.set_qflist()* + Sets the quickfix list + + Parameters: ~ + {opts} table|nil Configuration table. Keys: + • {open}: (boolean, default true) + • Open quickfix list after set + + • {client_id}: (number) + • If nil, will consider all clients attached to + buffer. + + • {severity}: (DiagnosticSeverity) + • Exclusive severity to consider. Overrides + {severity_limit} + + • {severity_limit}: (DiagnosticSeverity) + • Limit severity of diagnostics found. E.g. + "Warning" means { "Error", "Warning" } will be + valid. + + • {workspace}: (boolean, default true) + • Set the list with workspace diagnostics + *vim.lsp.diagnostic.set_signs()* set_signs({diagnostics}, {bufnr}, {client_id}, {sign_ns}, {opts}) Set signs for given diagnostics diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 6aa508956b..ab2230641d 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4539,11 +4539,6 @@ A jump table for the options with a short description can be found at |Q_op|. List of items that control the format of the output of |:hardcopy|. See |popt-option|. - *'prompt'* *'noprompt'* -'prompt' boolean (default on) - global - When on a ":" prompt is used in Ex mode. - *'pumblend'* *'pb'* 'pumblend' 'pb' number (default 0) global diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt index fb20a583c9..c19b05f6c7 100644 --- a/runtime/doc/quickref.txt +++ b/runtime/doc/quickref.txt @@ -809,7 +809,6 @@ Short explanation of each option: *option-list* 'printmbcharset' 'pmbcs' CJK character set to be used for :hardcopy 'printmbfont' 'pmbfn' font names to be used for CJK output of :hardcopy 'printoptions' 'popt' controls the format of :hardcopy output -'prompt' 'prompt' enable prompt in Ex mode 'pumheight' 'ph' maximum height of the popup menu 'pumwidth' 'pw' minimum width of the popup menu 'pythondll' name of the Python 2 dynamic library diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 6c51f37ae5..bc7a1e34c3 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -25,11 +25,15 @@ In the User Manual: ============================================================================== 1. Quick start *:syn-qstart* - *:syn-enable* *:syntax-enable* + *:syn-enable* *:syntax-enable* *:syn-on* *:syntax-on* This command switches on syntax highlighting: > :syntax enable +Alternatively: > + + :syntax on + What this command actually does is to execute the command > :source $VIMRUNTIME/syntax/syntax.vim @@ -42,19 +46,11 @@ are in the "/usr/vim/vim82/syntax" directory, set $VIMRUNTIME to This command also sources the |menu.vim| script when the GUI is running or will start soon. See |'go-M'| about avoiding that. - *:syn-on* *:syntax-on* -The `:syntax enable` command will keep most of your current color settings. -This allows using `:highlight` commands to set your preferred colors before or -after using this command. If you want Vim to overrule your settings with the -defaults, use: > - :syntax on -< *:hi-normal* *:highlight-normal* If you are running in the GUI, you can get white text on a black background with: > :highlight Normal guibg=Black guifg=White For a color terminal see |:hi-normal-cterm|. -For setting up your own colors syntax highlighting see |syncolor|. NOTE: The syntax files on MS-Windows have lines that end in <CR><NL>. The files for Unix end in <NL>. This means you should use the right type of @@ -277,12 +273,6 @@ located. This is used here as the variable |$VIMRUNTIME|. | +- Source first syntax/synload.vim in 'runtimepath' | | - | +- Setup the colors for syntax highlighting. If a color scheme is - | | defined it is loaded again with ":colors {name}". Otherwise - | | ":runtime! syntax/syncolor.vim" is used. ":syntax on" overrules - | | existing colors, ":syntax enable" only sets groups that weren't - | | set yet. - | | | +- Set up syntax autocmds to load the appropriate syntax file when | | the 'syntax' option is set. *synload-1* | | @@ -5271,51 +5261,10 @@ back to their Vim default. Note that if you are using a color scheme, the colors defined by the color scheme for syntax highlighting will be lost. -What this actually does is: > - - let g:syntax_cmd = "reset" - runtime! syntax/syncolor.vim - -Note that this uses the 'runtimepath' option. - - *syncolor* -If you want to use different colors for syntax highlighting, you can add a Vim -script file to set these colors. Put this file in a directory in -'runtimepath' which comes after $VIMRUNTIME, so that your settings overrule -the default colors. This way these colors will be used after the ":syntax -reset" command. - -For Unix you can use the file ~/.config/nvim/after/syntax/syncolor.vim. -Example: > - - if &background == "light" - highlight comment ctermfg=darkgreen guifg=darkgreen - else - highlight comment ctermfg=green guifg=green - endif - - *E679* -Do make sure this syncolor.vim script does not use a "syntax on", set the -'background' option or uses a "colorscheme" command, because it results in an -endless loop. - Note that when a color scheme is used, there might be some confusion whether your defined colors are to be used or the colors from the scheme. This depends on the color scheme file. See |:colorscheme|. - *syntax_cmd* -The "syntax_cmd" variable is set to one of these values when the -syntax/syncolor.vim files are loaded: - "on" ":syntax on" command. Highlight colors are overruled but - links are kept - "enable" ":syntax enable" command. Only define colors for groups that - don't have highlighting yet. Use ":syntax default". - "reset" ":syntax reset" command or loading a color scheme. Define all - the colors. - "skip" Don't define colors. Used to skip the default settings when a - syncolor.vim file earlier in 'runtimepath' has already set - them. - ============================================================================== 16. Highlighting tags *tag-highlight* diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 416ea3a08a..80500e3c15 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -169,7 +169,7 @@ a tree, using a simple to write lisp-like format. See https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax for more information on how to write queries. -Note: The perdicates listed in the web page above differ from those Neovim +Note: The predicates listed in the web page above differ from those Neovim supports. See |lua-treesitter-predicates| for a complete list of predicates supported by Neovim. @@ -226,6 +226,18 @@ Here is a list of built-in predicates : Each predicate has a `not-` prefixed predicate that is just the negation of the predicate. + *vim.treesitter.query.add_predicate()* +vim.treesitter.query.add_predicate({name}, {handler}) + +This adds a predicate with the name {name} to be used in queries. +{handler} should be a function whose signature will be : > + handler(match, pattern, bufnr, predicate) +< + *vim.treesitter.query.list_predicates()* +vim.treesitter.query.list_predicates() + +This lists the currently available predicates to use in queries. + Treesitter Query Directive *lua-treesitter-directives* Treesitter queries can also contain `directives`. Directives store metadata for a node @@ -249,6 +261,21 @@ Here is a list of built-in directives: `({capture_id}, {start_row}, {start_col}, {end_row}, {end_col}, {key?})` The default key is "offset". + *vim.treesitter.query.add_directive()* +vim.treesitter.query.add_directive({name}, {handler}) + +This adds a directive with the name {name} to be used in queries. +{handler} should be a function whose signature will be : > + handler(match, pattern, bufnr, predicate, metadata) +Handlers can set match level data by setting directly on the metadata object `metadata.key = value` +Handlers can set node level data by using the capture id on the metadata table +`metadata[capture_id].key = value` + + *vim.treesitter.query.list_directives()* +vim.treesitter.query.list_directives() + +This lists the currently available directives to use in queries. + Treesitter syntax highlighting (WIP) *lua-treesitter-highlight* NOTE: This is a partially implemented feature, and not usable as a default @@ -294,6 +321,19 @@ identical identifiers, highlighting both as |hl-WarningMsg|: > ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right)) < +Treesitter Highlighting Priority *lua-treesitter-highlight-priority* + +Tree-sitter uses |nvim_buf_set_extmark()| to set highlights with a default +priority of 100. This enables plugins to set a highlighting priority lower or +higher than tree-sitter. It is also possible to change the priority of an +individual query pattern manually by setting its `"priority"` metadata attribute: > + + ( + (super_important_node) @ImportantHighlight + ; Give the whole query highlight priority higher than the default (100) + (set! "priority" 105) + ) +< ============================================================================== Lua module: vim.treesitter *lua-treesitter-core* @@ -393,8 +433,13 @@ get_query_files({lang}, {query_name}, {is_included}) {is_included} Internal parameter, most of the time left as `nil` +list_directives() *list_directives()* + Return: ~ + The list of supported directives. + list_predicates() *list_predicates()* - TODO: Documentation + Return: ~ + The list of supported predicates. parse_query({lang}, {query}) *parse_query()* Parse {query} as a string. (If the query is in a file, the diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 27c4b82aca..2c53620049 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -358,6 +358,14 @@ Startup: - works by default: "-" file is optional - works in more cases: |-Es|, file args +Syntax highlighting: + syncolor.vim has been removed. Nvim now sets up default highlighting groups + automatically for both light and dark backgrounds, regardless of whether or + not syntax highlighting is enabled. This means that |:syntax-on| and + |:syntax-enable| are now identical. Users who previously used an + after/syntax/syncolor.vim file should transition that file into a + colorscheme. |:colorscheme| + TUI: *:set-termcap* Start Nvim with 'verbose' level 3 to show terminal capabilities: > @@ -473,6 +481,7 @@ Options: 'maxmem' Nvim delegates memory-management to the OS. 'maxmemtot' Nvim delegates memory-management to the OS. 'maxcombine' (6 is always used) + *'prompt'* *'noprompt'* *'restorescreen'* *'rs'* *'norestorescreen'* *'nors'* 'shelltype' *'shortname'* *'sn'* *'noshortname'* *'nosn'* diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 75faf9bcc7..87ecc3eeea 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -453,15 +453,7 @@ local function text_document_did_open_handler(bufnr, client) -- Next chance we get, we should re-do the diagnostics vim.schedule(function() - vim.lsp.handlers["textDocument/publishDiagnostics"]( - nil, - "textDocument/publishDiagnostics", - { - diagnostics = vim.lsp.diagnostic.get(bufnr, client.id), - uri = vim.uri_from_bufnr(bufnr), - }, - client.id - ) + vim.lsp.diagnostic.redraw(bufnr, client.id) end) end @@ -590,6 +582,10 @@ end --- as `initializationOptions`. See `initialize` in the LSP spec. --- --@param name (string, default=client-id) Name in log messages. +-- +--@param workspace_folders (table) List of workspace folders passed to the +--- language server. Defaults to root_dir if not set. See `workspaceFolders` in +--- the LSP spec --- --@param get_language_id function(bufnr, filetype) -> language ID as string. --- Defaults to the filetype. @@ -775,6 +771,14 @@ function lsp.start_client(config) off = 'off'; messages = 'messages'; verbose = 'verbose'; } local version = vim.version() + + if not config.workspace_folders then + config.workspace_folders = {{ + uri = vim.uri_from_fname(config.root_dir); + name = string.format("%s", config.root_dir); + }}; + end + local initialize_params = { -- The process Id of the parent process that started the server. Is null if -- the process has not been started by another process. If the parent @@ -815,10 +819,7 @@ function lsp.start_client(config) -- -- workspace folder in the user interface. -- name -- } - workspaceFolders = {{ - uri = vim.uri_from_fname(config.root_dir); - name = string.format("%s", config.root_dir); - }}; + workspaceFolders = config.workspace_folders, } if config.before_init then -- TODO(ashkan) handle errors here. diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index ced1747ee0..29f8d6c3bc 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -422,6 +422,21 @@ function M.clear_references() util.buf_clear_references() end +--- Requests code actions from all clients and calls the handler exactly once +--- with all aggregated results +--@private +local function code_action_request(params) + local bufnr = vim.api.nvim_get_current_buf() + local method = 'textDocument/codeAction' + vim.lsp.buf_request_all(bufnr, method, params, function(results) + local actions = {} + for _, r in pairs(results) do + vim.list_extend(actions, r.result or {}) + end + vim.lsp.handlers[method](nil, method, actions, nil, bufnr) + end) +end + --- Selects a code action from the input list that is available at the current --- cursor position. -- @@ -432,7 +447,7 @@ function M.code_action(context) context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() } local params = util.make_range_params() params.context = context - request('textDocument/codeAction', params) + code_action_request(params) end --- Performs |vim.lsp.buf.code_action()| for a given range. @@ -447,7 +462,7 @@ function M.range_code_action(context, start_pos, end_pos) context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() } local params = util.make_given_range_params(start_pos, end_pos) params.context = context - request('textDocument/codeAction', params) + code_action_request(params) end --- Executes an LSP server command. diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 1342df529f..120320becc 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -208,6 +208,9 @@ local diagnostic_cache_lines = setmetatable({}, bufnr_and_client_cacher_mt) local diagnostic_cache_counts = setmetatable({}, bufnr_and_client_cacher_mt) local diagnostic_attached_buffers = {} +-- Disabled buffers and clients +local diagnostic_disabled = setmetatable({}, bufnr_and_client_cacher_mt) + local _bufs_waiting_to_update = setmetatable({}, bufnr_and_client_cacher_mt) --- Store Diagnostic[] by line @@ -816,10 +819,7 @@ end ---@param diagnostic_ns number|nil Associated diagnostic namespace ---@param sign_ns number|nil Associated sign namespace function M.clear(bufnr, client_id, diagnostic_ns, sign_ns) - validate { bufnr = { bufnr, 'n' } } - - bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr - + bufnr = get_bufnr(bufnr) if client_id == nil then return vim.lsp.for_each_buffer_client(bufnr, function(_, iter_client_id, _) return M.clear(bufnr, iter_client_id) @@ -1092,6 +1092,10 @@ end --@private --- Display diagnostics for the buffer, given a configuration. function M.display(diagnostics, bufnr, client_id, config) + if diagnostic_disabled[bufnr][client_id] then + return + end + config = vim.lsp._with_extend('vim.lsp.diagnostic.on_publish_diagnostics', { signs = true, underline = true, @@ -1164,6 +1168,40 @@ function M.display(diagnostics, bufnr, client_id, config) save_extmarks(bufnr, client_id) end +--- Redraw diagnostics for the given buffer and client +--- +--- This calls the "textDocument/publishDiagnostics" handler manually using +--- the cached diagnostics already received from the server. This can be useful +--- for redrawing diagnostics after making changes in diagnostics +--- configuration. |lsp-handler-configuration| +--- +--- @param bufnr (optional, number): Buffer handle, defaults to current +--- @param client_id (optional, number): Redraw diagnostics for the given +--- client. The default is to redraw diagnostics for all attached +--- clients. +function M.redraw(bufnr, client_id) + bufnr = get_bufnr(bufnr) + if not client_id then + return vim.lsp.for_each_buffer_client(bufnr, function(client) + M.redraw(bufnr, client.id) + end) + end + + -- We need to invoke the publishDiagnostics handler directly instead of just + -- calling M.display so that we can preserve any custom configuration options + -- the user may have set with vim.lsp.with. + vim.lsp.handlers["textDocument/publishDiagnostics"]( + nil, + "textDocument/publishDiagnostics", + { + uri = vim.uri_from_bufnr(bufnr), + diagnostics = M.get(bufnr, client_id), + }, + client_id, + bufnr + ) +end + -- }}} -- Diagnostic User Functions {{{ @@ -1245,10 +1283,10 @@ function M.reset(client_id, buffer_client_map) end) end ---- Sets the location list +--- Gets diagnostics, converts them to quickfix/location list items, and applies the item_handler callback to the items. +---@param item_handler function Callback to apply to the diagnostic items +---@param command string|nil Command to execute after applying the item_handler ---@param opts table|nil Configuration table. Keys: ---- - {open_loclist}: (boolean, default true) ---- - Open loclist after set --- - {client_id}: (number) --- - If nil, will consider all clients attached to buffer. --- - {severity}: (DiagnosticSeverity) @@ -1257,9 +1295,8 @@ end --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. --- - {workspace}: (boolean, default false) --- - Set the list with workspace diagnostics -function M.set_loclist(opts) +local function apply_to_diagnostic_items(item_handler, command, opts) opts = opts or {} - local open_loclist = if_nil(opts.open_loclist, true) local current_bufnr = api.nvim_get_current_buf() local diags = opts.workspace and M.get_all(opts.client_id) or { [current_bufnr] = M.get(current_bufnr, opts.client_id) @@ -1276,11 +1313,89 @@ function M.set_loclist(opts) return true end local items = util.diagnostics_to_items(diags, predicate) - local win_id = vim.api.nvim_get_current_win() - util.set_loclist(items, win_id) - if open_loclist then - vim.cmd [[lopen]] + item_handler(items) + if command then + vim.cmd(command) + end +end + +--- Sets the quickfix list +---@param opts table|nil Configuration table. Keys: +--- - {open}: (boolean, default true) +--- - Open quickfix list after set +--- - {client_id}: (number) +--- - If nil, will consider all clients attached to buffer. +--- - {severity}: (DiagnosticSeverity) +--- - Exclusive severity to consider. Overrides {severity_limit} +--- - {severity_limit}: (DiagnosticSeverity) +--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. +--- - {workspace}: (boolean, default true) +--- - Set the list with workspace diagnostics +function M.set_qflist(opts) + opts = opts or {} + opts.workspace = if_nil(opts.workspace, true) + local open_qflist = if_nil(opts.open, true) + local command = open_qflist and [[copen]] or nil + apply_to_diagnostic_items(util.set_qflist, command, opts) +end + +--- Sets the location list +---@param opts table|nil Configuration table. Keys: +--- - {open}: (boolean, default true) +--- - Open loclist after set +--- - {client_id}: (number) +--- - If nil, will consider all clients attached to buffer. +--- - {severity}: (DiagnosticSeverity) +--- - Exclusive severity to consider. Overrides {severity_limit} +--- - {severity_limit}: (DiagnosticSeverity) +--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. +--- - {workspace}: (boolean, default false) +--- - Set the list with workspace diagnostics +function M.set_loclist(opts) + opts = opts or {} + local open_loclist = if_nil(opts.open, true) + local command = open_loclist and [[lopen]] or nil + apply_to_diagnostic_items(util.set_loclist, command, opts) +end + +--- Disable diagnostics for the given buffer and client +--- @param bufnr (optional, number): Buffer handle, defaults to current +--- @param client_id (optional, number): Disable diagnostics for the given +--- client. The default is to disable diagnostics for all attached +--- clients. +-- Note that when diagnostics are disabled for a buffer, the server will still +-- send diagnostic information and the client will still process it. The +-- diagnostics are simply not displayed to the user. +function M.disable(bufnr, client_id) + if not client_id then + return vim.lsp.for_each_buffer_client(bufnr, function(client) + M.disable(bufnr, client.id) + end) end + + diagnostic_disabled[bufnr][client_id] = true + M.clear(bufnr, client_id) +end + +--- Enable diagnostics for the given buffer and client +--- @param bufnr (optional, number): Buffer handle, defaults to current +--- @param client_id (optional, number): Enable diagnostics for the given +--- client. The default is to enable diagnostics for all attached +--- clients. +function M.enable(bufnr, client_id) + if not client_id then + return vim.lsp.for_each_buffer_client(bufnr, function(client) + M.enable(bufnr, client.id) + end) + end + + if not diagnostic_disabled[bufnr][client_id] then + return + end + + diagnostic_disabled[bufnr][client_id] = nil + + M.redraw(bufnr, client_id) end -- }}} diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index acd20a3e0b..a77c88e2dc 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -190,30 +190,41 @@ end --@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) +--- Return a function that converts LSP responses to list items and opens the list +--- +--- The returned function has an optional {config} parameter that accepts a table +--- with the following keys: +--- +--- loclist: (boolean) use the location list (default is to use the quickfix list) +--- +--- @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_list(map_result, entity) + return function(_, _, result, _, bufnr, config) 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") + config = config or {} + if config.loclist then + util.set_loclist(map_result(result, bufnr)) + api.nvim_command("lopen") + else + util.set_qflist(map_result(result, bufnr)) + api.nvim_command("copen") + end 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') +M['textDocument/references'] = response_to_list(util.locations_to_items, 'references') --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol -M['textDocument/documentSymbol'] = response_to_qflist(util.symbols_to_items, 'document symbols') +M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'document symbols') --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol -M['workspace/symbol'] = response_to_qflist(util.symbols_to_items, 'symbols') +M['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols') --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename M['textDocument/rename'] = function(_, _, result) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 1ea974dffa..dc15d67e1c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -990,6 +990,7 @@ function M.make_floating_popup_options(width, height, opts) style = 'minimal', width = width, border = opts.border or default_border, + zindex = opts.zindex or 50, } end diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 0a663628a5..33c2b2c46c 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -200,6 +200,12 @@ function vim.tbl_isempty(t) return next(t) == nil end +--- we only merge empty tables or tables that are not a list +--@private +local function can_merge(v) + return type(v) == "table" and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) +end + local function tbl_extend(behavior, deep_extend, ...) if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then error('invalid "behavior": '..tostring(behavior)) @@ -219,8 +225,8 @@ local function tbl_extend(behavior, deep_extend, ...) vim.validate{["after the second argument"] = {tbl,'t'}} if tbl then for k, v in pairs(tbl) do - if type(v) == 'table' and deep_extend and not vim.tbl_islist(v) then - ret[k] = tbl_extend(behavior, true, ret[k] or vim.empty_dict(), v) + if deep_extend and can_merge(v) and can_merge(ret[k]) then + ret[k] = tbl_extend(behavior, true, ret[k], v) elseif behavior ~= 'force' and ret[k] ~= nil then if behavior == 'error' then error('key found in more than one map: '..k) diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 84b6a5f135..cf3cdf4505 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -248,7 +248,7 @@ local function on_line_impl(self, buf, line) end while line >= state.next_row do - local capture, node = state.iter() + local capture, node, metadata = state.iter() if capture == nil then break end @@ -260,7 +260,7 @@ local function on_line_impl(self, buf, line) { end_line = end_row, end_col = end_col, hl_group = hl, ephemeral = true, - priority = 100 -- Low but leaves room below + priority = tonumber(metadata.priority) or 100 -- Low but leaves room below }) end if start_row > line then diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index b81eb18945..4ecd91d295 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -351,7 +351,12 @@ function M.add_directive(name, handler, force) directive_handlers[name] = handler end ---- Returns the list of currently supported predicates +--- @return The list of supported directives. +function M.list_directives() + return vim.tbl_keys(directive_handlers) +end + +--- @return The list of supported predicates. function M.list_predicates() return vim.tbl_keys(predicate_handlers) end diff --git a/runtime/syntax/syncolor.vim b/runtime/syntax/syncolor.vim deleted file mode 100644 index 5b907a3b83..0000000000 --- a/runtime/syntax/syncolor.vim +++ /dev/null @@ -1,87 +0,0 @@ -" Vim syntax support file -" Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2020 Feb 13 - -" This file sets up the default methods for highlighting. -" It is loaded from "synload.vim" and from Vim for ":syntax reset". -" Also used from init_highlight(). - -if !exists("syntax_cmd") || syntax_cmd == "on" - " ":syntax on" works like in Vim 5.7: set colors but keep links - command -nargs=* SynColor hi <args> - command -nargs=* SynLink hi link <args> -else - if syntax_cmd == "enable" - " ":syntax enable" keeps any existing colors - command -nargs=* SynColor hi def <args> - command -nargs=* SynLink hi def link <args> - elseif syntax_cmd == "reset" - " ":syntax reset" resets all colors to the default - command -nargs=* SynColor hi <args> - command -nargs=* SynLink hi! link <args> - else - " User defined syncolor file has already set the colors. - finish - endif -endif - -" Many terminals can only use six different colors (plus black and white). -" Therefore the number of colors used is kept low. It doesn't look nice with -" too many colors anyway. -" Careful with "cterm=bold", it changes the color to bright for some terminals. -" There are two sets of defaults: for a dark and a light background. -if &background == "dark" - SynColor Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#80a0ff guibg=NONE - SynColor Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE gui=NONE guifg=#ffa0a0 guibg=NONE - SynColor Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE gui=NONE guifg=Orange guibg=NONE - SynColor Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#40ffff guibg=NONE - SynColor Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE gui=bold guifg=#ffff60 guibg=NONE - SynColor PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE gui=NONE guifg=#ff80ff guibg=NONE - SynColor Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE gui=bold guifg=#60ff60 guibg=NONE - SynColor Underlined term=underline cterm=underline ctermfg=LightBlue gui=underline guifg=#80a0ff - SynColor Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE gui=NONE guifg=bg guibg=NONE -else - SynColor Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE gui=NONE guifg=Blue guibg=NONE - SynColor Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE gui=NONE guifg=Magenta guibg=NONE - " #6a5acd is SlateBlue - SynColor Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a5acd guibg=NONE - SynColor Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE gui=NONE guifg=DarkCyan guibg=NONE - SynColor Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE gui=bold guifg=Brown guibg=NONE - " #6a0dad is Purple - SynColor PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a0dad guibg=NONE - SynColor Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE gui=bold guifg=SeaGreen guibg=NONE - SynColor Underlined term=underline cterm=underline ctermfg=DarkMagenta gui=underline guifg=SlateBlue - SynColor Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE gui=NONE guifg=bg guibg=NONE -endif -SynColor Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE guifg=White guibg=Red -SynColor Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE guifg=Blue guibg=Yellow - -" Common groups that link to default highlighting. -" You can specify other highlighting easily. -SynLink String Constant -SynLink Character Constant -SynLink Number Constant -SynLink Boolean Constant -SynLink Float Number -SynLink Function Identifier -SynLink Conditional Statement -SynLink Repeat Statement -SynLink Label Statement -SynLink Operator Statement -SynLink Keyword Statement -SynLink Exception Statement -SynLink Include PreProc -SynLink Define PreProc -SynLink Macro PreProc -SynLink PreCondit PreProc -SynLink StorageClass Type -SynLink Structure Type -SynLink Typedef Type -SynLink Tag Special -SynLink SpecialChar Special -SynLink Delimiter Special -SynLink SpecialComment Special -SynLink Debug Special - -delcommand SynColor -delcommand SynLink diff --git a/runtime/syntax/synload.vim b/runtime/syntax/synload.vim index 3863a84c1a..bfcd3b06da 100644 --- a/runtime/syntax/synload.vim +++ b/runtime/syntax/synload.vim @@ -14,13 +14,6 @@ endif " let others know that syntax has been switched on let syntax_on = 1 -" Set the default highlighting colors. Use a color scheme if specified. -if exists("colors_name") - exe "colors " . colors_name -else - runtime! syntax/syncolor.vim -endif - " Line continuation is used here, remove 'C' from 'cpoptions' let s:cpo_save = &cpo set cpo&vim diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index f3371b485e..aa27c94f29 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -379,7 +379,7 @@ run_analysis() {( --sourcetree-root . || true rm -rf PVS-studio.{xml,err,tsk,html.d} - local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011" + local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011,V1042" plog-converter $plog_args --renderTypes xml --output PVS-studio.xml plog-converter $plog_args --renderTypes errorfile --output PVS-studio.err plog-converter $plog_args --renderTypes tasklist --output PVS-studio.tsk diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index b371c08d2a..77cff0cb4f 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -315,7 +315,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id, } rv.size = (size_t)(end - start); - rv.items = xcalloc(sizeof(Object), rv.size); + rv.items = xcalloc(rv.size, sizeof(Object)); if (!buf_collect_lines(buf, rv.size, start, (channel_id != VIML_INTERNAL_CALL), &rv, err)) { @@ -1433,8 +1433,14 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, /// - hl_group : name of the highlight group used to highlight /// this mark. /// - virt_text : virtual text to link to this mark. -/// - virt_text_pos : positioning of virtual text. Possible -/// values: +/// A list of [text, highlight] tuples, each representing a +/// text chunk with specified highlight. `highlight` element +/// can either be a a single highlight group, or an array of +/// multiple highlight groups that will be stacked +/// (highest priority last). A highlight group can be supplied +/// either as a string or as an integer, the latter which +/// can be obtained using |nvim_get_hl_id_by_name|. +/// - virt_text_pos : position of virtual text. Possible values: /// - "eol": right after eol character (default) /// - "overlay": display over the specified column, without /// shifting the underlying text. @@ -1560,7 +1566,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, "virt_text is not an Array"); goto error; } - decor.virt_text = parse_virt_text(v->data.array, err); + decor.virt_text = parse_virt_text(v->data.array, err, + &decor.virt_text_width); if (ERROR_SET(err)) { goto error; } @@ -1892,80 +1899,6 @@ void nvim_buf_clear_namespace(Buffer buffer, (int)line_end-1, MAXCOL); } -/// Set the virtual text (annotation) for a buffer line. -/// -/// By default (and currently the only option) the text will be placed after -/// the buffer text. Virtual text will never cause reflow, rather virtual -/// text will be truncated at the end of the screen line. The virtual text will -/// begin one cell (|lcs-eol| or space) after the ordinary text. -/// -/// Namespaces are used to support batch deletion/updating of virtual text. -/// To create a namespace, use |nvim_create_namespace()|. Virtual text is -/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for -/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both -/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If -/// the virtual text never will be cleared by an API call, pass `ns_id = -1`. -/// -/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the -/// virtual text, the allocated id is then returned. -/// -/// @param buffer Buffer handle, or 0 for current buffer -/// @param ns_id Namespace to use or 0 to create a namespace, -/// or -1 for a ungrouped annotation -/// @param line Line to annotate with virtual text (zero-indexed) -/// @param chunks A list of [text, hl_group] arrays, each representing a -/// text chunk with specified highlight. `hl_group` element -/// can be omitted for no highlight. -/// @param opts Optional parameters. Currently not used. -/// @param[out] err Error details, if any -/// @return The ns_id that was used -Integer nvim_buf_set_virtual_text(Buffer buffer, - Integer src_id, - Integer line, - Array chunks, - Dictionary opts, - Error *err) - FUNC_API_SINCE(5) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - if (!buf) { - return 0; - } - - if (line < 0 || line >= MAXLNUM) { - api_set_error(err, kErrorTypeValidation, "Line number outside range"); - return 0; - } - - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); - return 0; - } - - uint64_t ns_id = src2ns(&src_id); - - VirtText virt_text = parse_virt_text(chunks, err); - if (ERROR_SET(err)) { - return 0; - } - - - VirtText *existing = decor_find_virttext(buf, (int)line, ns_id); - - if (existing) { - clear_virttext(existing); - *existing = virt_text; - return src_id; - } - - Decoration *decor = xcalloc(1, sizeof(*decor)); - decor->virt_text = virt_text; - - extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true, - false, kExtmarkNoUndo); - return src_id; -} - /// call a function with buffer as temporary current buffer /// /// This temporarily switches current buffer to "buffer". diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 3989386bb9..554966e266 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -12,6 +12,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" #include "nvim/lua/executor.h" +#include "nvim/extmark.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/deprecated.c.generated.h" @@ -80,6 +81,87 @@ void nvim_buf_clear_highlight(Buffer buffer, } +/// Set the virtual text (annotation) for a buffer line. +/// +/// @deprecated use nvim_buf_set_extmark to use full virtual text +/// functionality. +/// +/// The text will be placed after the buffer text. Virtual text will never +/// cause reflow, rather virtual text will be truncated at the end of the screen +/// line. The virtual text will begin one cell (|lcs-eol| or space) after the +/// ordinary text. +/// +/// Namespaces are used to support batch deletion/updating of virtual text. +/// To create a namespace, use |nvim_create_namespace()|. Virtual text is +/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for +/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both +/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If +/// the virtual text never will be cleared by an API call, pass `ns_id = -1`. +/// +/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the +/// virtual text, the allocated id is then returned. +/// +/// @param buffer Buffer handle, or 0 for current buffer +/// @param ns_id Namespace to use or 0 to create a namespace, +/// or -1 for a ungrouped annotation +/// @param line Line to annotate with virtual text (zero-indexed) +/// @param chunks A list of [text, hl_group] arrays, each representing a +/// text chunk with specified highlight. `hl_group` element +/// can be omitted for no highlight. +/// @param opts Optional parameters. Currently not used. +/// @param[out] err Error details, if any +/// @return The ns_id that was used +Integer nvim_buf_set_virtual_text(Buffer buffer, + Integer src_id, + Integer line, + Array chunks, + Dictionary opts, + Error *err) + FUNC_API_SINCE(5) + FUNC_API_DEPRECATED_SINCE(8) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + if (!buf) { + return 0; + } + + if (line < 0 || line >= MAXLNUM) { + api_set_error(err, kErrorTypeValidation, "Line number outside range"); + return 0; + } + + if (opts.size > 0) { + api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + return 0; + } + + uint64_t ns_id = src2ns(&src_id); + int width; + + VirtText virt_text = parse_virt_text(chunks, err, &width); + if (ERROR_SET(err)) { + return 0; + } + + + Decoration *existing = decor_find_virttext(buf, (int)line, ns_id); + + if (existing) { + clear_virttext(&existing->virt_text); + existing->virt_text = virt_text; + existing->virt_text_width = width; + return src_id; + } + + Decoration *decor = xcalloc(1, sizeof(*decor)); + decor->virt_text = virt_text; + decor->virt_text_width = width; + + extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true, + false, kExtmarkNoUndo); + return src_id; +} + /// Inserts a sequence of lines to a buffer at a certain index /// /// @deprecated use nvim_buf_set_lines(buffer, lnum, lnum, true, lines) diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 9f2e94f31e..5a8c5de35c 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1592,9 +1592,10 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int } } -VirtText parse_virt_text(Array chunks, Error *err) +VirtText parse_virt_text(Array chunks, Error *err, int *width) { VirtText virt_text = KV_INITIAL_VALUE; + int w = 0; for (size_t i = 0; i < chunks.size; i++) { if (chunks.items[i].type != kObjectTypeArray) { api_set_error(err, kErrorTypeValidation, "Chunk is not an array"); @@ -1603,25 +1604,44 @@ VirtText parse_virt_text(Array chunks, Error *err) Array chunk = chunks.items[i].data.array; if (chunk.size == 0 || chunk.size > 2 || chunk.items[0].type != kObjectTypeString - || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) { + || chunk.size > 2) { api_set_error(err, kErrorTypeValidation, "Chunk is not an array with one or two strings"); goto free_exit; } String str = chunk.items[0].data.string; - char *text = transstr(str.size > 0 ? str.data : ""); // allocates int hl_id = 0; if (chunk.size == 2) { - String hl = chunk.items[1].data.string; - if (hl.size > 0) { - hl_id = syn_check_group((char_u *)hl.data, (int)hl.size); + Object hl = chunk.items[1]; + if (hl.type == kObjectTypeArray) { + Array arr = hl.data.array; + for (size_t j = 0; j < arr.size; j++) { + hl_id = object_to_hl_id(arr.items[j], "virt_text highlight", err); + if (ERROR_SET(err)) { + goto free_exit; + } + if (j < arr.size-1) { + kv_push(virt_text, ((VirtTextChunk){ .text = NULL, + .hl_id = hl_id })); + } + } + } else { + hl_id = object_to_hl_id(hl, "virt_text highlight", err); + if (ERROR_SET(err)) { + goto free_exit; + } } } + + char *text = transstr(str.size > 0 ? str.data : ""); // allocates + w += (int)mb_string2cells((char_u *)text); + kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id })); } + *width = w; return virt_text; free_exit: @@ -1656,7 +1676,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err) String str = obj.data.string; return str.size ? syn_check_group((char_u *)str.data, (int)str.size) : 0; } else if (obj.type == kObjectTypeInteger) { - return (int)obj.data.integer; + return MAX((int)obj.data.integer, 0); } else { api_set_error(err, kErrorTypeValidation, "%s is not a valid highlight", what); @@ -1687,6 +1707,7 @@ HlMessage parse_hl_msg(Array chunks, Error *err) if (chunk.size == 2) { String hl = chunk.items[1].data.string; if (hl.size > 0) { + // TODO(bfredl): use object_to_hl_id and allow integer int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size); attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9b0782f589..bbcfe173c5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1696,7 +1696,7 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, FUNC_API_SINCE(6) FUNC_API_CHECK_TEXTLOCK { - yankreg_T *reg = xcalloc(sizeof(yankreg_T), 1); + yankreg_T *reg = xcalloc(1, sizeof(yankreg_T)); if (!prepare_yankreg_from_object(reg, type, lines.size)) { api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data); goto cleanup; diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 3b4fc6c3df..587ef74b35 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -540,12 +540,10 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last) del_buf = true; } - /* - * Free all things allocated for this buffer. - * Also calls the "BufDelete" autocommands when del_buf is TRUE. - */ - /* Remember if we are closing the current buffer. Restore the number of - * windows, so that autocommands in buf_freeall() don't get confused. */ + // Free all things allocated for this buffer. + // Also calls the "BufDelete" autocommands when del_buf is true. + // Remember if we are closing the current buffer. Restore the number of + // windows, so that autocommands in buf_freeall() don't get confused. bool is_curbuf = (buf == curbuf); // When closing the current buffer stop Visual mode before freeing @@ -5046,8 +5044,8 @@ do_arg_all( xfree(opened); } -// Return TRUE if "buf" is a prompt buffer. -int bt_prompt(buf_T *buf) +/// @return true if "buf" is a prompt buffer. +bool bt_prompt(buf_T *buf) { return buf != NULL && buf->b_p_bt[0] == 'p'; } diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c index f46cac4637..1d131cc4b1 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -50,7 +50,7 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id, if (send_buffer) { Array args = ARRAY_DICT_INIT; args.size = 6; - args.items = xcalloc(sizeof(Object), args.size); + args.items = xcalloc(args.size, sizeof(Object)); // the first argument is always the buffer handle args.items[0] = BUFFER_OBJ(buf->handle); @@ -68,7 +68,7 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id, if (line_count >= 1) { linedata.size = line_count; - linedata.items = xcalloc(sizeof(Object), line_count); + linedata.items = xcalloc(line_count, sizeof(Object)); buf_collect_lines(buf, line_count, 1, true, &linedata, NULL); } @@ -93,7 +93,7 @@ void buf_updates_send_end(buf_T *buf, uint64_t channelid) { Array args = ARRAY_DICT_INIT; args.size = 1; - args.items = xcalloc(sizeof(Object), args.size); + args.items = xcalloc(args.size, sizeof(Object)); args.items[0] = BUFFER_OBJ(buf->handle); rpc_send_event(channelid, "nvim_buf_detach_event", args); } @@ -211,7 +211,7 @@ void buf_updates_send_changes(buf_T *buf, // send through the changes now channel contents now Array args = ARRAY_DICT_INIT; args.size = 6; - args.items = xcalloc(sizeof(Object), args.size); + args.items = xcalloc(args.size, sizeof(Object)); // the first argument is always the buffer handle args.items[0] = BUFFER_OBJ(buf->handle); @@ -230,7 +230,7 @@ void buf_updates_send_changes(buf_T *buf, if (num_added > 0) { STATIC_ASSERT(SIZE_MAX >= MAXLNUM, "size_t smaller than MAXLNUM"); linedata.size = (size_t)num_added; - linedata.items = xcalloc(sizeof(Object), (size_t)num_added); + linedata.items = xcalloc((size_t)num_added, sizeof(Object)); buf_collect_lines(buf, (size_t)num_added, firstline, true, &linedata, NULL); } @@ -394,7 +394,7 @@ void buf_updates_changedtick_single(buf_T *buf, uint64_t channel_id) { Array args = ARRAY_DICT_INIT; args.size = 2; - args.items = xcalloc(sizeof(Object), args.size); + args.items = xcalloc(args.size, sizeof(Object)); // the first argument is always the buffer handle args.items[0] = BUFFER_OBJ(buf->handle); diff --git a/src/nvim/change.c b/src/nvim/change.c index ca1ca756bb..b30490deca 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -779,7 +779,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) int movelen = oldlen - col - count + 1; // includes trailing NUL if (movelen <= 1) { // If we just took off the last character of a non-blank line, and - // fixpos is TRUE, we don't want to end up positioned at the NUL, + // fixpos is true, we don't want to end up positioned at the NUL, // unless "restart_edit" is set or 'virtualedit' contains "onemore". if (col > 0 && fixpos && restart_edit == 0 && (ve_flags & VE_ONEMORE) == 0 diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 9d969ada89..74cb9a26b7 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -119,7 +119,7 @@ void clear_virttext(VirtText *text) *text = (VirtText)KV_INITIAL_VALUE; } -VirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id) +Decoration *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id) { MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, row, 0, itr); @@ -132,7 +132,7 @@ VirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id) mark.id, false); if (item && (ns_id == 0 || ns_id == item->ns_id) && item->decor && kv_size(item->decor->virt_text)) { - return &item->decor->virt_text; + return item->decor; } marktree_itr_next(buf->b_marktree, itr); } @@ -218,6 +218,7 @@ bool decor_redraw_line(buf_T *buf, int row, DecorState *state) } state->row = row; state->col_until = -1; + state->eol_col = -1; return true; // TODO(bfredl): be more precise } @@ -230,10 +231,6 @@ static void decor_add(DecorState *state, int start_row, int start_col, *decor, attr_id, kv_size(decor->virt_text) && owned, -1 }; - if (decor->virt_text_pos == kVTEndOfLine) { - range.win_col = -2; // handled separately - } - kv_pushp(state->active); size_t index; for (index = kv_size(state->active)-1; index > 0; index--) { @@ -345,29 +342,22 @@ void decor_redraw_end(DecorState *state) state->buf = NULL; } -VirtText decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr, - bool *aligned) +bool decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr, int eol_col) { decor_redraw_col(buf, MAXCOL, MAXCOL, false, state); - VirtText text = VIRTTEXT_EMPTY; + state->eol_col = eol_col; + bool has_virttext = false; for (size_t i = 0; i < kv_size(state->active); i++) { DecorRange item = kv_A(state->active, i); if (item.start_row == state->row && kv_size(item.decor.virt_text)) { - if (!kv_size(text) && item.decor.virt_text_pos == kVTEndOfLine) { - text = item.decor.virt_text; - } else if (item.decor.virt_text_pos == kVTRightAlign - || item.decor.virt_text_pos == kVTWinCol) { - *aligned = true; - } + has_virttext = true; } - if (item.decor.hl_eol && item.start_row <= state->row) { *eol_attr = hl_combine_attr(*eol_attr, item.attr_id); } } - - return text; + return has_virttext; } void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col, diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 4cebc0b731..28dabeeada 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -34,19 +34,20 @@ typedef enum { struct Decoration { - int hl_id; // highlight group VirtText virt_text; + int hl_id; // highlight group VirtTextPos virt_text_pos; - bool virt_text_hide; HlMode hl_mode; + bool virt_text_hide; bool hl_eol; + bool shared; // shared decoration, don't free // TODO(bfredl): style, signs, etc DecorPriority priority; - bool shared; // shared decoration, don't free int col; // fixed col value, like win_col + int virt_text_width; // width of virt_text }; -#define DECORATION_INIT { 0, KV_INITIAL_VALUE, kVTEndOfLine, false, \ - kHlModeUnknown, false, DECOR_PRIORITY_BASE, false, 0 } +#define DECORATION_INIT { KV_INITIAL_VALUE, 0, kVTEndOfLine, kHlModeUnknown, \ + false, false, false, DECOR_PRIORITY_BASE, 0, 0 } typedef struct { int start_row; @@ -67,6 +68,8 @@ typedef struct { int row; int col_until; int current; + + int eol_col; VirtText *virt_text; } DecorState; diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index dd32cef1e3..07e484c178 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1502,10 +1502,10 @@ char_u *get_digraph_for_char(int val_arg) /// Get a digraph. Used after typing CTRL-K on the command line or in normal /// mode. /// -/// @param cmdline TRUE when called from the cmdline +/// @param cmdline true when called from the cmdline /// /// @returns composed character, or NUL when ESC was used. -int get_digraph(int cmdline) +int get_digraph(bool cmdline) { int cc; no_mapping++; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 33c6fae5cf..eb20cd1bc8 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -136,6 +136,7 @@ return { getchar={args={0, 1}}, getcharmod={}, getcharsearch={}, + getcharstr={args={0, 1}}, getcmdline={}, getcmdpos={}, getcmdtype={}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8960cac9c5..f4735b3751 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -1922,7 +1922,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (expr_start != NULL && !aborting()) { EMSG2(_(e_invexpr2), expr_start); } - need_clr_eos = FALSE; + need_clr_eos = false; rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; } else if (*s != NUL) { @@ -3028,10 +3028,9 @@ static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } -/* - * "getchar()" function - */ -static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +// "getchar()" and "getcharstr()" functions +static void getchar_common(typval_T *argvars, typval_T *rettv) + FUNC_ATTR_NONNULL_ALL { varnumber_T n; bool error = false; @@ -3098,6 +3097,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else { i += utf_char2bytes(n, temp + i); } + assert(i < 10); temp[i++] = NUL; rettv->v_type = VAR_STRING; rettv->vval.v_string = vim_strsave(temp); @@ -3106,15 +3106,14 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) int row = mouse_row; int col = mouse_col; int grid = mouse_grid; - win_T *win; linenr_T lnum; win_T *wp; int winnr = 1; if (row >= 0 && col >= 0) { - /* Find the window at the mouse coordinates and compute the - * text position. */ - win = mouse_find_win(&grid, &row, &col); + // Find the window at the mouse coordinates and compute the + // text position. + win_T *const win = mouse_find_win(&grid, &row, &col); if (win == NULL) { return; } @@ -3130,6 +3129,32 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +// "getchar()" function +static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + getchar_common(argvars, rettv); +} + +// "getcharstr()" function +static void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + getchar_common(argvars, rettv); + + if (rettv->v_type == VAR_NUMBER) { + char_u temp[7]; // mbyte-char: 6, NUL: 1 + const varnumber_T n = rettv->vval.v_number; + int i = 0; + + if (n != 0) { + i += utf_char2bytes(n, temp); + } + assert(i < 7); + temp[i++] = NUL; + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strsave(temp); + } +} + /* * "getcharmod()" function */ diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 0e7d7c2dc2..dc096bdb93 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2887,7 +2887,6 @@ void ex_append(exarg_T *eap) } else if (lnum > 0) indent = get_indent_lnum(lnum); } - ex_keep_indent = FALSE; if (eap->getline == NULL) { /* No getline() function, use the lines that follow. This ends * when there is no more. */ @@ -2915,10 +2914,6 @@ void ex_append(exarg_T *eap) if (theline == NULL) break; - /* Using ^ CTRL-D in getexmodeline() makes us repeat the indent. */ - if (ex_keep_indent) - append_indent = indent; - /* Look for the "." after automatic indent. */ vcol = 0; for (p = theline; indent > vcol; ++p) { @@ -3751,6 +3746,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, */ while (subflags.do_ask) { if (exmode_active) { + char *prompt; char_u *resp; colnr_T sc, ec; @@ -3767,13 +3763,14 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, sc += numw; ec += numw; } - msg_start(); - for (i = 0; i < (long)sc; ++i) - msg_putchar(' '); - for (; i <= (long)ec; ++i) - msg_putchar('^'); - resp = getexmodeline('?', NULL, 0, true); + prompt = xmallocz(ec + 1); + memset(prompt, ' ', sc); + memset(prompt + sc, '^', ec - sc + 1); + resp = (char_u *)getcmdline_prompt(NUL, prompt, 0, EXPAND_NOTHING, + NULL, CALLBACK_NONE); + msg_putchar('\n'); + xfree(prompt); if (resp != NULL) { typed = *resp; xfree(resp); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 83472fe146..c83c19fc35 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -186,17 +186,14 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp) } /// Repeatedly get commands for Ex mode, until the ":vi" command is given. -void do_exmode(int improved) +void do_exmode(void) { int save_msg_scroll; int prev_msg_row; linenr_T prev_line; int changedtick; - if (improved) - exmode_active = EXMODE_VIM; - else - exmode_active = EXMODE_NORMAL; + exmode_active = true; State = NORMAL; /* When using ":global /pat/ visual" and then "Q" we return to continue @@ -212,7 +209,7 @@ void do_exmode(int improved) while (exmode_active) { /* Check for a ":normal" command and no more characters left. */ if (ex_normal_busy > 0 && typebuf.tb_len == 0) { - exmode_active = 0; + exmode_active = false; break; } msg_scroll = true; @@ -565,7 +562,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, && (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) { store_loop_line(&lines_ga, next_cmdline); } - did_endif = FALSE; + did_endif = false; if (count++ == 0) { /* @@ -750,8 +747,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, * the :endtry to be missed. */ && (cstack.cs_trylevel == 0 || did_emsg_syntax) && used_getline - && (getline_equal(fgetline, cookie, getexmodeline) - || getline_equal(fgetline, cookie, getexline))) + && getline_equal(fgetline, cookie, getexline)) && (next_cmdline != NULL || cstack.cs_idx >= 0 || (flags & DOCMD_REPEAT))); @@ -944,7 +940,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, } } - did_endif = FALSE; /* in case do_cmdline used recursively */ + did_endif = false; // in case do_cmdline used recursively call_depth--; end_batch_changes(); @@ -2056,8 +2052,7 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only) // in ex mode, an empty line works like :+ if (*eap->cmd == NUL && exmode_active - && (getline_equal(eap->getline, eap->cookie, getexmodeline) - || getline_equal(eap->getline, eap->cookie, getexline)) + && getline_equal(eap->getline, eap->cookie, getexline) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { eap->cmd = (char_u *)"+"; if (!skip_only) { @@ -7303,7 +7298,7 @@ do_exedit( */ if (exmode_active && (eap->cmdidx == CMD_visual || eap->cmdidx == CMD_view)) { - exmode_active = 0; + exmode_active = false; ex_pressedreturn = false; if (*eap->arg == NUL) { /* Special case: ":global/pat/visual\NLvi-commands" */ @@ -7491,7 +7486,7 @@ static void ex_syncbind(exarg_T *eap) curwin = save_curwin; curbuf = save_curbuf; if (curwin->w_p_scb) { - did_syncbind = TRUE; + did_syncbind = true; checkpcmark(); if (old_linenr != curwin->w_cursor.lnum) { char_u ctrl_o[2]; diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h index f6bd2adcd5..c8c5a0a3e2 100644 --- a/src/nvim/ex_docmd.h +++ b/src/nvim/ex_docmd.h @@ -16,10 +16,6 @@ #define VALID_PATH 1 #define VALID_HEAD 2 -/* Values for exmode_active (0 is no exmode) */ -#define EXMODE_NORMAL 1 -#define EXMODE_VIM 2 - // Structure used to save the current state. Used when executing Normal mode // commands while in any other mode. typedef struct { diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 3c765e5d02..1ceccac2bb 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -832,24 +832,23 @@ void ex_if(exarg_T *eap) */ void ex_endif(exarg_T *eap) { - did_endif = TRUE; + did_endif = true; if (eap->cstack->cs_idx < 0 || (eap->cstack->cs_flags[eap->cstack->cs_idx] - & (CSF_WHILE | CSF_FOR | CSF_TRY))) + & (CSF_WHILE | CSF_FOR | CSF_TRY))) { eap->errmsg = (char_u *)N_("E580: :endif without :if"); - else { - /* - * When debugging or a breakpoint was encountered, display the debug - * prompt (if not already done). This shows the user that an ":endif" - * is executed when the ":if" or a previous ":elseif" was not TRUE. - * Handle a ">quit" debug command as if an interrupt had occurred before - * the ":endif". That is, throw an interrupt exception if appropriate. - * Doing this here prevents an exception for a parsing error being - * discarded by throwing the interrupt exception later on. - */ + } else { + // When debugging or a breakpoint was encountered, display the debug + // prompt (if not already done). This shows the user that an ":endif" + // is executed when the ":if" or a previous ":elseif" was not TRUE. + // Handle a ">quit" debug command as if an interrupt had occurred before + // the ":endif". That is, throw an interrupt exception if appropriate. + // Doing this here prevents an exception for a parsing error being + // discarded by throwing the interrupt exception later on. if (!(eap->cstack->cs_flags[eap->cstack->cs_idx] & CSF_TRUE) - && dbg_check_skipped(eap)) + && dbg_check_skipped(eap)) { (void)do_intthrow(eap->cstack); + } --eap->cstack->cs_idx; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 4ebd384ae0..855f71ca28 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2510,266 +2510,6 @@ getexline( return getcmdline(c, 1L, indent, do_concat); } -/* - * Get an Ex command line for Ex mode. - * In Ex mode we only use the OS supplied line editing features and no - * mappings or abbreviations. - * Returns a string in allocated memory or NULL. - */ -char_u * -getexmodeline( - int promptc, // normally ':', NUL for ":append" and '?' - // for :s prompt - void *cookie, - int indent, // indent for inside conditionals - bool do_concat -) -{ - garray_T line_ga; - char_u *pend; - int startcol = 0; - int c1 = 0; - int escaped = FALSE; /* CTRL-V typed */ - int vcol = 0; - char_u *p; - int prev_char; - int len; - - /* always start in column 0; write a newline if necessary */ - compute_cmdrow(); - if ((msg_col || msg_didout) && promptc != '?') - msg_putchar('\n'); - if (promptc == ':') { - /* indent that is only displayed, not in the line itself */ - if (p_prompt) - msg_putchar(':'); - while (indent-- > 0) - msg_putchar(' '); - startcol = msg_col; - } - - ga_init(&line_ga, 1, 30); - - /* autoindent for :insert and :append is in the line itself */ - if (promptc <= 0) { - vcol = indent; - while (indent >= 8) { - ga_append(&line_ga, TAB); - msg_puts(" "); - indent -= 8; - } - while (indent-- > 0) { - ga_append(&line_ga, ' '); - msg_putchar(' '); - } - } - no_mapping++; - - /* - * Get the line, one character at a time. - */ - got_int = FALSE; - while (!got_int) { - ga_grow(&line_ga, 40); - - /* Get one character at a time. Don't use inchar(), it can't handle - * special characters. */ - prev_char = c1; - - // Check for a ":normal" command and no more characters left. - if (ex_normal_busy > 0 && typebuf.tb_len == 0) { - c1 = '\n'; - } else { - c1 = vgetc(); - } - - /* - * Handle line editing. - * Previously this was left to the system, putting the terminal in - * cooked mode, but then CTRL-D and CTRL-T can't be used properly. - */ - if (got_int) { - msg_putchar('\n'); - break; - } - - if (!escaped) { - /* CR typed means "enter", which is NL */ - if (c1 == '\r') - c1 = '\n'; - - if (c1 == BS || c1 == K_BS || c1 == DEL || c1 == K_DEL || c1 == K_KDEL) { - if (!GA_EMPTY(&line_ga)) { - p = (char_u *)line_ga.ga_data; - p[line_ga.ga_len] = NUL; - len = utf_head_off(p, p + line_ga.ga_len - 1) + 1; - line_ga.ga_len -= len; - goto redraw; - } - continue; - } - - if (c1 == Ctrl_U) { - msg_col = startcol; - msg_clr_eos(); - line_ga.ga_len = 0; - goto redraw; - } - - int num_spaces; - if (c1 == Ctrl_T) { - int sw = get_sw_value(curbuf); - - p = (char_u *)line_ga.ga_data; - p[line_ga.ga_len] = NUL; - indent = get_indent_str(p, 8, FALSE); - num_spaces = sw - indent % sw; -add_indent: - if (num_spaces > 0) { - ga_grow(&line_ga, num_spaces + 1); - p = (char_u *)line_ga.ga_data; - char_u *s = skipwhite(p); - - // Insert spaces after leading whitespaces. - long move_len = line_ga.ga_len - (s - p) + 1; - assert(move_len >= 0); - memmove(s + num_spaces, s, (size_t)move_len); - memset(s, ' ', (size_t)num_spaces); - - line_ga.ga_len += num_spaces; - } -redraw: - /* redraw the line */ - msg_col = startcol; - vcol = 0; - p = (char_u *)line_ga.ga_data; - p[line_ga.ga_len] = NUL; - while (p < (char_u *)line_ga.ga_data + line_ga.ga_len) { - if (*p == TAB) { - do { - msg_putchar(' '); - } while (++vcol % 8); - p++; - } else { - len = utfc_ptr2len(p); - msg_outtrans_len(p, len); - vcol += ptr2cells(p); - p += len; - } - } - msg_clr_eos(); - cmd_cursor_goto(msg_row, msg_col); - continue; - } - - if (c1 == Ctrl_D) { - /* Delete one shiftwidth. */ - p = (char_u *)line_ga.ga_data; - if (prev_char == '0' || prev_char == '^') { - if (prev_char == '^') - ex_keep_indent = TRUE; - indent = 0; - p[--line_ga.ga_len] = NUL; - } else { - p[line_ga.ga_len] = NUL; - indent = get_indent_str(p, 8, FALSE); - if (indent == 0) { - continue; - } - --indent; - indent -= indent % get_sw_value(curbuf); - } - - // reduce the line's indentation - char_u *from = skipwhite(p); - char_u *to = from; - int old_indent; - while ((old_indent = get_indent_str(p, 8, FALSE)) > indent) { - *--to = NUL; - } - long move_len = line_ga.ga_len - (from - p) + 1; - assert(move_len > 0); - memmove(to, from, (size_t)move_len); - line_ga.ga_len -= (int)(from - to); - - // Removed to much indentation, fix it before redrawing. - num_spaces = indent - old_indent; - goto add_indent; - } - - if (c1 == Ctrl_V || c1 == Ctrl_Q) { - escaped = TRUE; - continue; - } - - if (IS_SPECIAL(c1)) { - // Ignore other special key codes - continue; - } - } - - if (IS_SPECIAL(c1)) { - c1 = '?'; - } - len = utf_char2bytes(c1, (char_u *)line_ga.ga_data + line_ga.ga_len); - if (c1 == '\n') { - msg_putchar('\n'); - } else if (c1 == TAB) { - // Don't use chartabsize(), 'ts' can be different. - do { - msg_putchar(' '); - } while (++vcol % 8); - } else { - msg_outtrans_len(((char_u *)line_ga.ga_data) + line_ga.ga_len, len); - vcol += char2cells(c1); - } - line_ga.ga_len += len; - escaped = FALSE; - - cmd_cursor_goto(msg_row, msg_col); - pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len; - - /* We are done when a NL is entered, but not when it comes after an - * odd number of backslashes, that results in a NUL. */ - if (!GA_EMPTY(&line_ga) && pend[-1] == '\n') { - int bcount = 0; - - while (line_ga.ga_len - 2 >= bcount && pend[-2 - bcount] == '\\') - ++bcount; - - if (bcount > 0) { - /* Halve the number of backslashes: "\NL" -> "NUL", "\\NL" -> - * "\NL", etc. */ - line_ga.ga_len -= (bcount + 1) / 2; - pend -= (bcount + 1) / 2; - pend[-1] = '\n'; - } - - if ((bcount & 1) == 0) { - --line_ga.ga_len; - --pend; - *pend = NUL; - break; - } - } - } - - no_mapping--; - - /* make following messages go to the next line */ - msg_didout = FALSE; - msg_col = 0; - if (msg_row < Rows - 1) { - msg_row++; - } - emsg_on_display = false; // don't want os_delay() - - if (got_int) - ga_clear(&line_ga); - - return (char_u *)line_ga.ga_data; -} - bool cmdline_overstrike(void) { return ccline.overstrike; @@ -6469,7 +6209,7 @@ static int open_cmdwin(void) char_u typestr[2]; int save_restart_edit = restart_edit; int save_State = State; - int save_exmode = exmode_active; + bool save_exmode = exmode_active; int save_cmdmsg_rl = cmdmsg_rl; /* Can't do this recursively. Can't do it when typing a password. */ @@ -6563,7 +6303,7 @@ static int open_cmdwin(void) save_cmdline(&save_ccline); // No Ex mode here! - exmode_active = 0; + exmode_active = false; State = NORMAL; setmouse(); diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 60b7b024f1..4b2dccd8a4 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -268,7 +268,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, } ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns; map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id); - map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark.id); + map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, start_id); marktree_del_itr(buf->b_marktree, itr, false); } else { marktree_itr_next(buf->b_marktree, itr); diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index ecea3fc01e..9b89a4dd38 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -292,8 +292,8 @@ readfile( * display the line. */ ex_no_reprint = TRUE; - /* don't display the file info for another buffer now */ - need_fileinfo = FALSE; + // don't display the file info for another buffer now + need_fileinfo = false; // For Unix: Use the short file name whenever possible. // Avoids problems with networks and when directory names are changed. diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 538ebf7978..b0d06b7a30 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2230,20 +2230,22 @@ static int vgetorpeek(bool advance) timedout = true; continue; } - /* When 'insertmode' is set, ESC just beeps in Insert - * mode. Use CTRL-L to make edit() return. - * For the command line only CTRL-C always breaks it. - * For the cmdline window: Alternate between ESC and - * CTRL-C: ESC for most situations and CTRL-C to close the - * cmdline window. */ - if (p_im && (State & INSERT)) + // When 'insertmode' is set, ESC just beeps in Insert + // mode. Use CTRL-L to make edit() return. + // In Ex-mode \n is compatible with original Vim behaviour. + // For the command line only CTRL-C always breaks it. + // For the cmdline window: Alternate between ESC and + // CTRL-C: ESC for most situations and CTRL-C to close the + // cmdline window. + if (p_im && (State & INSERT)) { c = Ctrl_L; - else if ((State & CMDLINE) - || (cmdwin_type > 0 && tc == ESC) - ) + } else if (exmode_active) { + c = '\n'; + } else if ((State & CMDLINE) || (cmdwin_type > 0 && tc == ESC)) { c = Ctrl_C; - else + } else { c = ESC; + } tc = c; break; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 9fd5ccf324..7b2320effa 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -138,12 +138,12 @@ EXTERN int mod_mask INIT(= 0x0); // current key modifiers // update_screen(). EXTERN int cmdline_row; -EXTERN int redraw_cmdline INIT(= false); // cmdline must be redrawn -EXTERN int clear_cmdline INIT(= false); // cmdline must be cleared -EXTERN int mode_displayed INIT(= false); // mode is being displayed -EXTERN int cmdline_star INIT(= false); // cmdline is encrypted -EXTERN int redrawing_cmdline INIT(= false); // cmdline is being redrawn -EXTERN int cmdline_was_last_drawn INIT(= false); // cmdline was last drawn +EXTERN int redraw_cmdline INIT(= false); // cmdline must be redrawn +EXTERN int clear_cmdline INIT(= false); // cmdline must be cleared +EXTERN int mode_displayed INIT(= false); // mode is being displayed +EXTERN int cmdline_star INIT(= false); // cmdline is encrypted +EXTERN bool redrawing_cmdline INIT(= false); // cmdline is being redrawn +EXTERN bool cmdline_was_last_drawn INIT(= false); // cmdline was last drawn EXTERN int exec_from_reg INIT(= false); // executing register @@ -165,7 +165,7 @@ EXTERN int compl_interrupted INIT(= false); // Set when doing something for completion that may call edit() recursively, // which is not allowed. Also used to disable folding during completion -EXTERN int compl_busy INIT(= false); +EXTERN bool compl_busy INIT(= false); // List of flags for method of completion. EXTERN int compl_cont_status INIT(= 0); @@ -201,8 +201,8 @@ EXTERN bool msg_did_scroll INIT(= false); EXTERN char_u *keep_msg INIT(= NULL); // msg to be shown after redraw EXTERN int keep_msg_attr INIT(= 0); // highlight attr for keep_msg -EXTERN int keep_msg_more INIT(= false); // keep_msg was set by msgmore() -EXTERN int need_fileinfo INIT(= false); // do fileinfo() after redraw +EXTERN bool keep_msg_more INIT(= false); // keep_msg was set by msgmore() +EXTERN bool need_fileinfo INIT(= false); // do fileinfo() after redraw EXTERN int msg_scroll INIT(= false); // msg_start() will scroll EXTERN int msg_didout INIT(= false); // msg_outstr() was used in line EXTERN int msg_didany INIT(= false); // msg_outstr() was used at all @@ -211,13 +211,13 @@ EXTERN int emsg_off INIT(= 0); // don't display errors for now, // unless 'debug' is set. EXTERN int info_message INIT(= false); // printing informative message EXTERN bool msg_hist_off INIT(= false); // don't add messages to history -EXTERN int need_clr_eos INIT(= false); // need to clear text before +EXTERN bool need_clr_eos INIT(= false); // need to clear text before // displaying a message. EXTERN int emsg_skip INIT(= 0); // don't display errors for // expression that is skipped EXTERN bool emsg_severe INIT(= false); // use message of next of several // emsg() calls for throw -EXTERN int did_endif INIT(= false); // just had ":endif" +EXTERN bool did_endif INIT(= false); // just had ":endif" EXTERN dict_T vimvardict; // Dictionary with v: variables EXTERN dict_T globvardict; // Dictionary with g: variables /// g: value @@ -234,16 +234,15 @@ EXTERN int rc_did_emsg INIT(= false); // vim_regcomp() called emsg() EXTERN int no_wait_return INIT(= 0); // don't wait for return for now EXTERN int need_wait_return INIT(= 0); // need to wait for return later -EXTERN int did_wait_return INIT(= false); // wait_return() was used and +EXTERN bool did_wait_return INIT(= false); // wait_return() was used and // nothing written since then -EXTERN int need_maketitle INIT(= true); // call maketitle() soon +EXTERN bool need_maketitle INIT(= true); // call maketitle() soon EXTERN int quit_more INIT(= false); // 'q' hit at "--more--" msg -EXTERN int ex_keep_indent INIT(= false); // getexmodeline(): keep indent EXTERN int vgetc_busy INIT(= 0); // when inside vgetc() then > 0 -EXTERN int didset_vim INIT(= false); // did set $VIM ourselves -EXTERN int didset_vimruntime INIT(= false); // idem for $VIMRUNTIME +EXTERN bool didset_vim INIT(= false); // did set $VIM ourselves +EXTERN bool didset_vimruntime INIT(= false); // idem for $VIMRUNTIME /// Lines left before a "more" message. Ex mode needs to be able to reset this /// after you type something. @@ -369,7 +368,7 @@ EXTERN colnr_T search_match_endcol; // col nr of match end EXTERN linenr_T search_first_line INIT(= 0); // for :{FIRST},{last}s/pat EXTERN linenr_T search_last_line INIT(= MAXLNUM); // for :{first},{LAST}s/pat -EXTERN int no_smartcase INIT(= false); // don't use 'smartcase' once +EXTERN bool no_smartcase INIT(= false); // don't use 'smartcase' once EXTERN int need_check_timestamps INIT(= false); // need to check file // timestamps asap @@ -525,6 +524,8 @@ EXTERN pos_T VIsual; EXTERN int VIsual_active INIT(= false); /// Whether Select mode is active. EXTERN int VIsual_select INIT(= false); +/// Restart Select mode when next cmd finished +EXTERN int restart_VIsual_select INIT(= 0); /// Whether to restart the selection after a Select-mode mapping or menu. EXTERN int VIsual_reselect; /// Type of Visual mode. @@ -556,7 +557,7 @@ EXTERN int end_comment_pending INIT(= NUL); // know that it should not attempt to perform scrollbinding due to the scroll // that was a result of the ":syncbind." (Otherwise, check_scrollbind() will // undo some of the work done by ":syncbind.") -ralston -EXTERN int did_syncbind INIT(= false); +EXTERN bool did_syncbind INIT(= false); // This flag is set when a smart indent has been performed. When the next typed // character is a '{' the inserted tab will be deleted again. @@ -621,7 +622,7 @@ EXTERN long opcount INIT(= 0); // count for pending operator EXTERN int motion_force INIT(=0); // motion force for pending operator // Ex Mode (Q) state -EXTERN int exmode_active INIT(= 0); // Zero, EXMODE_NORMAL or EXMODE_VIM. +EXTERN bool exmode_active INIT(= false); // true if Ex mode is active EXTERN int ex_no_reprint INIT(=false); // No need to print after z or p. EXTERN int reg_recording INIT(= 0); // register for recording or zero @@ -643,7 +644,7 @@ EXTERN int arrow_used; // Normally false, set to true after EXTERN bool ins_at_eol INIT(= false); // put cursor after eol when // restarting edit after CTRL-O -EXTERN int no_abbr INIT(= true); // true when no abbreviations loaded +EXTERN bool no_abbr INIT(= true); // true when no abbreviations loaded EXTERN int mapped_ctrl_c INIT(= 0); // Modes where CTRL-C is mapped. @@ -663,7 +664,7 @@ EXTERN bool cmd_silent INIT(= false); // don't echo the command line EXTERN int swap_exists_action INIT(= SEA_NONE); // For dialog when swap file already // exists. -EXTERN int swap_exists_did_quit INIT(= false); +EXTERN bool swap_exists_did_quit INIT(= false); // Selected "quit" at the dialog. EXTERN char_u IObuff[IOSIZE]; ///< Buffer for sprintf, I/O, etc. @@ -732,7 +733,7 @@ EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline EXTERN char_u *autocmd_fname INIT(= NULL); // fname for <afile> on cmdline EXTERN int autocmd_bufnr INIT(= 0); // fnum for <abuf> on cmdline EXTERN char_u *autocmd_match INIT(= NULL); // name for <amatch> on cmdline -EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd +EXTERN bool did_cursorhold INIT(= false); // set when CursorHold t'gerd EXTERN int postponed_split INIT(= 0); // for CTRL-W CTRL-] command EXTERN int postponed_split_flags INIT(= 0); // args for win_split() diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 79e474fa2e..29ee7aae56 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -46,7 +46,7 @@ void highlight_init(void) .id1 = 0, .id2 = 0 })); } -/// @return TRUE if hl table was reset +/// @return true if hl table was reset bool highlight_use_hlstate(void) { if (hlstate_active) { diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 8fa61515ef..c1f9c1e172 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -62,10 +62,10 @@ int get_indent_buf(buf_T *buf, linenr_T lnum) } -// Count the size (in window cells) of the indent in line "ptr", with -// 'tabstop' at "ts". -// If @param list is TRUE, count only screen size for tabs. -int get_indent_str(const char_u *ptr, int ts, int list) +/// Count the size (in window cells) of the indent in line "ptr", with +/// 'tabstop' at "ts". +/// If @param list is true, count only screen size for tabs. +int get_indent_str(const char_u *ptr, int ts, bool list) FUNC_ATTR_NONNULL_ALL { int count = 0; @@ -91,9 +91,9 @@ int get_indent_str(const char_u *ptr, int ts, int list) return count; } -// Count the size (in window cells) of the indent in line "ptr", using -// variable tabstops. -// if "list" is true, count only screen size for tabs. +/// Count the size (in window cells) of the indent in line "ptr", using +/// variable tabstops. +/// if "list" is true, count only screen size for tabs. int get_indent_str_vtab(const char_u *ptr, long ts, long *vts, bool list) { int count = 0; diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 6dacace0a4..277b9ade89 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -543,7 +543,7 @@ unsigned int trans_special(const char_u **srcp, const size_t src_len, /// Put the character sequence for "key" with "modifiers" into "dst" and return /// the resulting length. -/// When "keycode" is TRUE prefer key code, e.g. K_DEL instead of DEL. +/// When "keycode" is true prefer key code, e.g. K_DEL instead of DEL. /// The sequence is not NUL terminated. /// This is how characters in a string are encoded. unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst) diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index b6d1b5fda4..5799c3ee98 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -45,6 +45,9 @@ static int in_fast_callback = 0; +// Initialized in nlua_init(). +static lua_State *global_lstate = NULL; + typedef struct { Error err; String lua_err_str; @@ -250,7 +253,7 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, static void nlua_schedule_event(void **argv) { LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; nlua_pushref(lstate, cb); nlua_unref(lstate, cb); if (lua_pcall(lstate, 0, 0, 0)) { @@ -553,14 +556,10 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 0; } -/// Initialize lua interpreter +/// Initialize global lua interpreter /// -/// Crashes Nvim if initialization fails. Should be called once per lua -/// interpreter instance. -/// -/// @return New lua interpreter instance. -static lua_State *nlua_init(void) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT +/// Crashes Nvim if initialization fails. +void nlua_init(void) { #ifdef NLUA_TRACK_REFS const char *env = os_getenv("NVIM_LUA_NOTRACK"); @@ -577,28 +576,9 @@ static lua_State *nlua_init(void) luaL_openlibs(lstate); nlua_state_init(lstate); - return lstate; + global_lstate = lstate; } -// only to be used by nlua_enter and nlua_free_all_mem! -static lua_State *global_lstate = NULL; - -/// Enter lua interpreter -/// -/// Calls nlua_init() if needed. Is responsible for pre-lua call initialization -/// like updating `package.[c]path` with directories derived from &runtimepath. -/// -/// @return Interpreter instance to use. Will either be initialized now or -/// taken from previous initialization. -static lua_State *nlua_enter(void) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (global_lstate == NULL) { - global_lstate = nlua_init(); - } - lua_State *const lstate = global_lstate; - return lstate; -} void nlua_free_all_mem(void) { @@ -1043,8 +1023,7 @@ void nlua_unref(lua_State *lstate, LuaRef ref) void api_free_luaref(LuaRef ref) { - lua_State *const lstate = nlua_enter(); - nlua_unref(lstate, ref); + nlua_unref(global_lstate, ref); } /// push a value referenced in the registry @@ -1064,7 +1043,7 @@ LuaRef api_new_luaref(LuaRef original_ref) return LUA_NOREF; } - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; nlua_pushref(lstate, original_ref); LuaRef new_ref = nlua_ref(lstate, -1); lua_pop(lstate, 1); @@ -1143,7 +1122,7 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, return; } - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; if (luaL_loadbuffer(lstate, lcmd, lcmd_len, name)) { nlua_error(lstate, _("E5107: Error loading lua %.*s")); return; @@ -1233,7 +1212,7 @@ int typval_exec_lua_callable( /// @return Return value of the execution. Object nlua_exec(const String str, const Array args, Error *err) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; if (luaL_loadbuffer(lstate, str.data, str.size, "<nvim>")) { size_t len; @@ -1270,7 +1249,7 @@ Object nlua_exec(const String str, const Array args, Error *err) Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Error *err) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; nlua_pushref(lstate, ref); int nargs = (int)args.size; if (name != NULL) { @@ -1346,7 +1325,7 @@ void ex_luado(exarg_T *const eap) const char *const cmd = (const char *)eap->arg; const size_t cmd_len = strlen(cmd); - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; #define DOSTART "return function(line, linenr) " #define DOEND " end" @@ -1431,7 +1410,7 @@ void ex_luafile(exarg_T *const eap) bool nlua_exec_file(const char *path) FUNC_ATTR_NONNULL_ALL { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; if (luaL_loadfile(lstate, path)) { nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); @@ -1480,7 +1459,7 @@ int nlua_expand_pat(expand_T *xp, int *num_results, char_u ***results) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; int ret = OK; // [ vim ] @@ -1690,7 +1669,7 @@ int nlua_CFunction_func_call( typval_T *rettv, void *state) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; LuaCFunctionState *funcstate = (LuaCFunctionState *)state; return typval_exec_lua_callable(lstate, funcstate->lua_callable, @@ -1699,7 +1678,7 @@ int nlua_CFunction_func_call( void nlua_CFunction_func_free(void *state) { - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; LuaCFunctionState *funcstate = (LuaCFunctionState *)state; nlua_unref(lstate, funcstate->lua_callable.func_ref); @@ -1730,7 +1709,7 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) return NULL; } - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; #ifndef NDEBUG int top = lua_gettop(lstate); @@ -1769,7 +1748,7 @@ void nlua_execute_log_keystroke(int c) char_u buf[NUMBUFLEN]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); - lua_State *const lstate = nlua_enter(); + lua_State *const lstate = global_lstate; #ifndef NDEBUG int top = lua_gettop(lstate); diff --git a/src/nvim/main.c b/src/nvim/main.c index 16700d20ab..7a2b9746e9 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -7,8 +7,6 @@ #include <string.h> #include <stdbool.h> -#include <lua.h> -#include <lauxlib.h> #include <msgpack.h> #include "nvim/ascii.h" @@ -258,6 +256,8 @@ int main(int argc, char **argv) // Check if we have an interactive window. check_and_set_isatty(¶ms); + nlua_init(); + // Process the command line arguments. File names are put in the global // argument list "global_alist". command_line_scan(¶ms); @@ -318,7 +318,8 @@ int main(int argc, char **argv) debug_break_level = params.use_debug_break_level; // Read ex-commands if invoked with "-es". - if (!params.input_isatty && silent_mode && exmode_active == EXMODE_NORMAL) { + if (!params.input_isatty && !params.input_neverscript + && silent_mode && exmode_active) { input_start(STDIN_FILENO); } @@ -341,7 +342,6 @@ int main(int argc, char **argv) TIME_MSG("initialized screen early for UI"); } - // open terminals when opening files that start with term:// #define PROTO "term://" do_cmdline_cmd("augroup nvim_terminal"); @@ -765,7 +765,7 @@ static bool edit_stdin(bool explicit, mparm_T *parmp) { bool implicit = !headless_mode && !embedded_mode - && exmode_active != EXMODE_NORMAL // -E/-Es but not -e/-es. + && (!exmode_active || parmp->input_neverscript) && !parmp->input_isatty && scriptin[0] == NULL; // `-s -` was not given. return explicit || implicit; @@ -908,11 +908,12 @@ static void command_line_scan(mparm_T *parmp) break; } case 'e': { // "-e" Ex mode - exmode_active = EXMODE_NORMAL; + exmode_active = true; break; } case 'E': { // "-E" Ex mode - exmode_active = EXMODE_VIM; + exmode_active = true; + parmp->input_neverscript = true; break; } case 'f': { // "-f" GUI: run in foreground. @@ -1424,7 +1425,7 @@ static void handle_quickfix(mparm_T *paramp) static void handle_tag(char_u *tagname) { if (tagname != NULL) { - swap_exists_did_quit = FALSE; + swap_exists_did_quit = false; vim_snprintf((char *)IObuff, IOSIZE, "ta %s", tagname); do_cmdline_cmd((char *)IObuff); @@ -1632,7 +1633,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd) curwin->w_arg_idx = arg_idx; /* Edit file from arg list, if there is one. When "Quit" selected * at the ATTENTION prompt close the window. */ - swap_exists_did_quit = FALSE; + swap_exists_did_quit = false; (void)do_ecmd(0, arg_idx < GARGCOUNT ? alist_name(&GARGLIST[arg_idx]) : NULL, NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin); diff --git a/src/nvim/main.h b/src/nvim/main.h index 61252f2bce..d387e6d668 100644 --- a/src/nvim/main.h +++ b/src/nvim/main.h @@ -30,6 +30,7 @@ typedef struct { bool input_isatty; // stdin is a terminal bool output_isatty; // stdout is a terminal bool err_isatty; // stderr is a terminal + bool input_neverscript; // never treat stdin as script (-E/-Es) int no_swap_file; // "-n" argument used int use_debug_break_level; int window_count; // number of windows to use diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 73e3ba53a5..9cd57affb9 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -2354,10 +2354,8 @@ int convert_setup(vimconv_T *vcp, char_u *from, char_u *to) return convert_setup_ext(vcp, from, true, to, true); } -/* - * As convert_setup(), but only when from_unicode_is_utf8 is TRUE will all - * "from" unicode charsets be considered utf-8. Same for "to". - */ +/// As convert_setup(), but only when from_unicode_is_utf8 is true will all +/// "from" unicode charsets be considered utf-8. Same for "to". int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, char_u *to, bool to_unicode_is_utf8) { diff --git a/src/nvim/memfile_defs.h b/src/nvim/memfile_defs.h index 2402d2147d..3eaa7d83e0 100644 --- a/src/nvim/memfile_defs.h +++ b/src/nvim/memfile_defs.h @@ -101,7 +101,7 @@ typedef struct memfile { blocknr_T mf_neg_count; /// number of negative blocks numbers blocknr_T mf_infile_count; /// number of pages in the file unsigned mf_page_size; /// number of bytes in a page - bool mf_dirty; /// TRUE if there are dirty blocks + bool mf_dirty; /// true if there are dirty blocks } memfile_T; #endif // NVIM_MEMFILE_DEFS_H diff --git a/src/nvim/message.c b/src/nvim/message.c index ec5dabbbc0..7ac846a553 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1284,7 +1284,7 @@ void set_keep_msg(char_u *s, int attr) keep_msg = vim_strsave(s); else keep_msg = NULL; - keep_msg_more = FALSE; + keep_msg_more = false; keep_msg_attr = attr; } @@ -1324,9 +1324,8 @@ void msg_start(void) 0; } else if (msg_didout) { // start message on next line msg_putchar('\n'); - did_return = TRUE; - if (exmode_active != EXMODE_NORMAL) - cmdline_row = msg_row; + did_return = true; + cmdline_row = msg_row; } if (!msg_didany || lines_left < 0) msg_starthere(); diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 38d0a7dadf..771174b854 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -750,8 +750,8 @@ get_number ( stuffcharReadbuff(':'); if (!exmode_active) cmdline_row = msg_row; - skip_redraw = TRUE; /* skip redraw once */ - do_redraw = FALSE; + skip_redraw = true; // skip redraw once + do_redraw = false; break; } else if (c == Ctrl_C || c == ESC || c == 'q') { n = 0; @@ -849,7 +849,7 @@ void msgmore(long n) } if (msg(msg_buf)) { set_keep_msg(msg_buf, 0); - keep_msg_more = TRUE; + keep_msg_more = true; } } } diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 4c0339e5f4..f1ad0ed105 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -570,9 +570,8 @@ static linenr_T find_longest_lnum(void) return ret; } -/// -/// Do a horizontal scroll. Return TRUE if the cursor moved, FALSE otherwise. -/// +/// Do a horizontal scroll. +/// @return true if the cursor moved, false otherwise. bool mouse_scroll_horiz(int dir) { if (curwin->w_p_wrap) { diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 74a3d74860..9185062f94 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -92,8 +92,6 @@ static linenr_T resel_VIsual_line_count; /* number of lines */ static colnr_T resel_VIsual_vcol; /* nr of cols or end col */ static int VIsual_mode_orig = NUL; /* saved Visual mode */ -static int restart_VIsual_select = 0; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "normal.c.generated.h" @@ -1188,7 +1186,7 @@ static void normal_check_interrupt(NormalState *s) && s->previous_got_int) { // Typed two CTRL-C in a row: go back to ex mode as if "Q" was // used and keep "got_int" set, so that it aborts ":g". - exmode_active = EXMODE_NORMAL; + exmode_active = true; State = NORMAL; } else if (!global_busy || !exmode_active) { if (!quit_more) { @@ -1340,7 +1338,7 @@ static int normal_check(VimState *state) quit_more = false; // If skip redraw is set (for ":" in wait_return()), don't redraw now. - // If there is nothing in the stuff_buffer or do_redraw is TRUE, + // If there is nothing in the stuff_buffer or do_redraw is true, // update cursor and redraw. if (skip_redraw || exmode_active) { skip_redraw = false; @@ -1398,7 +1396,7 @@ static int normal_check(VimState *state) if (s->noexmode) { return 0; } - do_exmode(exmode_active == EXMODE_VIM); + do_exmode(); return -1; } @@ -4652,7 +4650,7 @@ static void nv_exmode(cmdarg_T *cap) if (VIsual_active) { vim_beep(BO_EX); } else if (!checkclearop(cap->oap)) { - do_exmode(false); + do_exmode(); } } @@ -7101,8 +7099,9 @@ static void nv_g_cmd(cmdarg_T *cap) break; } - if (!checkclearopq(oap)) - do_exmode(true); + if (!checkclearopq(oap)) { + do_exmode(); + } break; case ',': @@ -8146,10 +8145,8 @@ static void nv_event(cmdarg_T *cap) } } -/* - * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos". - */ -static int mouse_model_popup(void) +/// @return true when 'mousemodel' is set to "popup" or "popup_setpos". +static bool mouse_model_popup(void) { return p_mousem[0] == 'p'; } diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 0a556390e7..5e40bdd6ef 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -459,7 +459,6 @@ EXTERN char_u *p_pmcs; // 'printmbcharset' EXTERN char_u *p_pfn; // 'printfont' EXTERN char_u *p_popt; // 'printoptions' EXTERN char_u *p_header; // 'printheader' -EXTERN int p_prompt; // 'prompt' EXTERN char_u *p_guicursor; // 'guicursor' EXTERN char_u *p_guifont; // 'guifont' EXTERN char_u *p_guifontwide; // 'guifontwide' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 48e53c68f3..0830fb4638 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1800,7 +1800,7 @@ return { full_name='prompt', short_desc=N_("enable prompt in Ex mode"), type='bool', scope={'global'}, - varname='p_prompt', + varname='p_force_on', defaults={if_true={vi=true}} }, { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index ae785132bb..d8f5f1077c 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -165,7 +165,7 @@ static bool resizing = false; #endif #define SEARCH_HL_PRIORITY 0 -static char * provider_first_error = NULL; +static char * provider_err = NULL; static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, Array args, bool default_true) @@ -187,10 +187,10 @@ static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, const char *ns_name = describe_ns(ns_id); ELOG("error in provider %s:%s: %s", ns_name, name, err.msg); bool verbose_errs = true; // TODO(bfredl): - if (verbose_errs && provider_first_error == NULL) { + if (verbose_errs && provider_err == NULL) { static char errbuf[IOSIZE]; snprintf(errbuf, sizeof errbuf, "%s: %s", ns_name, err.msg); - provider_first_error = xstrdup(errbuf); + provider_err = xstrdup(errbuf); } } @@ -2103,7 +2103,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool search_attr_from_match = false; // if search_attr is from :match bool has_decor = false; // this buffer has decoration - bool do_virttext = false; // draw virtual text for this line int win_col_offset = 0; // offset for window columns char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext @@ -2148,8 +2147,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, row = startrow; - char *err_text = NULL; - buf_T *buf = wp->w_buffer; if (!number_only) { @@ -2194,14 +2191,20 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } } - if (has_decor) { - extra_check = true; + if (provider_err) { + Decoration err_decor = DECORATION_INIT; + int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg")); + kv_push(err_decor.virt_text, + ((VirtTextChunk){ .text = provider_err, + .hl_id = hl_err })); + err_decor.virt_text_width = mb_string2cells((char_u *)provider_err); + decor_add_ephemeral(lnum-1, 0, lnum-1, 0, &err_decor); + provider_err = NULL; + has_decor = true; } - if (provider_first_error) { - err_text = provider_first_error; - provider_first_error = NULL; - do_virttext = true; + if (has_decor) { + extra_check = true; } // Check for columns to display for 'colorcolumn'. @@ -3953,19 +3956,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, if (draw_color_col) draw_color_col = advance_color_col(VCOL_HLC, &color_cols); - VirtText virt_text = KV_INITIAL_VALUE; - bool has_aligned = false; - if (err_text) { - int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg")); - kv_push(virt_text, ((VirtTextChunk){ .text = err_text, - .hl_id = hl_err })); - do_virttext = true; - } else if (has_decor) { - virt_text = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr, - &has_aligned); - if (kv_size(virt_text)) { - do_virttext = true; - } + bool has_virttext = false; + // Make sure alignment is the same regardless + // if listchars=eol:X is used or not. + int eol_skip = (wp->w_p_lcs_chars.eol == lcs_eol_one && eol_hl_off == 0 + ? 1 : 0); + + if (has_decor) { + has_virttext = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr, + col + eol_skip); } if (((wp->w_p_cuc @@ -3974,20 +3973,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, grid->Columns * (row - startrow + 1) + v && lnum != wp->w_cursor.lnum) || draw_color_col || line_attr_lowprio || line_attr - || diff_hlf != (hlf_T)0 || do_virttext - || has_aligned)) { + || diff_hlf != (hlf_T)0 || has_virttext)) { int rightmost_vcol = 0; int i; - size_t virt_pos = 0; - LineState s = LINE_STATE(""); - int virt_attr = 0; - - // Make sure alignment is the same regardless - // if listchars=eol:X is used or not. - bool delay_virttext = wp->w_p_lcs_chars.eol == lcs_eol_one - && eol_hl_off == 0; - if (wp->w_p_cuc) { rightmost_vcol = wp->w_virtcol; } @@ -4013,37 +4002,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } int base_attr = hl_combine_attr(line_attr_lowprio, diff_attr); - if (base_attr || line_attr || has_aligned) { + if (base_attr || line_attr || has_virttext) { rightmost_vcol = INT_MAX; } int col_stride = wp->w_p_rl ? -1 : 1; while (wp->w_p_rl ? col >= 0 : col < grid->Columns) { - int cells = -1; - if (do_virttext && !delay_virttext) { - if (*s.p == NUL) { - if (virt_pos < virt_text.size) { - s.p = kv_A(virt_text, virt_pos).text; - int hl_id = kv_A(virt_text, virt_pos).hl_id; - virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; - virt_pos++; - } else { - do_virttext = false; - } - } - if (*s.p != NUL) { - cells = line_putchar(&s, &linebuf_char[off], grid->Columns - col, - false); - } - } - delay_virttext = false; - - if (cells == -1) { - schar_from_ascii(linebuf_char[off], ' '); - cells = 1; - } - col += cells * col_stride; + schar_from_ascii(linebuf_char[off], ' '); + col += col_stride; if (draw_color_col) { draw_color_col = advance_color_col(VCOL_HLC, &color_cols); } @@ -4056,24 +4023,16 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, col_attr = mc_attr; } - if (do_virttext) { - col_attr = hl_combine_attr(col_attr, virt_attr); - } - col_attr = hl_combine_attr(col_attr, line_attr); linebuf_attr[off] = col_attr; - if (cells == 2) { - linebuf_attr[off+1] = col_attr; - } - off += cells * col_stride; + off += col_stride; - if (VCOL_HLC >= rightmost_vcol && *s.p == NUL - && virt_pos >= virt_text.size) { + if (VCOL_HLC >= rightmost_vcol) { break; } - vcol += cells; + vcol += 1; } } @@ -4392,7 +4351,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } xfree(p_extra_free); - xfree(err_text); return row; } @@ -4400,13 +4358,17 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col) { DecorState *state = &decor_state; int right_pos = max_col; + bool do_eol = state->eol_col > -1; for (size_t i = 0; i < kv_size(state->active); i++) { DecorRange *item = &kv_A(state->active, i); if (item->start_row == state->row && kv_size(item->decor.virt_text)) { if (item->win_col == -1) { if (item->decor.virt_text_pos == kVTRightAlign) { - right_pos -= item->decor.col; + right_pos -= item->decor.virt_text_width; item->win_col = right_pos; + } else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) { + item->win_col = state->eol_col; + state->eol_col += item->decor.virt_text_width; } else if (item->decor.virt_text_pos == kVTWinCol) { item->win_col = MAX(item->decor.col+col_off, 0); } @@ -4424,14 +4386,20 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col) while (col < max_col) { if (!*s.p) { - if (virt_pos == kv_size(vt)) { + if (virt_pos >= kv_size(vt)) { + break; + } + virt_attr = 0; + do { + s.p = kv_A(vt, virt_pos).text; + int hl_id = kv_A(vt, virt_pos).hl_id; + virt_attr = hl_combine_attr(virt_attr, + hl_id > 0 ? syn_id2attr(hl_id) : 0); + virt_pos++; + } while (!s.p && virt_pos < kv_size(vt)); + if (!s.p) { break; } - s.p = kv_A(vt, virt_pos).text; - int hl_id = kv_A(vt, virt_pos).hl_id; - virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0; - virt_pos++; - continue; } int attr; bool through = false; diff --git a/src/nvim/search.c b/src/nvim/search.c index a946a5e24b..4ec5f4f74d 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -474,7 +474,7 @@ void set_last_search_pat(const char_u *s, int idx, int magic, int setlast) spats[idx].timestamp = os_time(); spats[idx].additional_data = NULL; spats[idx].magic = magic; - spats[idx].no_scs = FALSE; + spats[idx].no_scs = false; spats[idx].off.dir = '/'; set_vv_searchforward(); spats[idx].off.line = FALSE; @@ -1501,7 +1501,7 @@ int searchc(cmdarg_T *cap, int t_cmd) FUNC_ATTR_NONNULL_ALL { int c = cap->nchar; // char to search for - Direction dir = cap->arg; // TRUE for searching forward + int dir = cap->arg; // true for searching forward long count = cap->count1; // repeat count int col; char_u *p; diff --git a/src/nvim/search.h b/src/nvim/search.h index 98ddaa5eeb..0dbaf79c37 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -88,7 +88,7 @@ typedef struct searchstat { int cur; // current position of found words int cnt; // total count of found words - int exact_match; // TRUE if matched exactly on specified position + bool exact_match; // true if matched exactly on specified position int incomplete; // 0: search was fully completed // 1: recomputing was timed out // 2: max count exceeded diff --git a/src/nvim/sign.c b/src/nvim/sign.c index d884ae62f4..c6f59b42b8 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -115,10 +115,10 @@ static void sign_group_unref(char_u *groupname) } } -/// Returns TRUE if 'sign' is in 'group'. +/// @return true if 'sign' is in 'group'. /// A sign can either be in the global group (sign->group == NULL) /// or in a named group. If 'group' is '*', then the sign is part of the group. -int sign_in_group(sign_entry_T *sign, const char_u *group) +bool sign_in_group(sign_entry_T *sign, const char_u *group) { return ((group != NULL && STRCMP(group, "*") == 0) || (group == NULL && sign->se_group == NULL) diff --git a/src/nvim/state.c b/src/nvim/state.c index a3c74789d1..02d63d8ab1 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -144,6 +144,9 @@ char *get_mode(void) buf[0] = (char)(VIsual_mode + 's' - 'v'); } else { buf[0] = (char)VIsual_mode; + if (restart_VIsual_select) { + buf[1] = 's'; + } } } else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE || State == CONFIRM) { @@ -171,12 +174,10 @@ char *get_mode(void) buf[1] = 'x'; } } - } else if ((State & CMDLINE) || exmode_active) { + } else if (State & CMDLINE) { buf[0] = 'c'; - if (exmode_active == EXMODE_VIM) { + if (exmode_active) { buf[1] = 'v'; - } else if (exmode_active == EXMODE_NORMAL) { - buf[1] = 'e'; } } else if (State & TERM_FOCUS) { buf[0] = 't'; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 6347d83626..00d999cd9b 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -3417,16 +3417,6 @@ static void syn_cmd_on(exarg_T *eap, int syncing) } /* - * Handle ":syntax enable" command. - */ -static void syn_cmd_enable(exarg_T *eap, int syncing) -{ - set_internal_string_var("syntax_cmd", (char_u *)"enable"); - syn_cmd_onoff(eap, "syntax"); - do_unlet(S_LEN("g:syntax_cmd"), true); -} - -/* * Handle ":syntax reset" command. * It actually resets highlighting, not syntax. */ @@ -3434,9 +3424,7 @@ static void syn_cmd_reset(exarg_T *eap, int syncing) { eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { - set_internal_string_var("syntax_cmd", (char_u *)"reset"); - do_cmdline_cmd("runtime! syntax/syncolor.vim"); - do_unlet(S_LEN("g:syntax_cmd"), true); + init_highlight(true, true); } } @@ -3475,7 +3463,7 @@ void syn_maybe_enable(void) exarg_T ea; ea.arg = (char_u *)""; ea.skip = false; - syn_cmd_enable(&ea, false); + syn_cmd_on(&ea, false); } } @@ -5534,7 +5522,7 @@ static struct subcommand subcommands[] = { "clear", syn_cmd_clear }, { "cluster", syn_cmd_cluster }, { "conceal", syn_cmd_conceal }, - { "enable", syn_cmd_enable }, + { "enable", syn_cmd_on }, { "foldlevel", syn_cmd_foldlevel }, { "include", syn_cmd_include }, { "iskeyword", syn_cmd_iskeyword }, @@ -6057,6 +6045,34 @@ static const char *highlight_init_both[] = { "RedrawDebugClear ctermbg=Yellow guibg=Yellow", "RedrawDebugComposed ctermbg=Green guibg=Green", "RedrawDebugRecompose ctermbg=Red guibg=Red", + "Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE " + "guifg=White guibg=Red", + "Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE " + "guifg=Blue guibg=Yellow", + "default link String Constant", + "default link Character Constant", + "default link Number Constant", + "default link Boolean Constant", + "default link Float Number", + "default link Function Identifier", + "default link Conditional Statement", + "default link Repeat Statement", + "default link Label Statement", + "default link Operator Statement", + "default link Keyword Statement", + "default link Exception Statement", + "default link Include PreProc", + "default link Define PreProc", + "default link Macro PreProc", + "default link PreCondit PreProc", + "default link StorageClass Type", + "default link Structure Type", + "default link Typedef Type", + "default link Tag Special", + "default link SpecialChar Special", + "default link Delimiter Special", + "default link SpecialComment Special", + "default link Debug Special", NULL }; @@ -6090,6 +6106,24 @@ static const char *highlight_init_light[] = { "Title ctermfg=DarkMagenta gui=bold guifg=Magenta", "Visual guibg=LightGrey", "WarningMsg ctermfg=DarkRed guifg=Red", + "Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE " + "gui=NONE guifg=Blue guibg=NONE", + "Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE " + "gui=NONE guifg=Magenta guibg=NONE", + "Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE " + "gui=NONE guifg=#6a5acd guibg=NONE", + "Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE " + "gui=NONE guifg=DarkCyan guibg=NONE", + "Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE " + "gui=bold guifg=Brown guibg=NONE", + "PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE " + "gui=NONE guifg=#6a0dad guibg=NONE", + "Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE " + "gui=bold guifg=SeaGreen guibg=NONE", + "Underlined term=underline cterm=underline ctermfg=DarkMagenta " + "gui=underline guifg=SlateBlue", + "Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE " + "gui=NONE guifg=bg guibg=NONE", NULL }; @@ -6123,6 +6157,24 @@ static const char *highlight_init_dark[] = { "Title ctermfg=LightMagenta gui=bold guifg=Magenta", "Visual guibg=DarkGrey", "WarningMsg ctermfg=LightRed guifg=Red", + "Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE " + "gui=NONE guifg=#80a0ff guibg=NONE", + "Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE " + "gui=NONE guifg=#ffa0a0 guibg=NONE", + "Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE " + "gui=NONE guifg=Orange guibg=NONE", + "Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE " + "gui=NONE guifg=#40ffff guibg=NONE", + "Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE " + "gui=bold guifg=#ffff60 guibg=NONE", + "PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE " + "gui=NONE guifg=#ff80ff guibg=NONE", + "Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE " + "gui=bold guifg=#60ff60 guibg=NONE", + "Underlined term=underline cterm=underline ctermfg=LightBlue " + "gui=underline guifg=#80a0ff", + "Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE " + "gui=NONE guifg=bg guibg=NONE", NULL }; @@ -6398,20 +6450,6 @@ void init_highlight(bool both, bool reset) } } - /* - * If syntax highlighting is enabled load the highlighting for it. - */ - if (get_var_value("g:syntax_on") != NULL) { - static int recursive = 0; - - if (recursive >= 5) { - EMSG(_("E679: recursive loop loading syncolor.vim")); - } else { - recursive++; - (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL); - recursive--; - } - } syn_init_cmdline_highlight(false, false); } diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 224ca257ab..bcf2edcc93 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -534,6 +534,7 @@ func Test_mode() set complete=. inoremap <F2> <C-R>=Save_mode()<CR> + xnoremap <F2> <Cmd>call Save_mode()<CR> normal! 3G exe "normal i\<F2>\<Esc>" @@ -645,6 +646,14 @@ func Test_mode() call assert_equal("\<C-S>", mode(1)) call feedkeys("\<Esc>", 'xt') + " v_CTRL-O + exe "normal gh\<C-O>\<F2>\<Esc>" + call assert_equal("v-vs", g:current_modes) + exe "normal gH\<C-O>\<F2>\<Esc>" + call assert_equal("V-Vs", g:current_modes) + exe "normal g\<C-H>\<C-O>\<F2>\<Esc>" + call assert_equal("\<C-V>-\<C-V>s", g:current_modes) + call feedkeys(":echo \<C-R>=Save_mode()\<C-U>\<CR>", 'xt') call assert_equal('c-c', g:current_modes) call feedkeys("gQecho \<C-R>=Save_mode()\<CR>\<CR>vi\<CR>", 'xt') @@ -653,6 +662,7 @@ func Test_mode() bwipe! iunmap <F2> + xunmap <F2> set complete& endfunc @@ -1315,7 +1325,15 @@ endfunc func Test_getchar() call feedkeys('a', '') call assert_equal(char2nr('a'), getchar()) + call assert_equal(0, getchar(0)) + call assert_equal(0, getchar(1)) + + call feedkeys('a', '') + call assert_equal('a', getcharstr()) + call assert_equal('', getcharstr(0)) + call assert_equal('', getcharstr(1)) + call setline(1, 'xxxx') " call test_setmouse(1, 3) " let v:mouse_win = 9 " let v:mouse_winid = 9 @@ -1328,6 +1346,7 @@ func Test_getchar() call assert_equal(win_getid(1), v:mouse_winid) call assert_equal(1, v:mouse_lnum) call assert_equal(3, v:mouse_col) + enew! endfunc func Test_libcall_libcallnr() diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 431237bac5..dcc086a0cf 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1123,8 +1123,8 @@ static void tui_mode_change(UI *ui, String mode, Integer mode_idx) data->showing_mode = (ModeShape)mode_idx; } -static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow, - Integer startcol, Integer endcol, +static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, // -V751 + Integer endrow, Integer startcol, Integer endcol, Integer rows, Integer cols FUNC_ATTR_UNUSED) { TUIData *data = ui->data; diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 7afabc7913..3096fe84c0 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -1018,14 +1018,14 @@ static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error, extup->type = type; if (type == kExtmarkSplice) { n_elems = (size_t)sizeof(ExtmarkSplice) / sizeof(uint8_t); - buf = xcalloc(sizeof(uint8_t), n_elems); + buf = xcalloc(n_elems, sizeof(uint8_t)); if (!undo_read(bi, buf, n_elems)) { goto error; } extup->data.splice = *(ExtmarkSplice *)buf; } else if (type == kExtmarkMove) { n_elems = (size_t)sizeof(ExtmarkMove) / sizeof(uint8_t); - buf = xcalloc(sizeof(uint8_t), n_elems); + buf = xcalloc(n_elems, sizeof(uint8_t)); if (!undo_read(bi, buf, n_elems)) { goto error; } diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 976e63b44d..4e2bed4deb 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -603,6 +603,31 @@ describe('lua stdlib', function() return vim.tbl_islist(c) and count == 0 ]])) + eq(exec_lua([[ + local a = { a = { b = 1 } } + local b = { a = {} } + return vim.tbl_deep_extend("force", a, b) + ]]), {a = {b = 1}}) + + eq(exec_lua([[ + local a = { a = 123 } + local b = { a = { b = 1} } + return vim.tbl_deep_extend("force", a, b) + ]]), {a = {b = 1}}) + + ok(exec_lua([[ + local a = { a = {[2] = 3} } + local b = { a = {[3] = 3} } + local c = vim.tbl_deep_extend("force", a, b) + return vim.deep_equal(c, {a = {[3] = 3}}) + ]])) + + eq(exec_lua([[ + local a = { a = { b = 1} } + local b = { a = 123 } + return vim.tbl_deep_extend("force", a, b) + ]]), {a = 123 }) + eq('Error executing lua: vim/shared.lua:0: invalid "behavior": nil', pcall_err(exec_lua, [[ return vim.tbl_deep_extend() diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index c1c76c3916..7359ee4bce 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -241,6 +241,38 @@ describe('vim.lsp.diagnostic', function() ]])) end) + it('should not display diagnostics when disabled', function() + eq({0, 2}, exec_lua [[ + local server_1_diags = { + make_error("Error 1", 1, 1, 1, 5), + make_warning("Warning on Server 1", 2, 1, 2, 5), + } + local server_2_diags = { + make_warning("Warning 1", 2, 1, 2, 5), + } + + vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_1_diags }, 1) + vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_2_diags }, 2) + + vim.lsp.diagnostic.disable(diagnostic_bufnr, 1) + + return { + count_of_extmarks_for_client(diagnostic_bufnr, 1), + count_of_extmarks_for_client(diagnostic_bufnr, 2), + } + ]]) + + eq({4, 0}, exec_lua [[ + vim.lsp.diagnostic.enable(diagnostic_bufnr, 1) + vim.lsp.diagnostic.disable(diagnostic_bufnr, 2) + + return { + count_of_extmarks_for_client(diagnostic_bufnr, 1), + count_of_extmarks_for_client(diagnostic_bufnr, 2), + } + ]]) + end) + describe('reset', function() it('diagnostic count is 0 and displayed diagnostics are 0 after call', function() -- 1 Error (1) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index e38ed10ab9..e5533af73b 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -14,6 +14,7 @@ local retry = helpers.retry local NIL = helpers.NIL local read_file = require('test.helpers').read_file local write_file = require('test.helpers').write_file +local isCI = helpers.isCI -- Use these to get access to a coroutine so that I can run async tests and use -- yield. @@ -262,8 +263,8 @@ describe('LSP', function() end) it('should succeed with manual shutdown', function() - if 'openbsd' == helpers.uname() then - pending('hangs the build on openbsd #14028, re-enable with freeze timeout #14204') + if isCI() then + pending('hangs the build on CI #14028, re-enable with freeze timeout #14204') return end local expected_handlers = { diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 05e0c5fe2c..175525b3f2 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -570,4 +570,47 @@ describe('treesitter highlighting', function() ]]} screen:expect{ unchanged=true } end) + + it("supports highlighting with priority", function() + if pending_c_parser(pending) then return end + + insert([[ + int x = INT_MAX; + #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + #define foo void main() { \ + return 42; \ + } + ]]) + + exec_lua [[ + local parser = vim.treesitter.get_parser(0, "c") + test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @Error (set! "priority" 101))\n'}}) + ]] + -- expect everything to have Error highlight + screen:expect{grid=[[ + {12:int}{8: x = INT_MAX;} | + {8:#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))}| + {8:#define foo void main() { \} | + {8: return 42; \} | + {8: }} | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], attr_ids={ + [1] = {bold = true, foreground = Screen.colors.Blue1}; + [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}; + -- bold will not be overwritten at the moment + [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Grey100}; + }} + end) end) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index d2f9148e8f..d9df5fbc0d 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -646,6 +646,19 @@ int x = INT_MAX; {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) }, get_ranges()) end) + it("should list all directives", function() + local res_list = exec_lua[[ + local query = require'vim.treesitter.query' + + local list = query.list_directives() + + table.sort(list) + + return list + ]] + + eq({ 'offset!', 'set!' }, res_list) + end) end) end) diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index af709cd521..16ed3b9486 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -858,8 +858,8 @@ describe('Buffer highlighting', function() it('works with cursorline', function() command("set cursorline") - screen:expect([[ - {14:^1 + 2 }{15:=}{16: 3}{14: }| + screen:expect{grid=[[ + {14:^1 + 2 }{3:=}{2: 3}{14: }| 3 + {11:ERROR:} invalid syntax | 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| @@ -867,32 +867,32 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| | - ]]) + ]]} feed('j') - screen:expect([[ + screen:expect{grid=[[ 1 + 2 {3:=}{2: 3} | - {14:^3 + }{11:ERROR:}{14: invalid syntax }| + {14:^3 + }{11:ERROR:} invalid syntax{14: }| 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| x = 4 | {1:~ }| {1:~ }| | - ]]) + ]]} feed('j') - screen:expect([[ + screen:expect{grid=[[ 1 + 2 {3:=}{2: 3} | 3 + {11:ERROR:} invalid syntax | {14:^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}| - {14:, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s}| + {14:, 5, 5, 5, 5, 5, 5, }Lorem ipsum dolor s| x = 4 | {1:~ }| {1:~ }| | - ]]) + ]]} end) it('works with color column', function() @@ -910,11 +910,11 @@ describe('Buffer highlighting', function() command("set colorcolumn=9") screen:expect{grid=[[ - ^1 + 2 {3:=}{2: }{17:3} | + ^1 + 2 {3:=}{2: 3} | 3 + {11:ERROR:} invalid syntax | 5, 5, 5,{18: }5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5| , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s| - x = 4 {12:暗}{19:x}{12:事} | + x = 4 {12:暗x事} | {1:~ }| {1:~ }| | diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 0ea8bab957..ad23402ff9 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -14,6 +14,8 @@ local function new_screen(opt) [3] = {bold = true, reverse = true}, [4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [6] = {foreground = Screen.colors.Magenta}, + [7] = {bold = true, foreground = Screen.colors.Brown}, }) return screen end @@ -267,7 +269,7 @@ local function test_cmdline(linegrid) special = {'"', true}, }, { firstc = "=", - content = {{"1"}, {"+"}, {"2"}}, + content = {{"1", 6}, {"+", 7}, {"2", 6}}, pos = 3, }} diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 98aafd8757..4373d17890 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -562,7 +562,7 @@ end]] {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) | {5:i}{12:c}{11:ombining color} {13:nil} {5:then} | {11:replacing color}d_cell | - {5:e}{8:bl}{14:endy}{15:i}{14:text}{15:o}{14:-}{15:o}{14:h}{7:ere} | + {5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here} | {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | {11:replacing color} line[colpos] | cell.text = text | @@ -697,4 +697,96 @@ end]] | ]]} end) + + it('can have virtual text which combines foreground and backround groups', function() + screen:set_default_attr_ids { + [1] = {bold=true, foreground=Screen.colors.Blue}; + [2] = {background = tonumber('0x123456'), foreground = tonumber('0xbbbbbb')}; + [3] = {background = tonumber('0x123456'), foreground = tonumber('0xcccccc')}; + [4] = {background = tonumber('0x234567'), foreground = tonumber('0xbbbbbb')}; + [5] = {background = tonumber('0x234567'), foreground = tonumber('0xcccccc')}; + [6] = {bold = true, foreground = tonumber('0xcccccc'), background = tonumber('0x234567')}; + } + + exec [[ + hi BgOne guibg=#123456 + hi BgTwo guibg=#234567 + hi FgEin guifg=#bbbbbb + hi FgZwei guifg=#cccccc + hi VeryBold gui=bold + ]] + + meths.buf_set_extmark(0, ns, 0, 0, { virt_text={ + {'a', {'BgOne', 'FgEin'}}; + {'b', {'BgOne', 'FgZwei'}}; + {'c', {'BgTwo', 'FgEin'}}; + {'d', {'BgTwo', 'FgZwei'}}; + {'X', {'BgTwo', 'FgZwei', 'VeryBold'}}; + }}) + + screen:expect{grid=[[ + ^ {2:a}{3:b}{4:c}{5:d}{6:X} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end) + + it('does not crash when deleting a cleared buffer #15212', function() + exec_lua [[ + ns = vim.api.nvim_create_namespace("myplugin") + vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {virt_text = {{"a"}}, end_col = 0}) + ]] + screen:expect{grid=[[ + ^ a | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + exec_lua [[ + vim.api.nvim_buf_clear_namespace(0, ns, 0, -1) + vim.cmd("bdelete") + ]] + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + helpers.assert_alive() + end) end) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 8992ee27ce..7471255345 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -789,7 +789,7 @@ describe("'listchars' highlight", function() [0] = {bold=true, foreground=Screen.colors.Blue}, [1] = {background=Screen.colors.Grey90}, [2] = {foreground=Screen.colors.Red}, - [3] = {foreground=Screen.colors.Green1}, + [3] = {foreground=Screen.colors.X11Green, background=Screen.colors.Red1}, }) feed_command('highlight clear ModeMsg') feed_command('highlight Whitespace guifg=#FF0000') diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 06c92a4b10..741b93043d 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -176,8 +176,8 @@ describe('Signs', function() command('sign place 5 line=3 name=pietWarn buffer=1') command('sign place 3 line=3 name=pietError buffer=1') screen:expect([[ - {1:>>}XX{6: 1 }a | - XX{1:>>}{6: 2 }b | + {1:>>}{8:XX}{6: 1 }a | + {8:XX}{1:>>}{6: 2 }b | {1:>>}WW{6: 3 }c | {2: }{6: 4 }^ | {0:~ }| @@ -194,7 +194,7 @@ describe('Signs', function() -- With the default setting, we get the sign with the top id. command('set signcolumn=yes:1') screen:expect([[ - XX{6: 1 }a | + {8:XX}{6: 1 }a | {1:>>}{6: 2 }b | WW{6: 3 }c | {2: }{6: 4 }^ | @@ -212,9 +212,9 @@ describe('Signs', function() -- "auto:3" accommodates all the signs we defined so far. command('set signcolumn=auto:3') screen:expect([[ - {1:>>}XX{2: }{6: 1 }a | - XX{1:>>}{2: }{6: 2 }b | - XX{1:>>}WW{6: 3 }c | + {1:>>}{8:XX}{2: }{6: 1 }a | + {8:XX}{1:>>}{2: }{6: 2 }b | + {8:XX}{1:>>}WW{6: 3 }c | {2: }{6: 4 }^ | {0:~ }| {0:~ }| @@ -230,9 +230,9 @@ describe('Signs', function() -- Check "yes:9". command('set signcolumn=yes:9') screen:expect([[ - {1:>>}XX{2: }{6: 1 }a | - XX{1:>>}{2: }{6: 2 }b | - XX{1:>>}WW{2: }{6: 3 }c | + {1:>>}{8:XX}{2: }{6: 1 }a | + {8:XX}{1:>>}{2: }{6: 2 }b | + {8:XX}{1:>>}WW{2: }{6: 3 }c | {2: }{6: 4 }^ | {0:~ }| {0:~ }| @@ -249,9 +249,9 @@ describe('Signs', function() -- a single line (same result as "auto:3"). command('set signcolumn=auto:4') screen:expect{grid=[[ - {1:>>}XX{2: }{6: 1 }a | - XX{1:>>}{2: }{6: 2 }b | - XX{1:>>}WW{6: 3 }c | + {1:>>}{8:XX}{2: }{6: 1 }a | + {8:XX}{1:>>}{2: }{6: 2 }b | + {8:XX}{1:>>}WW{6: 3 }c | {2: }{6: 4 }^ | {0:~ }| {0:~ }| @@ -267,8 +267,8 @@ describe('Signs', function() -- line deletion deletes signs. command('2d') screen:expect([[ - {1:>>}XX{2: }{6: 1 }a | - XX{1:>>}WW{6: 2 }^c | + {1:>>}{8:XX}{2: }{6: 1 }a | + {8:XX}{1:>>}WW{6: 2 }^c | {2: }{6: 3 } | {0:~ }| {0:~ }| diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua index 032baf6578..8342044b5e 100644 --- a/test/unit/viml/expressions/parser_spec.lua +++ b/test/unit/viml/expressions/parser_spec.lua @@ -52,6 +52,32 @@ local predefined_hl_defs = { QuickFixLine=true, Substitute=true, Whitespace=true, + Error=true, + Todo=true, + String=true, + Character=true, + Number=true, + Boolean=true, + Float=true, + Function=true, + Conditional=true, + Repeat=true, + Label=true, + Operator=true, + Keyword=true, + Exception=true, + Include=true, + Define=true, + Macro=true, + PreCondit=true, + StorageClass=true, + Structure=true, + Typedef=true, + Tag=true, + SpecialChar=true, + Delimiter=true, + SpecialComment=true, + Debug=true, -- From highlight_init_(dark|light) ColorColumn=true, @@ -83,8 +109,6 @@ local predefined_hl_defs = { Visual=true, WarningMsg=true, Normal=true, - - -- From syncolor.vim, if &background Comment=true, Constant=true, Special=true, @@ -94,36 +118,6 @@ local predefined_hl_defs = { Type=true, Underlined=true, Ignore=true, - - -- From syncolor.vim, below if &background - Error=true, - Todo=true, - - -- From syncolor.vim, links at the bottom - String=true, - Character=true, - Number=true, - Boolean=true, - Float=true, - Function=true, - Conditional=true, - Repeat=true, - Label=true, - Operator=true, - Keyword=true, - Exception=true, - Include=true, - Define=true, - Macro=true, - PreCondit=true, - StorageClass=true, - Structure=true, - Typedef=true, - Tag=true, - SpecialChar=true, - Delimiter=true, - SpecialComment=true, - Debug=true, } local nvim_hl_defs = {} |