diff options
-rw-r--r-- | runtime/doc/lsp.txt | 8 | ||||
-rw-r--r-- | runtime/filetype.vim | 3 | ||||
-rw-r--r-- | runtime/lua/vim/filetype.lua | 1 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 44 | ||||
-rw-r--r-- | src/nvim/getchar.c | 18 | ||||
-rw-r--r-- | src/nvim/testdir/test_filetype.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_popup.vim | 15 | ||||
-rw-r--r-- | test/functional/plugin/lsp_spec.lua | 44 |
8 files changed, 118 insertions, 16 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index d5ee959c36..f55c959a03 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1060,9 +1060,8 @@ format({options}) *vim.lsp.buf.format()* See also: ~ https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting • timeout_ms (integer|nil, default 1000): Time in - milliseconds to block for formatting requests. - Formatting requests are current synchronous to prevent - editing of the buffer. + milliseconds to block for formatting requests. No effect + if async=true • bufnr (number|nil): Restrict formatting to the clients attached to the given buffer, defaults to the current buffer (0). @@ -1081,6 +1080,9 @@ format({options}) *vim.lsp.buf.format()* end } < + • async boolean|nil If true the method won't block. + Defaults to false. Editing the buffer while formatting + asynchronous can lead to unexpected changes. • id (number|nil): Restrict formatting to the client with ID (client.id) matching this field. • name (string|nil): Restrict formatting to the client diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 28ca09e57d..7337647b03 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -715,6 +715,9 @@ au BufNewFile,BufRead *.git/* " Gkrellmrc au BufNewFile,BufRead gkrellmrc,gkrellmrc_? setf gkrellmrc +" Gleam +au BufNewFile,BufRead *.gleam setf gleam + " GLSL au BufNewFile,BufRead *.glsl setf glsl diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 1297ef6241..2a34fec7f2 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -241,6 +241,7 @@ local extension = { gmi = "gemtext", gemini = "gemtext", gift = "gift", + gleam = "gleam", glsl = "glsl", gpi = "gnuplot", gnuplot = "gnuplot", diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 59682e8a0a..aabafc422f 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -152,8 +152,7 @@ end --- automatically derived from the current Neovim options. --- @see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting --- - timeout_ms (integer|nil, default 1000): ---- Time in milliseconds to block for formatting requests. Formatting requests are current ---- synchronous to prevent editing of the buffer. +--- Time in milliseconds to block for formatting requests. No effect if async=true --- - bufnr (number|nil): --- Restrict formatting to the clients attached to the given buffer, defaults to the current --- buffer (0). @@ -174,6 +173,11 @@ end --- } --- </pre> --- +--- - async boolean|nil +--- If true the method won't block. Defaults to false. +--- Editing the buffer while formatting asynchronous can lead to unexpected +--- changes. +--- --- - id (number|nil): --- Restrict formatting to the client with ID (client.id) matching this field. --- - name (string|nil): @@ -207,14 +211,30 @@ function M.format(options) vim.notify("[LSP] Format request failed, no matching language servers.") end - local timeout_ms = options.timeout_ms or 1000 - for _, client in pairs(clients) do - local params = util.make_formatting_params(options.formatting_options) - local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) - if result and result.result then - util.apply_text_edits(result.result, bufnr, client.offset_encoding) - elseif err then - vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + if options.async then + local do_format + do_format = function(idx, client) + if not client then + return + end + local params = util.make_formatting_params(options.formatting_options) + client.request("textDocument/formatting", params, function(...) + local handler = client.handlers['textDocument/formatting'] or vim.lsp.handlers['textDocument/formatting'] + handler(...) + do_format(next(clients, idx)) + end, bufnr) + end + do_format(next(clients)) + else + local timeout_ms = options.timeout_ms or 1000 + for _, client in pairs(clients) do + local params = util.make_formatting_params(options.formatting_options) + local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) + if result and result.result then + util.apply_text_edits(result.result, bufnr, client.offset_encoding) + elseif err then + vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + end end end end @@ -227,6 +247,10 @@ end -- ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting function M.formatting(options) + vim.notify_once( + 'vim.lsp.buf.formatting is deprecated. Use vim.lsp.buf.format { async = true } instead', + vim.log.levels.WARN + ) local params = util.make_formatting_params(options) local bufnr = vim.api.nvim_get_current_buf() select_client('textDocument/formatting', function(client) diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 7d06164c89..6dd6c51e8f 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1768,6 +1768,20 @@ static int put_string_in_typebuf(int offset, int slen, char_u *string, int new_s return OK; } +/// Check if the bytes at the start of the typeahead buffer are a character used +/// in Insert mode completion. This includes the form with a CTRL modifier. +static bool at_ins_compl_key(void) +{ + char_u *p = typebuf.tb_buf + typebuf.tb_off; + int c = *p; + + if (typebuf.tb_len > 3 && c == K_SPECIAL && p[1] == KS_MODIFIER && (p[2] & MOD_MASK_CTRL)) { + c = p[3] & 0x1f; + } + return (ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c)) + || ((compl_cont_status & CONT_LOCAL) && (c == Ctrl_N || c == Ctrl_P)); +} + /// Check if typebuf.tb_buf[] contains a modifer plus key that can be changed /// into just a key, apply that. /// Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off + "max_offset"]. @@ -1870,9 +1884,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) && !(State == HITRETURN && (tb_c1 == CAR || tb_c1 == ' ')) && State != ASKMORE && State != CONFIRM - && !((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(tb_c1)) - || ((compl_cont_status & CONT_LOCAL) - && (tb_c1 == Ctrl_N || tb_c1 == Ctrl_P)))) { + && !at_ins_compl_key()) { if (tb_c1 == K_SPECIAL) { nolmaplen = 2; } else { diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 6872eb3bb7..6ae957da70 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -211,6 +211,7 @@ let s:filename_checks = { \ 'gitrebase': ['git-rebase-todo'], \ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'], \ 'gkrellmrc': ['gkrellmrc', 'gkrellmrc_x'], + \ 'gleam': ['file.gleam'], \ 'glsl': ['file.glsl'], \ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'], \ 'gnuplot': ['file.gpi', '.gnuplot'], diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index eb367cfe5c..9a31f61582 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -325,6 +325,21 @@ func Test_compl_vim_cmds_after_register_expr() bwipe! endfunc +func Test_compl_ignore_mappings() + call setline(1, ['foo', 'bar', 'baz', 'foobar']) + inoremap <C-P> (C-P) + inoremap <C-N> (C-N) + normal! G + call feedkeys("o\<C-X>\<C-N>\<C-N>\<C-N>\<C-P>\<C-N>\<C-Y>", 'tx') + call assert_equal('baz', getline('.')) + " Also test with unsimplified keys + call feedkeys("o\<C-X>\<*C-N>\<*C-N>\<*C-N>\<*C-P>\<*C-N>\<C-Y>", 'tx') + call assert_equal('baz', getline('.')) + iunmap <C-P> + iunmap <C-N> + bwipe! +endfunc + func DummyCompleteOne(findstart, base) if a:findstart return 0 diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 6e28946cc4..be717cf724 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2833,5 +2833,49 @@ describe('LSP', function() end, } end) + it('Can format async', function() + local expected_handlers = { + {NIL, {}, {method="shutdown", client_id=1}}; + {NIL, {}, {method="start", client_id=1}}; + } + local client + test_rpc_server { + test_name = "basic_formatting", + on_init = function(c) + client = c + end, + on_handler = function(_, _, ctx) + table.remove(expected_handlers) + if ctx.method == "start" then + local result = exec_lua([[ + local bufnr = vim.api.nvim_get_current_buf() + vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) + + local notify_msg + local notify = vim.notify + vim.notify = function(msg, log_level) + notify_msg = msg + end + + local handler = vim.lsp.handlers['textDocument/formatting'] + local handler_called = false + vim.lsp.handlers['textDocument/formatting'] = function(...) + handler_called = true + end + + vim.lsp.buf.format({ bufnr = bufnr, async = true }) + vim.wait(1000, function() return handler_called end) + + vim.notify = notify + vim.lsp.handlers['textDocument/formatting'] = handler + return {notify = notify_msg, handler_called = handler_called} + ]]) + eq({handler_called=true}, result) + elseif ctx.method == "shutdown" then + client.stop() + end + end, + } + end) end) end) |