diff options
-rw-r--r-- | .github/workflows/api-docs.yml | 4 | ||||
-rw-r--r-- | runtime/doc/api.txt | 2 | ||||
-rw-r--r-- | runtime/doc/channel.txt | 5 | ||||
-rw-r--r-- | runtime/doc/diagnostic.txt | 107 | ||||
-rw-r--r-- | runtime/doc/help.txt | 20 | ||||
-rw-r--r-- | runtime/doc/lsp.txt | 18 | ||||
-rw-r--r-- | runtime/lua/vim/diagnostic.lua | 27 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 50 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/protocol.lua | 144 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 2 | ||||
-rw-r--r-- | src/nvim/api/extmark.c | 26 | ||||
-rw-r--r-- | src/nvim/api/keysets.lua | 1 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 5 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 5 | ||||
-rw-r--r-- | src/nvim/edit.c | 38 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 3 | ||||
-rw-r--r-- | src/nvim/screen.c | 4 | ||||
-rw-r--r-- | src/nvim/testdir/runtest.vim | 5 | ||||
-rw-r--r-- | src/nvim/testdir/test_prompt_buffer.vim | 80 | ||||
-rw-r--r-- | src/nvim/window.c | 65 | ||||
-rw-r--r-- | test/functional/api/extmark_spec.lua | 12 | ||||
-rw-r--r-- | test/functional/legacy/prompt_buffer_spec.lua | 87 | ||||
-rw-r--r-- | test/functional/lua/diagnostic_spec.lua | 40 |
23 files changed, 474 insertions, 276 deletions
diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index 413c2e90c6..ee72cf5f01 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -26,7 +26,9 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y doxygen python3 python3-msgpack luajit + sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y python3 luajit + conda install -c conda-forge doxygen=1.9.2 msgpack-python + echo "$CONDA/bin" >> $GITHUB_PATH - name: Setup git config run: | diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 482d8c198d..d2d010882e 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -2353,7 +2353,7 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {*opts}) |api-indexing| {opts} Optional parameters. • id : id of the extmark to edit. - • end_line : ending line of the mark, 0-based + • end_row : ending line of the mark, 0-based inclusive. • end_col : ending col of the mark, 0-based exclusive. diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt index 656bb10c45..5f376a600e 100644 --- a/runtime/doc/channel.txt +++ b/runtime/doc/channel.txt @@ -210,6 +210,11 @@ effective prompt text for a buffer, with |prompt_getprompt()|. The user can go to Normal mode and navigate through the buffer. This can be useful to see older output or copy text. +The CTRL-W key can be used to start a window command, such as CTRL-W w to +switch to the next window. This also works in Insert mode (use Shift-CTRL-W +to delete a word). When leaving the window Insert mode will be stopped. When +coming back to the prompt window Insert mode will be restored. + Any command that starts Insert mode, such as "a", "i", "A" and "I", will move the cursor to the last line. "A" will move to the end of the line, "I" to the start of the line. diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 9a65737dae..d02510a829 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -574,61 +574,64 @@ match({str}, {pat}, {groups}, {severity_map}, {defaults}) diagnostic |diagnostic-structure| or `nil` if {pat} fails to match {str}. -open_float({bufnr}, {opts}) *vim.diagnostic.open_float()* +open_float({opts}, {...}) *vim.diagnostic.open_float()* Show diagnostics in a floating window. Parameters: ~ - {bufnr} number|nil Buffer number. Defaults to the current - buffer. - {opts} table|nil Configuration table with the same keys - as |vim.lsp.util.open_floating_preview()| in - addition to the following: - • namespace: (number) Limit diagnostics to the - given namespace - • scope: (string, default "line") Show - diagnostics from the whole buffer ("buffer"), - the current cursor line ("line"), or the - current cursor position ("cursor"). - • pos: (number or table) If {scope} is "line" or - "cursor", use this position rather than the - cursor position. If a number, interpreted as a - line number; otherwise, a (row, col) tuple. - • severity_sort: (default false) Sort diagnostics - by severity. Overrides the setting from - |vim.diagnostic.config()|. - • severity: See |diagnostic-severity|. Overrides - the setting from |vim.diagnostic.config()|. - • header: (string or table) String to use as the - header for the floating window. If a table, it - is interpreted as a [text, hl_group] tuple. - Overrides the setting from - |vim.diagnostic.config()|. - • source: (string) Include the diagnostic source - in the message. One of "always" or "if_many". - Overrides the setting from - |vim.diagnostic.config()|. - • format: (function) A function that takes a - diagnostic as input and returns a string. The - return value is the text used to display the - diagnostic. Overrides the setting from - |vim.diagnostic.config()|. - • prefix: (function, string, or table) Prefix - each diagnostic in the floating window. If a - function, it must have the signature - (diagnostic, i, total) -> (string, string), - where {i} is the index of the diagnostic being - evaluated and {total} is the total number of - diagnostics displayed in the window. The - function should return a string which is - prepended to each diagnostic in the window as - well as an (optional) highlight group which - will be used to highlight the prefix. If - {prefix} is a table, it is interpreted as a - [text, hl_group] tuple as in |nvim_echo()|; - otherwise, if {prefix} is a string, it is - prepended to each diagnostic in the window with - no highlight. Overrides the setting from - |vim.diagnostic.config()|. + {opts} table|nil Configuration table with the same keys + as |vim.lsp.util.open_floating_preview()| in + addition to the following: + • bufnr: (number) Buffer number to show + diagnostics from. Defaults to the current + buffer. + • namespace: (number) Limit diagnostics to the + given namespace + • scope: (string, default "line") Show diagnostics + from the whole buffer ("buffer"), the current + cursor line ("line"), or the current cursor + position ("cursor"). Shorthand versions are also + accepted ("c" for "cursor", "l" for "line", "b" + for "buffer"). + • pos: (number or table) If {scope} is "line" or + "cursor", use this position rather than the + cursor position. If a number, interpreted as a + line number; otherwise, a (row, col) tuple. + • severity_sort: (default false) Sort diagnostics + by severity. Overrides the setting from + |vim.diagnostic.config()|. + • severity: See |diagnostic-severity|. Overrides + the setting from |vim.diagnostic.config()|. + • header: (string or table) String to use as the + header for the floating window. If a table, it + is interpreted as a [text, hl_group] tuple. + Overrides the setting from + |vim.diagnostic.config()|. + • source: (string) Include the diagnostic source + in the message. One of "always" or "if_many". + Overrides the setting from + |vim.diagnostic.config()|. + • format: (function) A function that takes a + diagnostic as input and returns a string. The + return value is the text used to display the + diagnostic. Overrides the setting from + |vim.diagnostic.config()|. + • prefix: (function, string, or table) Prefix each + diagnostic in the floating window. If a + function, it must have the signature + (diagnostic, i, total) -> (string, string), + where {i} is the index of the diagnostic being + evaluated and {total} is the total number of + diagnostics displayed in the window. The + function should return a string which is + prepended to each diagnostic in the window as + well as an (optional) highlight group which will + be used to highlight the prefix. If {prefix} is + a table, it is interpreted as a [text, hl_group] + tuple as in |nvim_echo()|; otherwise, if + {prefix} is a string, it is prepended to each + diagnostic in the window with no highlight. + Overrides the setting from + |vim.diagnostic.config()|. Return: ~ tuple ({float_bufnr}, {win_id}) diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt index 6416f49061..173d3c0cdf 100644 --- a/runtime/doc/help.txt +++ b/runtime/doc/help.txt @@ -93,6 +93,7 @@ REFERENCE MANUAL: These files explain every detail of Vim. *reference_toc* General subjects ~ |intro.txt| general introduction to Vim; notation used in help files +|nvim.txt| Transitioning from Vim |help.txt| overview and quick reference (this file) |helphelp.txt| about using the help files |index.txt| alphabetical index of all commands @@ -133,17 +134,19 @@ Advanced editing ~ |api.txt| Nvim API via RPC, Lua and VimL Special issues ~ -|testing.txt| testing Vim and Vim scripts -|print.txt| printing -|remote.txt| using Vim as a server or client +|testing.txt| testing Vim and Vim scripts +|print.txt| printing +|remote_plugin.txt| Nvim support for remote plugins Programming language support ~ |indent.txt| automatic indenting for C and other languages |lsp.txt| Language Server Protocol (LSP) |treesitter.txt| tree-sitter library for incremental parsing of buffers +|diagnostic.txt| Diagnostic framework |syntax.txt| syntax highlighting |filetype.txt| settings done specifically for a type of file |quickfix.txt| commands for a quick edit-compile-fix cycle +|provider.txt| Built-in remote plugin hosts |ft_ada.txt| Ada (the programming language) support |ft_ps1.txt| Filetype plugin for Windows PowerShell |ft_raku.txt| Filetype plugin for Raku @@ -164,6 +167,7 @@ GUI ~ Interfaces ~ |if_cscop.txt| using Cscope with Vim +|if_perl.txt| Perl interface |if_pyth.txt| Python interface |if_ruby.txt| Ruby interface |sign.txt| debugging signs @@ -171,6 +175,16 @@ Interfaces ~ Versions ~ |vim_diff.txt| Main differences between Nvim and Vim |vi_diff.txt| Main differences between Vim and Vi +|deprecated.txt| Deprecated items that have been or will be removed + +Other ~ +|terminal_emulator.txt| Terminal buffers +|term.txt| Terminal UI +|ui.txt| Nvim UI protocol +|channel.txt| Nvim asynchronous IO +|dev_style.txt| Nvim style guide +|job_control.txt| Spawn and control multiple processes + *standard-plugin-list* Standard plugins ~ |matchit.txt| Extended |%| matching diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 9bd304cbb4..11f9d62e69 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1909,14 +1909,14 @@ make_client_capabilities() *vim.lsp.protocol.resolve_capabilities()* resolve_capabilities({server_capabilities}) - `*` to match one or more characters in a path segment `?` to - match on one character in a path segment `**` to match any - number of path segments, including none `{}` to group - conditions (e.g. `**/*.{ts,js}` matches all TypeScript and - JavaScript files) `[]` to declare a range of characters to - match in a path segment (e.g., `example.[0-9]` to match on - `example.0` , `example.1` , …) `[!...]` to negate a range of - characters to match in a path segment (e.g., `example.[!0-9]` - to match on `example.a` , `example.b` , but not `example.0` ) + Creates a normalized object describing LSP server + capabilities. + + Parameters: ~ + {server_capabilities} table Table of capabilities + supported by the server + + Return: ~ + table Normalized table of capabilities vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index ac4081bb54..dfcac33f6d 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -520,8 +520,8 @@ local function diagnostic_move_pos(opts, pos) local float_opts = type(float) == "table" and float or {} vim.schedule(function() M.open_float( - vim.api.nvim_win_get_buf(win_id), vim.tbl_extend("keep", float_opts, { + bufnr = vim.api.nvim_win_get_buf(win_id), scope = "cursor", focus = false, }) @@ -1135,12 +1135,15 @@ end --- Show diagnostics in a floating window. --- ----@param bufnr number|nil Buffer number. Defaults to the current buffer. ---@param opts table|nil Configuration table with the same keys as --- |vim.lsp.util.open_floating_preview()| in addition to the following: +--- - bufnr: (number) Buffer number to show diagnostics from. +--- Defaults to the current buffer. --- - namespace: (number) Limit diagnostics to the given namespace --- - scope: (string, default "line") Show diagnostics from the whole buffer ("buffer"), --- the current cursor line ("line"), or the current cursor position ("cursor"). +--- Shorthand versions are also accepted ("c" for "cursor", "l" for "line", "b" +--- for "buffer"). --- - pos: (number or table) If {scope} is "line" or "cursor", use this position rather --- than the cursor position. If a number, interpreted as a line number; --- otherwise, a (row, col) tuple. @@ -1169,15 +1172,21 @@ end --- highlight. --- Overrides the setting from |vim.diagnostic.config()|. ---@return tuple ({float_bufnr}, {win_id}) -function M.open_float(bufnr, opts) - vim.validate { - bufnr = { bufnr, 'n', true }, - opts = { opts, 't', true }, - } +function M.open_float(opts, ...) + -- Support old (bufnr, opts) signature + local bufnr + if opts == nil or type(opts) == "number" then + bufnr = opts + opts = ... + else + vim.validate { + opts = { opts, 't', true }, + } + end opts = opts or {} - bufnr = get_bufnr(bufnr) - local scope = opts.scope or "line" + bufnr = get_bufnr(bufnr or opts.bufnr) + local scope = ({l = "line", c = "cursor", b = "buffer"})[opts.scope] or opts.scope or "line" local lnum, col if scope == "line" or scope == "cursor" then if not opts.pos then diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 7c807d9b6f..8850d25233 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -153,19 +153,6 @@ function M.get_namespace(client_id) return _client_namespaces[client_id] end ---- Save diagnostics to the current buffer. ---- ---- Handles saving diagnostics from multiple clients in the same buffer. ----@param diagnostics Diagnostic[] ----@param bufnr number ----@param client_id number ----@private -function M.save(diagnostics, bufnr, client_id) - local namespace = M.get_namespace(client_id) - vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) -end --- }}} - --- |lsp-handler| for the method "textDocument/publishDiagnostics" --- --- See |vim.diagnostic.config()| for configuration options. Handler-specific @@ -245,6 +232,23 @@ end -- Deprecated Functions {{{ + +--- Save diagnostics to the current buffer. +--- +---@deprecated Prefer |vim.diagnostic.set()| +--- +--- Handles saving diagnostics from multiple clients in the same buffer. +---@param diagnostics Diagnostic[] +---@param bufnr number +---@param client_id number +---@private +function M.save(diagnostics, bufnr, client_id) + vim.api.nvim_echo({{'vim.lsp.diagnostic.save is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + local namespace = M.get_namespace(client_id) + vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) +end +-- }}} + --- Get all diagnostics for clients --- ---@deprecated Prefer |vim.diagnostic.get()| @@ -253,6 +257,7 @@ end --- If nil, diagnostics of all clients are included. ---@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[]) function M.get_all(client_id) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get_all is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) local result = {} local namespace if client_id then @@ -274,6 +279,7 @@ end --- Else, return just the diagnostics associated with the client_id. ---@param predicate function|nil Optional function for filtering diagnostics function M.get(bufnr, client_id, predicate) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) predicate = predicate or function() return true end if client_id == nil then local all_diagnostics = {} @@ -335,6 +341,7 @@ end ---@param severity DiagnosticSeverity ---@param client_id number the client id function M.get_count(bufnr, severity, client_id) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get_count is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) severity = severity_lsp_to_vim(severity) local opts = { severity = severity } if client_id ~= nil then @@ -351,6 +358,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic function M.get_prev(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get_prev is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -368,6 +376,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic position function M.get_prev_pos(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get_prev_pos is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -384,6 +393,7 @@ end --- ---@param opts table See |vim.lsp.diagnostic.goto_next()| function M.goto_prev(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.goto_prev is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -401,6 +411,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic function M.get_next(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get_next is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -418,6 +429,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic position function M.get_next_pos(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get_next_pos is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -432,6 +444,7 @@ end --- ---@deprecated Prefer |vim.diagnostic.goto_next()| function M.goto_next(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.goto_next is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -455,6 +468,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_signs(diagnostics, bufnr, client_id, _, opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.set_signs is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -475,6 +489,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_underline(diagnostics, bufnr, client_id, _, opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.set_underline is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -496,6 +511,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.set_virtual_text is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -514,6 +530,7 @@ end ---@return an array of [text, hl_group] arrays. This can be passed directly to --- the {virt_text} option of |nvim_buf_set_extmark()|. function M.get_virtual_text_chunks_for_line(bufnr, _, line_diags, opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.get_virtual_text_chunks_for_line is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) return vim.diagnostic._get_virt_text_chunks(diagnostic_lsp_to_vim(line_diags, bufnr), opts) end @@ -531,6 +548,7 @@ end ---@param position table|nil The (0,0)-indexed position ---@return table {popup_bufnr, win_id} function M.show_position_diagnostics(opts, buf_nr, position) + vim.api.nvim_echo({{'vim.lsp.diagnostic.show_position_diagnostics is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) opts = opts or {} opts.scope = "cursor" opts.pos = position @@ -554,6 +572,7 @@ end ---@param client_id number|nil the client id ---@return table {popup_bufnr, win_id} function M.show_line_diagnostics(opts, buf_nr, line_nr, client_id) + vim.api.nvim_echo({{'vim.lsp.diagnostic.show_line_diagnostics is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) opts = opts or {} opts.scope = "line" opts.pos = line_nr @@ -577,6 +596,7 @@ end --- client. The default is to redraw diagnostics for all attached --- clients. function M.redraw(bufnr, client_id) + vim.api.nvim_echo({{'vim.lsp.diagnostic.redraw is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) bufnr = get_bufnr(bufnr) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) @@ -604,6 +624,7 @@ end --- - {workspace}: (boolean, default true) --- - Set the list with workspace diagnostics function M.set_qflist(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.set_qflist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -635,6 +656,7 @@ end --- - {workspace}: (boolean, default false) --- - Set the list with workspace diagnostics function M.set_loclist(opts) + vim.api.nvim_echo({{'vim.lsp.diagnostic.set_loclist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -662,6 +684,7 @@ end -- 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) + vim.api.nvim_echo({{'vim.lsp.diagnostic.disable is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.disable(bufnr, client.id) @@ -682,6 +705,7 @@ end --- client. The default is to enable diagnostics for all attached --- clients. function M.enable(bufnr, client_id) + vim.api.nvim_echo({{'vim.lsp.diagnostic.enable is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.enable(bufnr, client.id) diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index b3aa8b934f..86c9e2fd58 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -776,149 +776,9 @@ function protocol.make_client_capabilities() } end ---[=[ -export interface DocumentFilter { - --A language id, like `typescript`. - language?: string; - --A Uri [scheme](#Uri.scheme), like `file` or `untitled`. - scheme?: string; - --A glob pattern, like `*.{ts,js}`. - -- - --Glob patterns can have the following syntax: - --- `*` to match one or more characters in a path segment - --- `?` to match on one character in a path segment - --- `**` to match any number of path segments, including none - --- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) - --- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) - --- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) - pattern?: string; -} ---]=] - ---[[ ---Static registration options to be returned in the initialize request. -interface StaticRegistrationOptions { - --The id used to register the request. The id can be used to deregister - --the request again. See also Registration#id. - id?: string; -} - -export interface DocumentFilter { - --A language id, like `typescript`. - language?: string; - --A Uri [scheme](#Uri.scheme), like `file` or `untitled`. - scheme?: string; - --A glob pattern, like `*.{ts,js}`. - -- - --Glob patterns can have the following syntax: - --- `*` to match one or more characters in a path segment - --- `?` to match on one character in a path segment - --- `**` to match any number of path segments, including none - --- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files) - --- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) - --- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) - pattern?: string; -} -export type DocumentSelector = DocumentFilter[]; -export interface TextDocumentRegistrationOptions { - --A document selector to identify the scope of the registration. If set to null - --the document selector provided on the client side will be used. - documentSelector: DocumentSelector | null; -} - ---Code Action options. -export interface CodeActionOptions { - --CodeActionKinds that this server may return. - -- - --The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server - --may list out every specific kind they provide. - codeActionKinds?: CodeActionKind[]; -} - -interface ServerCapabilities { - --Defines how text documents are synced. Is either a detailed structure defining each notification or - --for backwards compatibility the TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`. - textDocumentSync?: TextDocumentSyncOptions | number; - --The server provides hover support. - hoverProvider?: boolean; - --The server provides completion support. - completionProvider?: CompletionOptions; - --The server provides signature help support. - signatureHelpProvider?: SignatureHelpOptions; - --The server provides goto definition support. - definitionProvider?: boolean; - --The server provides Goto Type Definition support. - -- - --Since 3.6.0 - typeDefinitionProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions); - --The server provides Goto Implementation support. - -- - --Since 3.6.0 - implementationProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions); - --The server provides find references support. - referencesProvider?: boolean; - --The server provides document highlight support. - documentHighlightProvider?: boolean; - --The server provides document symbol support. - documentSymbolProvider?: boolean; - --The server provides workspace symbol support. - workspaceSymbolProvider?: boolean; - --The server provides code actions. The `CodeActionOptions` return type is only - --valid if the client signals code action literal support via the property - --`textDocument.codeAction.codeActionLiteralSupport`. - codeActionProvider?: boolean | CodeActionOptions; - --The server provides code lens. - codeLensProvider?: CodeLensOptions; - --The server provides document formatting. - documentFormattingProvider?: boolean; - --The server provides document range formatting. - documentRangeFormattingProvider?: boolean; - --The server provides document formatting on typing. - documentOnTypeFormattingProvider?: DocumentOnTypeFormattingOptions; - --The server provides rename support. RenameOptions may only be - --specified if the client states that it supports - --`prepareSupport` in its initial `initialize` request. - renameProvider?: boolean | RenameOptions; - --The server provides document link support. - documentLinkProvider?: DocumentLinkOptions; - --The server provides color provider support. - -- - --Since 3.6.0 - colorProvider?: boolean | ColorProviderOptions | (ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions); - --The server provides folding provider support. - -- - --Since 3.10.0 - foldingRangeProvider?: boolean | FoldingRangeProviderOptions | (FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions); - --The server provides go to declaration support. - -- - --Since 3.14.0 - declarationProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions); - --The server provides execute command support. - executeCommandProvider?: ExecuteCommandOptions; - --Workspace specific server capabilities - workspace?: { - --The server supports workspace folder. - -- - --Since 3.6.0 - workspaceFolders?: { - * The server has support for workspace folders - supported?: boolean; - * Whether the server wants to receive workspace folder - * change notifications. - * - * If a strings is provided the string is treated as a ID - * under which the notification is registered on the client - * side. The ID can be used to unregister for these events - * using the `client/unregisterCapability` request. - changeNotifications?: string | boolean; - } - } - --Experimental server capabilities. - experimental?: any; -} ---]] - --- Creates a normalized object describing LSP server capabilities. +---@param server_capabilities table Table of capabilities supported by the server +---@return table Normalized table of capabilities function protocol.resolve_capabilities(server_capabilities) local general_properties = {} local text_document_sync_properties diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 059e66c53a..a3a91a34f7 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1531,6 +1531,7 @@ end --- ---@param items (table) list of items function M.set_loclist(items, win_id) + vim.api.nvim_echo({{'vim.lsp.util.set_loclist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) vim.fn.setloclist(win_id or 0, {}, ' ', { title = 'Language Server'; items = items; @@ -1544,6 +1545,7 @@ end --- ---@param items (table) list of items function M.set_qflist(items) + vim.api.nvim_echo({{'vim.lsp.util.set_qflist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) vim.fn.setqflist({}, ' ', { title = 'Language Server'; items = items; diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 6e25e627b9..742b953c2a 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -339,7 +339,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// @param col Column where to place the mark, 0-based. |api-indexing| /// @param opts Optional parameters. /// - id : id of the extmark to edit. -/// - end_line : ending line of the mark, 0-based inclusive. +/// - end_row : ending line of the mark, 0-based inclusive. /// - end_col : ending col of the mark, 0-based exclusive. /// - hl_group : name of the highlight group used to highlight /// this mark. @@ -431,16 +431,26 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer } int line2 = -1; - if (opts->end_line.type == kObjectTypeInteger) { - Integer val = opts->end_line.data.integer; + + // For backward compatibility we support "end_line" as an alias for "end_row" + if (HAS_KEY(opts->end_line)) { + if (HAS_KEY(opts->end_row)) { + api_set_error(err, kErrorTypeValidation, "cannot use both end_row and end_line"); + goto error; + } + opts->end_row = opts->end_line; + } + + if (opts->end_row.type == kObjectTypeInteger) { + Integer val = opts->end_row.data.integer; if (val < 0 || val > buf->b_ml.ml_line_count) { - api_set_error(err, kErrorTypeValidation, "end_line value outside range"); + api_set_error(err, kErrorTypeValidation, "end_row value outside range"); goto error; } else { line2 = (int)val; } - } else if (HAS_KEY(opts->end_line)) { - api_set_error(err, kErrorTypeValidation, "end_line is not an integer"); + } else if (HAS_KEY(opts->end_row)) { + api_set_error(err, kErrorTypeValidation, "end_row is not an integer"); goto error; } @@ -571,10 +581,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer OPTION_TO_BOOL(right_gravity, right_gravity, true); // Only error out if they try to set end_right_gravity without - // setting end_col or end_line + // setting end_col or end_row if (line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)) { api_set_error(err, kErrorTypeValidation, - "cannot set end_right_gravity without setting end_line or end_col"); + "cannot set end_right_gravity without setting end_row or end_col"); goto error; } diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index e956a54dbc..f3e7f2f1dc 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -5,6 +5,7 @@ return { set_extmark = { "id"; "end_line"; + "end_row"; "end_col"; "hl_group"; "virt_text"; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 36179b1fab..4f7c320129 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -842,7 +842,7 @@ void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err) for (uint32_t i = 0; i < kv_size(hl_msg); i++) { HlMessageChunk chunk = kv_A(hl_msg, i); msg_multiline_attr((const char *)chunk.text.data, chunk.attr, - false, &need_clear); + true, &need_clear); } if (history) { msg_ext_set_kind("echomsg"); @@ -1842,6 +1842,9 @@ static void write_msg(String message, bool to_err) ++no_wait_return; for (uint32_t i = 0; i < message.size; i++) { + if (got_int) { + break; + } if (to_err) { PUSH_CHAR(i, err_pos, err_line_buf, emsg); } else { diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 490fe5a0ac..9044657358 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1213,10 +1213,13 @@ win_found: // Hmm, original window disappeared. Just use the first one. curwin = firstwin; } + curbuf = curwin->w_buffer; + // May need to restore insert mode for a prompt buffer. + entering_window(curwin); + prevwin = win_find_by_handle(aco->save_prevwin_handle); vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab - curbuf = curwin->w_buffer; xfree(globaldir); globaldir = aco->globaldir; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index fe69da7fcb..9bfb8a9d4a 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -227,6 +227,7 @@ typedef struct insert_state { cmdarg_T *ca; int mincol; int cmdchar; + int cmdchar_todo; // cmdchar to handle once in init_prompt int startln; long count; int c; @@ -290,6 +291,7 @@ static void insert_enter(InsertState *s) s->did_backspace = true; s->old_topfill = -1; s->replaceState = REPLACE; + s->cmdchar_todo = s->cmdchar; // Remember whether editing was restarted after CTRL-O did_restart_edit = restart_edit; // sleep before redrawing, needed for "CTRL-O :" that results in an @@ -585,7 +587,8 @@ static int insert_check(VimState *state) } if (bt_prompt(curbuf)) { - init_prompt(s->cmdchar); + init_prompt(s->cmdchar_todo); + s->cmdchar_todo = NUL; } // If we inserted a character at the last position of the last line in the @@ -655,10 +658,17 @@ static int insert_check(VimState *state) static int insert_execute(VimState *state, int key) { + InsertState *const s = (InsertState *)state; + if (stop_insert_mode) { + // Insert mode ended, possibly from a callback. + s->count = 0; + s->nomove = true; + return 0; + } + if (key == K_IGNORE || key == K_NOP) { return -1; // get another key } - InsertState *s = (InsertState *)state; s->c = key; // Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V. @@ -984,6 +994,15 @@ static int insert_handle_key(InsertState *s) break; case Ctrl_W: // delete word before the cursor + if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0) { + // In a prompt window CTRL-W is used for window commands. + // Use Shift-CTRL-W to delete a word. + stuffcharReadbuff(Ctrl_W); + restart_edit = 'A'; + s->nomove = true; + s->count = 0; + return 0; + } s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space); auto_format(false, true); break; @@ -1653,10 +1672,21 @@ static void init_prompt(int cmdchar_todo) coladvance(MAXCOL); changed_bytes(curbuf->b_ml.ml_line_count, 0); } + + // Insert always starts after the prompt, allow editing text after it. + if (Insstart_orig.lnum != curwin->w_cursor.lnum || Insstart_orig.col != (colnr_T)STRLEN(prompt)) { + Insstart.lnum = curwin->w_cursor.lnum; + Insstart.col = STRLEN(prompt); + Insstart_orig = Insstart; + Insstart_textlen = Insstart.col; + Insstart_blank_vcol = MAXCOL; + arrow_used = false; + } + if (cmdchar_todo == 'A') { coladvance(MAXCOL); } - if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) { + if (curwin->w_cursor.col < (colnr_T)STRLEN(prompt)) { curwin->w_cursor.col = STRLEN(prompt); } // Make sure the cursor is in a valid position. @@ -8241,7 +8271,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) || (!revins_on && ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) || (!can_bs(BS_START) - && (arrow_used + && ((arrow_used && !bt_prompt(curbuf)) || (curwin->w_cursor.lnum == Insstart_orig.lnum && curwin->w_cursor.col <= Insstart_orig.col))) || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 6a8b70a158..a899ca63ac 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -521,6 +521,9 @@ static void nlua_print_event(void **argv) const size_t len = (size_t)(intptr_t)argv[1]-1; // exclude final NUL for (size_t i = 0; i < len;) { + if (got_int) { + break; + } const size_t start = i; while (i < len) { switch (str[i]) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 4146ae0fe3..a666b9c8b0 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -6932,7 +6932,7 @@ int showmode(void) do_mode = ((p_smd && msg_silent == 0) && ((State & TERM_FOCUS) || (State & INSERT) - || restart_edit + || restart_edit != NUL || VIsual_active)); if (do_mode || reg_recording != 0) { // Don't show mode right now, when not redrawing or inside a mapping. @@ -7012,7 +7012,7 @@ int showmode(void) } msg_puts_attr(_(" INSERT"), attr); } else if (restart_edit == 'I' || restart_edit == 'i' - || restart_edit == 'a') { + || restart_edit == 'a' || restart_edit == 'A') { msg_puts_attr(_(" (insert)"), attr); } else if (restart_edit == 'R') { msg_puts_attr(_(" (replace)"), attr); diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 49993c03aa..ab047fd2a8 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -197,7 +197,12 @@ func RunTheTest(test) " Close any extra tab pages and windows and make the current one not modified. while tabpagenr('$') > 1 + let winid = win_getid() quit! + if winid == win_getid() + echoerr 'Could not quit window' + break + endif endwhile while 1 diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim index c59a00afcc..8f94a8572b 100644 --- a/src/nvim/testdir/test_prompt_buffer.vim +++ b/src/nvim/testdir/test_prompt_buffer.vim @@ -41,6 +41,10 @@ func WriteScript(name) \ ' set nomodified', \ 'endfunc', \ '', + \ 'func SwitchWindows()', + \ ' call timer_start(0, {-> execute("wincmd p|wincmd p", "")})', + \ 'endfunc', + \ '', \ 'call setline(1, "other buffer")', \ 'set nomodified', \ 'new', @@ -89,9 +93,12 @@ func Test_prompt_editing() call term_sendkeys(buf, left . left . left . bs . '-') call WaitForAssert({-> assert_equal('cmd: -hel', term_getline(buf, 1))}) + call term_sendkeys(buf, "\<C-O>lz") + call WaitForAssert({-> assert_equal('cmd: -hzel', term_getline(buf, 1))}) + let end = "\<End>" call term_sendkeys(buf, end . "x") - call WaitForAssert({-> assert_equal('cmd: -helx', term_getline(buf, 1))}) + call WaitForAssert({-> assert_equal('cmd: -hzelx', term_getline(buf, 1))}) call term_sendkeys(buf, "\<C-U>exit\<CR>") call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))}) @@ -100,6 +107,28 @@ func Test_prompt_editing() call delete(scriptName) endfunc +func Test_prompt_switch_windows() + throw 'skipped: TODO' + call CanTestPromptBuffer() + let scriptName = 'XpromptSwitchWindows' + call WriteScript(scriptName) + + let buf = RunVimInTerminal('-S ' . scriptName, {'rows': 12}) + call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))}) + call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))}) + + call term_sendkeys(buf, "\<C-O>:call SwitchWindows()\<CR>") + call term_wait(buf, 50) + call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))}) + + call term_sendkeys(buf, "\<Esc>") + call term_wait(buf, 50) + call WaitForAssert({-> assert_match('^ *$', term_getline(buf, 12))}) + + call StopVimInTerminal(buf) + call delete(scriptName) +endfunc + func Test_prompt_garbage_collect() func MyPromptCallback(x, text) " NOP @@ -126,6 +155,14 @@ func Test_prompt_garbage_collect() bwipe! endfunc +func Test_prompt_backspace() + new + set buftype=prompt + call feedkeys("A123456\<Left>\<BS>\<Esc>", 'xt') + call assert_equal('% 12346', getline(1)) + bwipe! +endfunc + " Test for editing the prompt buffer func Test_prompt_buffer_edit() new @@ -145,10 +182,9 @@ func Test_prompt_buffer_edit() call assert_beeps("normal! \<C-X>") " pressing CTRL-W in the prompt buffer should trigger the window commands call assert_equal(1, winnr()) - " In Nvim, CTRL-W commands aren't usable from insert mode in a prompt buffer - " exe "normal A\<C-W>\<C-W>" - " call assert_equal(2, winnr()) - " wincmd w + exe "normal A\<C-W>\<C-W>" + call assert_equal(2, winnr()) + wincmd w close! call assert_equal(0, prompt_setprompt([], '')) endfunc @@ -187,4 +223,38 @@ func Test_prompt_buffer_getbufinfo() %bwipe! endfunc +function! Test_prompt_while_writing_to_hidden_buffer() + throw 'skipped: TODO' + call CanTestPromptBuffer() + CheckUnix + + " Make a job continuously write to a hidden buffer, check that the prompt + " buffer is not affected. + let scriptName = 'XpromptscriptHiddenBuf' + let script =<< trim END + set buftype=prompt + call prompt_setprompt( bufnr(), 'cmd:' ) + let job = job_start(['/bin/sh', '-c', + \ 'while true; + \ do echo line; + \ sleep 0.1; + \ done'], #{out_io: 'buffer', out_name: ''}) + startinsert + END + eval script->writefile(scriptName) + + let buf = RunVimInTerminal('-S ' .. scriptName, {}) + call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))}) + + call term_sendkeys(buf, 'test') + call WaitForAssert({-> assert_equal('cmd:test', term_getline(buf, 1))}) + call term_sendkeys(buf, 'test') + call WaitForAssert({-> assert_equal('cmd:testtest', term_getline(buf, 1))}) + call term_sendkeys(buf, 'test') + call WaitForAssert({-> assert_equal('cmd:testtesttest', term_getline(buf, 1))}) + + call StopVimInTerminal(buf) + call delete(scriptName) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/window.c b/src/nvim/window.c index 3e6e42dec2..be963d8374 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2229,6 +2229,54 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int } } +static void leaving_window(win_T *const win) + FUNC_ATTR_NONNULL_ALL +{ + // Only matters for a prompt window. + if (!bt_prompt(win->w_buffer)) { + return; + } + + // When leaving a prompt window stop Insert mode and perhaps restart + // it when entering that window again. + win->w_buffer->b_prompt_insert = restart_edit; + if (restart_edit != NUL && mode_displayed) { + clear_cmdline = true; // unshow mode later + } + restart_edit = NUL; + + // When leaving the window (or closing the window) was done from a + // callback we need to break out of the Insert mode loop and restart Insert + // mode when entering the window again. + if (State & INSERT) { + stop_insert_mode = true; + if (win->w_buffer->b_prompt_insert == NUL) { + win->w_buffer->b_prompt_insert = 'A'; + } + } +} + +void entering_window(win_T *const win) + FUNC_ATTR_NONNULL_ALL +{ + // Only matters for a prompt window. + if (!bt_prompt(win->w_buffer)) { + return; + } + + // When switching to a prompt buffer that was in Insert mode, don't stop + // Insert mode, it may have been set in leaving_window(). + if (win->w_buffer->b_prompt_insert != NUL) { + stop_insert_mode = false; + } + + // When entering the prompt window restart Insert mode if we were in Insert + // mode when we left it and not already in Insert mode. + if ((State & INSERT) == 0) { + restart_edit = win->w_buffer->b_prompt_insert; + } +} + /// Closes all windows for buffer `buf`. /// /// @param keep_curwin don't close `curwin` @@ -2367,6 +2415,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev shell_new_rows(); } } + entering_window(curwin); // Since goto_tabpage_tp above did not trigger *Enter autocommands, do // that now. @@ -2434,10 +2483,10 @@ int win_close(win_T *win, bool free_buf) } if (win == curwin) { - /* - * Guess which window is going to be the new current window. - * This may change because of the autocommands (sigh). - */ + leaving_window(curwin); + + // Guess which window is going to be the new current window. + // This may change because of the autocommands (sigh). if (!win->w_floating) { wp = frame2win(win_altframe(win, NULL)); } else { @@ -3801,6 +3850,8 @@ int win_new_tabpage(int after, char_u *filename) lastused_tabpage = old_curtab; + entering_window(curwin); + apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf); apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf); @@ -3956,6 +4007,7 @@ static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds) { tabpage_T *tp = curtab; + leaving_window(curwin); reset_VIsual_and_resel(); // stop Visual mode if (trigger_leave_autocmds) { if (new_curbuf != curbuf) { @@ -4478,6 +4530,10 @@ static void win_enter_ext(win_T *const wp, const int flags) return; } + if (!curwin_invalid) { + leaving_window(curwin); + } + if (!curwin_invalid && (flags & WEE_TRIGGER_LEAVE_AUTOCMDS)) { // Be careful: If autocommands delete the window, return now. if (wp->w_buffer != curbuf) { @@ -4525,6 +4581,7 @@ static void win_enter_ext(win_T *const wp, const int flags) fix_current_dir(); + entering_window(curwin); // Careful: autocommands may close the window and make "wp" invalid if (flags & WEE_TRIGGER_NEW_AUTOCMDS) { apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 50b4b85d2a..45a01be620 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -104,10 +104,10 @@ describe('API/extmarks', function() it("can end extranges past final newline using end_col = 0", function() set_extmark(ns, marks[1], 0, 0, { end_col = 0, - end_line = 1 + end_row = 1 }) eq("end_col value outside range", - pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_line = 1 })) + pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 })) end) it('adds, updates and deletes marks', function() @@ -1424,6 +1424,14 @@ describe('API/extmarks', function() eq({ {1, 0, 0}, {2, 0, 8} }, meths.buf_get_extmarks(0, ns, 0, -1, {})) end) + + it('can accept "end_row" or "end_line" #16548', function() + set_extmark(ns, marks[1], 0, 0, { + end_col = 0, + end_line = 1 + }) + eq({ {1, 0, 0, { end_col = 0, end_row = 1 }} }, get_extmarks(ns, 0, -1, {details=true})) + end) end) describe('Extmarks buffer api with many marks', function() diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 513be807be..47eca19de3 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -1,9 +1,12 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local feed= helpers.feed +local feed = helpers.feed local source = helpers.source local clear = helpers.clear local feed_command = helpers.feed_command +local poke_eventloop = helpers.poke_eventloop +local meths = helpers.meths +local eq = helpers.eq describe('prompt buffer', function() local screen @@ -28,12 +31,17 @@ describe('prompt buffer', function() func TimerFunc(text) call append(line("$") - 1, 'Result: "' . a:text .'"') endfunc + + func SwitchWindows() + call timer_start(0, {-> execute("wincmd p|wincmd p", "")}) + endfunc ]]) feed_command("set noshowmode | set laststatus=0") feed_command("call setline(1, 'other buffer')") feed_command("new") feed_command("set buftype=prompt") feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))") + feed_command("eval bufnr('')->prompt_setprompt('cmd: ')") end) after_each(function() @@ -56,10 +64,10 @@ describe('prompt buffer', function() feed("i") feed("hello\n") screen:expect([[ - % hello | + cmd: hello | Command: "hello" | Result: "hello" | - % ^ | + cmd: ^ | [Prompt] [+] | other buffer | ~ | @@ -98,7 +106,7 @@ describe('prompt buffer', function() feed("i") feed("hello<BS><BS>") screen:expect([[ - % hel^ | + cmd: hel^ | ~ | ~ | ~ | @@ -111,7 +119,20 @@ describe('prompt buffer', function() ]]) feed("<Left><Left><Left><BS>-") screen:expect([[ - % -^hel | + cmd: -^hel | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + feed("<C-O>lz") + screen:expect([[ + cmd: -hz^el | ~ | ~ | ~ | @@ -124,7 +145,7 @@ describe('prompt buffer', function() ]]) feed("<End>x") screen:expect([[ - % -helx^ | + cmd: -hzelx^ | ~ | ~ | ~ | @@ -150,4 +171,58 @@ describe('prompt buffer', function() ]]) end) + it('switch windows', function() + feed_command("set showmode") + feed("i") + screen:expect([[ + cmd: ^ | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + -- INSERT -- | + ]]) + feed("<C-O>:call SwitchWindows()<CR>") + poke_eventloop() + screen:expect([[ + cmd: ^ | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + -- INSERT -- | + ]]) + feed("<Esc>") + poke_eventloop() + screen:expect([[ + cmd:^ | + ~ | + ~ | + ~ | + [Prompt] [+] | + other buffer | + ~ | + ~ | + ~ | + | + ]]) + end) + + it('keeps insert mode after aucmd_restbuf in callback', function() + source [[ + let s:buf = nvim_create_buf(1, 1) + call timer_start(0, {-> nvim_buf_set_lines(s:buf, -1, -1, 0, ['walrus'])}) + startinsert + ]] + poke_eventloop() + eq({ mode = "i", blocking = false }, meths.get_mode()) + end) end) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index eeb9316b06..a88da63e90 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1343,7 +1343,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = "We're no strangers to love..."}) + local float_bufnr, winnr = vim.diagnostic.open_float({header = "We're no strangers to love..."}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1355,7 +1355,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = {'You know the rules', 'Search'}}) + local float_bufnr, winnr = vim.diagnostic.open_float({header = {'You know the rules', 'Search'}}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1370,7 +1370,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false, scope="buffer"}) + local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope="buffer"}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1387,7 +1387,7 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) vim.api.nvim_win_set_cursor(0, {2, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false}) + local float_bufnr, winnr = vim.diagnostic.open_float({header=false}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1402,7 +1402,7 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, pos=1}) + local float_bufnr, winnr = vim.diagnostic.open_float({header=false, pos=1}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1419,7 +1419,7 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) vim.api.nvim_win_set_cursor(0, {2, 2}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, scope="cursor"}) + local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor"}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1434,7 +1434,7 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, scope="cursor", pos={1,3}}) + local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={1,3}}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1449,7 +1449,7 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) vim.api.nvim_win_set_cursor(0, {1, 1}) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header=false, scope="cursor", pos={0,first_line_len}}) + local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={0,first_line_len}}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1665,7 +1665,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false, scope = "buffer"}) + local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1678,7 +1678,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, {header = false, scope = "buffer", prefix = ""}) + local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer", prefix = ""}) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines @@ -1691,7 +1691,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, prefix = function(_, i, total) -- Only show a number if there is more than one diagnostic @@ -1712,7 +1712,7 @@ describe('vim.diagnostic', function() } vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - local float_bufnr, winnr = vim.diagnostic.open_float(0, { + local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, prefix = function(_, i, total) -- Only show a number if there is more than one diagnostic @@ -1728,7 +1728,21 @@ describe('vim.diagnostic', function() ]]) eq("Error executing lua: .../diagnostic.lua:0: prefix: expected 'string' or 'table' or 'function', got 42", - pcall_err(exec_lua, [[ vim.diagnostic.open_float(0, { prefix = 42 }) ]])) + pcall_err(exec_lua, [[ vim.diagnostic.open_float({ prefix = 42 }) ]])) + end) + + it('works with the old signature', function() + eq({'1. Syntax error'}, exec_lua [[ + local diagnostics = { + make_error("Syntax error", 0, 1, 0, 3), + } + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false }) + local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) + vim.api.nvim_win_close(winnr, true) + return lines + ]]) end) end) |