aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/lsp.txt8
-rw-r--r--runtime/filetype.vim3
-rw-r--r--runtime/lua/vim/filetype.lua1
-rw-r--r--runtime/lua/vim/lsp/buf.lua44
-rw-r--r--src/nvim/getchar.c18
-rw-r--r--src/nvim/testdir/test_filetype.vim1
-rw-r--r--src/nvim/testdir/test_popup.vim15
-rw-r--r--test/functional/plugin/lsp_spec.lua44
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)