Compare commits

...

5 Commits

Author SHA1 Message Date
marvim
38073747ae docs: update version.c 2025-09-01 03:34:55 +00:00
github-actions[bot]
c6bfc203f1 docs: update version.c #35484
vim-patch:8.1.1083: MS-Windows: hang when opening a file on network share
vim-patch:8.1.1527: when moving popup window over the cmdline it is not redrawn
vim-patch:8.1.1550: when a popup has left padding text may be cut off
vim-patch:8.1.1562: popup window not always redrawn after popup_setoptions()
vim-patch:8.1.1575: callbacks may be garbage collected
vim-patch:8.1.1596: when resizing the screen may draw popup in wrong position
vim-patch:8.1.1602: popup window cannot overflow on the left or right
vim-patch:8.1.1615: crash when passing buffer number to popup_create()
vim-patch:8.1.1617: no test for popup window with mask and position fixed
vim-patch:8.1.1620: no test for popup window with border and mask
vim-patch:8.1.1622: wrong width if displaying a lot of lines in a popup window
vim-patch:8.1.1636: crash when popup has fitting scrollbar
vim-patch:8.1.1646: build failure
vim-patch:8.1.1649: Illegal memory access when closing popup window
vim-patch:8.1.1656: popup window width is wrong when using Tabs
vim-patch:8.1.1665: crash when popup window with mask is below the screen
vim-patch:8.1.1666: click in popup window scrollbar with border doesn't scroll
vim-patch:8.1.1676: "maxwidth" of popup window does not always work properly
vim-patch:8.1.1678: using popup_menu() does not scroll to show the selected line
vim-patch:8.1.1707: Coverity warns for possibly using a NULL pointer
vim-patch:8.1.1709: Coverity warns for possibly using a NULL pointer
vim-patch:8.1.1719: popup too wide when 'showbreak' is set
vim-patch:8.1.1733: the man ftplugin leaves an empty buffer behind
vim-patch:8.1.1753: use of popup window mask is inefficient
vim-patch:8.1.1754: build failure
vim-patch:8.1.1755: leaking memory when using a popup window mask
vim-patch:8.1.1768: man plugin changes setting in current window
vim-patch:8.1.1773: the preview popup window may be too far to the right
vim-patch:8.1.1778: not showing the popup window right border is confusing
vim-patch:8.1.1779: not showing the popup window right border is confusing
vim-patch:8.1.1786: double click in popup scrollbar starts selection
vim-patch:8.1.1789: cannot see file name of preview popup window
vim-patch:8.1.1814: a long title in a popup window overflows
vim-patch:8.1.1845: may use NULL pointer when running out of memory
vim-patch:8.1.1850: focus may remain in popup window
vim-patch:8.1.1874: modeless selection in popup window overlaps scrollbar
vim-patch:8.1.1902: cannot have an info popup without a border
vim-patch:8.1.1907: wrong position for info popup with scrollbar on the left
vim-patch:8.1.1917: non-current window is not redrawn when moving popup
vim-patch:8.1.1918: redrawing popups is inefficient
vim-patch:8.1.1929: no tests for text property popup window
vim-patch:8.1.1934: not enough tests for text property popup window
vim-patch:8.1.1936: not enough tests for text property popup window
vim-patch:8.1.1945: popup window "firstline" cannot be reset
vim-patch:8.1.1959: when using "firstline" in popup window text may jump
vim-patch:8.1.1963: popup window filter may be called recursively
vim-patch:8.1.1997: no redraw after a popup window filter is invoked
vim-patch:8.1.1998: redraw even when no popup window filter was invoked
vim-patch:8.1.2009: cursorline highlighting not updated in popup window
vim-patch:8.1.2032: scrollbar thumb wrong in popup window
vim-patch:8.1.2109: popup_getoptions() hangs with tab-local popup
vim-patch:8.1.2110: CTRL-C closes two popups instead of one
vim-patch:8.1.2114: when a popup is closed with CTRL-C the callback aborts
vim-patch:8.1.2164: stuck when using "j" in a popupwin with popup_filter_menu
vim-patch:8.1.2210: using negative offset for popup_create() does not work
vim-patch:8.1.2213: popup_textprop tests fail
vim-patch:8.1.2240: popup window width changes when scrolling
vim-patch:8.1.2277: terminal window is not updated when info popup changes
vim-patch:8.1.2286: using border highlight in popup window leaks memory
vim-patch:8.1.2287: using EndOfBuffer highlight in popup does not look good
vim-patch:8.1.2288: not using all space when popup with "topleft" flips to above
vim-patch:8.1.2300: redraw breaks going through list of popup windows
vim-patch:8.1.2307: positioning popup doesn't work for buffer-local textprop
vim-patch:8.1.2334: possible NULL pointer dereference in popup_locate()
vim-patch:8.1.2420: crash when calling popup_close() in win_execute()

vim-patch:8.2.0826: Vim9: crash in :defcompile
vim-patch:8.2.1207: Vim9: crash in expr test when run in the GUI
vim-patch:8.2.2018: Vim9: script variable not found from lambda

vim-patch:9.0.0133: virtual text after line moves to joined line
2025-08-31 19:02:30 -07:00
Riley Bruins
77e3efecee feat(lsp): support textDocument/onTypeFormatting (#34637)
Implements [on-type
formatting](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_onTypeFormatting)
using a `vim.on_key()` approach to listen to typed keys. It will listen
to keys on the *left hand side* of mappings. The `on_key` callback is
cleared when detaching the last on-type formatting client. This feature
is disabled by default.

Co-authored-by: Maria José Solano <majosolano99@gmail.com>
2025-08-31 14:09:12 -07:00
Michael Henry
f311c96973 fix(health): update advice for Python #35564
Problem: `:checkhealth` advice for Python is out-of-date.

Solution: Update the advice to point to `:help provider-python`.
2025-08-31 11:17:21 -07:00
Jan Edmund Lazo
582e0714b5 vim-patch:8.1.1752: resizing hashtable is inefficient (#35563)
Problem:    Resizing hashtable is inefficient.
Solution:   Avoid resizing when the final size is predictable.

7b73d7ebf7

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2025-08-31 05:29:43 +00:00
11 changed files with 544 additions and 73 deletions

View File

@@ -2377,6 +2377,33 @@ set_level({level}) *vim.lsp.log.set_level()*
• {level} (`string|integer`) One of |vim.log.levels|
==============================================================================
Lua module: vim.lsp.on_type_formatting *lsp-on_type_formatting*
enable({enable}, {filter}) *vim.lsp.on_type_formatting.enable()*
Enables/disables on-type formatting globally or for the {filter}ed scope.
The following are some practical usage examples: >lua
-- Enable for all clients
vim.lsp.on_type_formatting.enable()
-- Enable for a specific client
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
local client_id = args.data.client_id
local client = assert(vim.lsp.get_client_by_id(client_id))
if client.name == 'rust-analyzer' then
vim.lsp.on_type_formatting.enable(true, { client_id = client_id })
end
end,
})
<
Parameters: ~
• {enable} (`boolean?`) true/nil to enable, false to disable.
• {filter} (`table?`) Optional filters |kwargs|:
• {client_id} (`integer?`) Client ID, or `nil` for all.
==============================================================================
Lua module: vim.lsp.rpc *lsp-rpc*

View File

@@ -242,6 +242,8 @@ LSP
• |vim.lsp.buf.signature_help()| supports "noActiveParameterSupport".
• Support for `textDocument/inlineCompletion` |lsp-inline_completion|
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_inlineCompletion
• Support for `textDocument/onTypeFormatting`: |lsp-on_type_formatting|
https://microsoft.github.io/language-server-protocol/specification/#textDocument_onTypeFormatting
LUA

View File

@@ -19,6 +19,7 @@ local lsp = vim._defer_require('vim.lsp', {
inline_completion = ..., --- @module 'vim.lsp.inline_completion'
linked_editing_range = ..., --- @module 'vim.lsp.linked_editing_range'
log = ..., --- @module 'vim.lsp.log'
on_type_formatting = ..., --- @module 'vim.lsp.on_type_formatting'
protocol = ..., --- @module 'vim.lsp.protocol'
rpc = ..., --- @module 'vim.lsp.rpc'
semantic_tokens = ..., --- @module 'vim.lsp.semantic_tokens'

View File

@@ -211,6 +211,9 @@ local all_clients = {}
---
--- @field _enabled_capabilities table<vim.lsp.capability.Name, boolean?>
---
--- Whether on-type formatting is enabled for this client.
--- @field _otf_enabled boolean?
---
--- Track this so that we can escalate automatically if we've already tried a
--- graceful shutdown
--- @field private _graceful_shutdown_failed true?

View File

@@ -0,0 +1,261 @@
local api = vim.api
local lsp = vim.lsp
local util = lsp.util
local method = lsp.protocol.Methods.textDocument_onTypeFormatting
local schedule = vim.schedule
local current_buf = api.nvim_get_current_buf
local get_mode = api.nvim_get_mode
local ns = api.nvim_create_namespace('nvim.lsp.on_type_formatting')
local augroup = api.nvim_create_augroup('nvim.lsp.on_type_formatting', {})
local M = {}
--- @alias vim.lsp.on_type_formatting.BufTriggers table<string, table<integer, vim.lsp.Client>>
--- A map from bufnr -> trigger character -> client ID -> client
--- @type table<integer, vim.lsp.on_type_formatting.BufTriggers>
local buf_handles = {}
--- |lsp-handler| for the `textDocument/onTypeFormatting` method.
---
--- @param err? lsp.ResponseError
--- @param result? lsp.TextEdit[]
--- @param ctx lsp.HandlerContext
local function on_type_formatting(err, result, ctx)
if err then
lsp.log.error('on_type_formatting', err)
return
end
local bufnr = assert(ctx.bufnr)
-- A `null` result is equivalent to an empty `TextEdit[]` result; no work should be done.
if not result or not api.nvim_buf_is_loaded(bufnr) or util.buf_versions[bufnr] ~= ctx.version then
return
end
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
util.apply_text_edits(result, ctx.bufnr, client.offset_encoding)
end
---@param bufnr integer
---@param typed string
---@param triggered_clients vim.lsp.Client[]
---@param idx integer?
---@param client vim.lsp.Client?
local function format_iter(bufnr, typed, triggered_clients, idx, client)
if not idx or not client then
return
end
---@type lsp.DocumentOnTypeFormattingParams
local params = vim.tbl_extend(
'keep',
util.make_formatting_params(),
util.make_position_params(0, client.offset_encoding),
{ ch = typed }
)
client:request(method, params, function(...)
on_type_formatting(...)
format_iter(bufnr, typed, triggered_clients, next(triggered_clients, idx))
end, bufnr)
end
---@param typed string
local function on_key(_, typed)
local mode = get_mode()
if mode.blocking or mode.mode ~= 'i' then
return
end
local bufnr = current_buf()
local buf_handle = buf_handles[bufnr]
if not buf_handle then
return
end
-- LSP expects '\n' for formatting on newline
if typed == '\r' then
typed = '\n'
end
local triggered_clients = buf_handle[typed]
if not triggered_clients then
return
end
-- Schedule the formatting to occur *after* the LSP is aware of the inserted character
schedule(function()
format_iter(bufnr, typed, triggered_clients, next(triggered_clients))
end)
end
--- @param client vim.lsp.Client
--- @param bufnr integer
local function detach(client, bufnr)
local buf_handle = buf_handles[bufnr]
if not buf_handle then
return
end
local client_id = client.id
-- Remove this client from its associated trigger characters
for trigger_char, attached_clients in pairs(buf_handle) do
attached_clients[client_id] = nil
-- Remove the trigger character if we detached its last client.
if not next(attached_clients) then
buf_handle[trigger_char] = nil
end
end
-- Remove the buf handle and its autocmds if we removed its last client.
if not next(buf_handle) then
buf_handles[bufnr] = nil
api.nvim_clear_autocmds({ group = augroup, buffer = bufnr })
-- Remove the on_key callback if we removed the last buf handle.
if not next(buf_handles) then
vim.on_key(nil, ns)
end
end
end
--- @param client vim.lsp.Client
--- @param bufnr integer
local function attach(client, bufnr)
if not client:supports_method(method, bufnr) then
return
end
local client_id = client.id
---@type lsp.DocumentOnTypeFormattingOptions
local otf_capabilities =
assert(vim.tbl_get(client.server_capabilities, 'documentOnTypeFormattingProvider'))
-- Set on_key callback, clearing first in case it was already registered.
vim.on_key(nil, ns)
vim.on_key(on_key, ns)
-- Populate the buf handle data. We cannot use defaulttable here because then an empty table will
-- be created for each unique keystroke
local buf_handle = buf_handles[bufnr] or {}
buf_handles[bufnr] = buf_handle
local trigger = buf_handle[otf_capabilities.firstTriggerCharacter] or {}
buf_handle[otf_capabilities.firstTriggerCharacter] = trigger
trigger[client_id] = client
for _, char in ipairs(otf_capabilities.moreTriggerCharacter or {}) do
trigger = buf_handle[char] or {}
buf_handle[char] = trigger
trigger[client_id] = client
end
api.nvim_clear_autocmds({ group = augroup, buffer = bufnr })
api.nvim_create_autocmd('LspDetach', {
buffer = bufnr,
desc = 'Detach on-type formatting module when the client detaches',
group = augroup,
callback = function(args)
local detached_client = assert(lsp.get_client_by_id(args.data.client_id))
detach(detached_client, bufnr)
end,
})
end
api.nvim_create_autocmd('LspAttach', {
desc = 'Enable on-type formatting for all buffers with individually-enabled clients.',
callback = function(ev)
local buf = ev.buf
local client = assert(lsp.get_client_by_id(ev.data.client_id))
if client._otf_enabled then
attach(client, buf)
end
end,
})
---@param enable boolean
---@param client vim.lsp.Client
local function toggle_for_client(enable, client)
local handler = enable and attach or detach
-- Toggle for buffers already attached.
for bufnr, _ in pairs(client.attached_buffers) do
handler(client, bufnr)
end
client._otf_enabled = enable
end
---@param enable boolean
local function toggle_globally(enable)
-- Toggle for clients that have already attached.
local clients = lsp.get_clients({ method = method })
for _, client in ipairs(clients) do
toggle_for_client(enable, client)
end
-- If disabling, only clear the attachment autocmd. If enabling, create it as well.
local group = api.nvim_create_augroup('nvim.lsp.on_type_formatting', { clear = true })
if enable then
api.nvim_create_autocmd('LspAttach', {
group = group,
desc = 'Enable on-type formatting for ALL clients by default.',
callback = function(ev)
local client = assert(lsp.get_client_by_id(ev.data.client_id))
if client._otf_enabled ~= false then
attach(client, ev.buf)
end
end,
})
end
end
--- Optional filters |kwargs|:
--- @inlinedoc
--- @class vim.lsp.on_type_formatting.enable.Filter
--- @field client_id integer? Client ID, or `nil` for all.
--- Enables/disables on-type formatting globally or for the {filter}ed scope. The following are some
--- practical usage examples:
---
--- ```lua
--- -- Enable for all clients
--- vim.lsp.on_type_formatting.enable()
---
--- -- Enable for a specific client
--- vim.api.nvim_create_autocmd('LspAttach', {
--- callback = function(args)
--- local client_id = args.data.client_id
--- local client = assert(vim.lsp.get_client_by_id(client_id))
--- if client.name == 'rust-analyzer' then
--- vim.lsp.on_type_formatting.enable(true, { client_id = client_id })
--- end
--- end,
--- })
--- ```
---
--- @param enable? boolean true/nil to enable, false to disable.
--- @param filter vim.lsp.on_type_formatting.enable.Filter?
function M.enable(enable, filter)
vim.validate('enable', enable, 'boolean', true)
vim.validate('filter', filter, 'table', true)
enable = enable ~= false
filter = filter or {}
if filter.client_id then
local client =
assert(lsp.get_client_by_id(filter.client_id), 'Client not found for id ' .. filter.client_id)
toggle_for_client(enable, client)
else
toggle_globally(enable)
end
end
return M

View File

@@ -572,6 +572,9 @@ function protocol.make_client_capabilities()
linkedEditingRange = {
dynamicRegistration = false,
},
onTypeFormatting = {
dynamicRegistration = false,
},
},
workspace = {
symbol = {

View File

@@ -732,10 +732,9 @@ local function python()
local message = 'Detected pip upgrade failure: Python executable can import "pynvim" but not "neovim": '
.. pynvim_exe
local advice = {
'Use that Python version to reinstall "pynvim" and optionally "neovim".',
'Use that Python version to uninstall any "pynvim" or "neovim", e.g.:',
pynvim_exe .. ' -m pip uninstall pynvim neovim',
pynvim_exe .. ' -m pip install pynvim',
pynvim_exe .. ' -m pip install neovim # only if needed by third-party software',
'Then see :help provider-python for "pynvim" installation steps.',
}
health.error(message, advice)
end
@@ -761,7 +760,7 @@ local function python()
if is_bad_response(current) then
health.error(
'pynvim is not installed.\nError: ' .. current,
'Run in shell: ' .. python_exe .. ' -m pip install pynvim'
'See :help provider-python for "pynvim" installation steps.'
)
end

View File

@@ -286,6 +286,7 @@ local config = {
'inline_completion.lua',
'linked_editing_range.lua',
'log.lua',
'on_type_formatting.lua',
'rpc.lua',
'semantic_tokens.lua',
'tagfunc.lua',

View File

@@ -317,7 +317,7 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
// Use specified size.
minitems = MAX(minitems, ht->ht_used);
// array is up to 2/3 full
minsize = minitems * 3 / 2;
minsize = (minitems * 3 + 1) / 2;
}
size_t newsize = HT_INIT_SIZE;

View File

@@ -61,7 +61,7 @@ static const int included_patches[] = {
2423,
2422,
2421,
// 2420,
2420,
2419,
// 2418,
2417,
@@ -110,7 +110,7 @@ static const int included_patches[] = {
2374,
2373,
2372,
// 2371,
2371,
2370,
2369,
2368,
@@ -147,7 +147,7 @@ static const int included_patches[] = {
2337,
2336,
2335,
// 2334,
2334,
2333,
2332,
2331,
@@ -174,14 +174,14 @@ static const int included_patches[] = {
2310,
2309,
2308,
// 2307,
2307,
2306,
2305,
2304,
2303,
2302,
2301,
// 2300,
2300,
2299,
2298,
2297,
@@ -193,9 +193,9 @@ static const int included_patches[] = {
2291,
2290,
2289,
// 2288,
// 2287,
// 2286,
2288,
2287,
2286,
2285,
2284,
2283,
@@ -204,7 +204,7 @@ static const int included_patches[] = {
2280,
// 2279,
2278,
// 2277,
2277,
2276,
2275,
2274,
@@ -241,7 +241,7 @@ static const int included_patches[] = {
2243,
2242,
// 2241,
// 2240,
2240,
2239,
2238,
2237,
@@ -268,10 +268,10 @@ static const int included_patches[] = {
2216,
2215,
2214,
// 2213,
2213,
2212,
2211,
// 2210,
2210,
2209,
// 2208,
2207,
@@ -317,7 +317,7 @@ static const int included_patches[] = {
2167,
2166,
2165,
// 2164,
2164,
2163,
2162,
2161,
@@ -367,12 +367,12 @@ static const int included_patches[] = {
2117,
2116,
2115,
// 2114,
2114,
2113,
2112,
2111,
// 2110,
// 2109,
2110,
2109,
2108,
2107,
2106,
@@ -449,7 +449,7 @@ static const int included_patches[] = {
2035,
2034,
2033,
// 2032,
2032,
2031,
2030,
2029,
@@ -472,7 +472,7 @@ static const int included_patches[] = {
2012,
2011,
2010,
// 2009,
2009,
2008,
2007,
2006,
@@ -483,8 +483,8 @@ static const int included_patches[] = {
2001,
2000,
// 1999,
// 1998,
// 1997,
1998,
1997,
// 1996,
1995,
1994,
@@ -518,11 +518,11 @@ static const int included_patches[] = {
1966,
1965,
// 1964,
// 1963,
1963,
1962,
1961,
1960,
// 1959,
1959,
1958,
// 1957,
1956,
@@ -536,7 +536,7 @@ static const int included_patches[] = {
1948,
1947,
1946,
// 1945,
1945,
// 1944,
// 1943,
1942,
@@ -545,14 +545,14 @@ static const int included_patches[] = {
// 1939,
1938,
1937,
// 1936,
1936,
1935,
// 1934,
1934,
1933,
1932,
1931,
1930,
// 1929,
1929,
// 1928,
1927,
1926,
@@ -563,8 +563,8 @@ static const int included_patches[] = {
1921,
// 1920,
// 1919,
// 1918,
// 1917,
1918,
1917,
1916,
1915,
1914,
@@ -574,12 +574,12 @@ static const int included_patches[] = {
1910,
1909,
// 1908,
// 1907,
1907,
// 1906,
// 1905,
// 1904,
1903,
// 1902,
1902,
1901,
1900,
1899,
@@ -607,7 +607,7 @@ static const int included_patches[] = {
1877,
1876,
1875,
// 1874,
1874,
1873,
1872,
1871,
@@ -631,12 +631,12 @@ static const int included_patches[] = {
1853,
1852,
// 1851,
// 1850,
1850,
1849,
1848,
1847,
1846,
// 1845,
1845,
1844,
1843,
1842,
@@ -667,7 +667,7 @@ static const int included_patches[] = {
1817,
1816,
1815,
// 1814,
1814,
// 1813,
1812,
// 1811,
@@ -692,28 +692,28 @@ static const int included_patches[] = {
1792,
1791,
1790,
// 1789,
1789,
1788,
// 1787,
// 1786,
1786,
1785,
// 1784,
1783,
1782,
1781,
1780,
// 1779,
// 1778,
1779,
1778,
1777,
1776,
1775,
1774,
// 1773,
1773,
1772,
1771,
// 1770,
1769,
// 1768,
1768,
1767,
1766,
1765,
@@ -726,10 +726,10 @@ static const int included_patches[] = {
1758,
1757,
1756,
// 1755,
// 1754,
// 1753,
// 1752,
1755,
1754,
1753,
1752,
// 1751,
1750,
1749,
@@ -748,7 +748,7 @@ static const int included_patches[] = {
1736,
1735,
1734,
// 1733,
1733,
1732,
1731,
1730,
@@ -762,7 +762,7 @@ static const int included_patches[] = {
1722,
1721,
1720,
// 1719,
1719,
// 1718,
1717,
1716,
@@ -772,9 +772,9 @@ static const int included_patches[] = {
1712,
1711,
1710,
// 1709,
1709,
1708,
// 1707,
1707,
1706,
1705,
1704,
@@ -803,9 +803,9 @@ static const int included_patches[] = {
1681,
1680,
1679,
// 1678,
1678,
1677,
// 1676,
1676,
1675,
1674,
// 1673,
@@ -815,8 +815,8 @@ static const int included_patches[] = {
1669,
1668,
1667,
// 1666,
// 1665,
1666,
1665,
1664,
1663,
1662,
@@ -825,17 +825,17 @@ static const int included_patches[] = {
// 1659,
1658,
1657,
// 1656,
1656,
1655,
1654,
1653,
1652,
1651,
1650,
// 1649,
1649,
1648,
1647,
// 1646,
1646,
1645,
1644,
1643,
@@ -845,7 +845,7 @@ static const int included_patches[] = {
1639,
1638,
1637,
// 1636,
1636,
1635,
1634,
1633,
@@ -859,14 +859,14 @@ static const int included_patches[] = {
1625,
1624,
1623,
// 1622,
1622,
1621,
// 1620,
1620,
1619,
1618,
// 1617,
1617,
1616,
// 1615,
1615,
1614,
1613,
// 1612,
@@ -879,13 +879,13 @@ static const int included_patches[] = {
1605,
1604,
1603,
// 1602,
1602,
1601,
// 1600,
1599,
1598,
// 1597,
// 1596,
1596,
1595,
1594,
1593,
@@ -919,7 +919,7 @@ static const int included_patches[] = {
1565,
1564,
1563,
// 1562,
1562,
// 1561,
// 1560,
// 1559,
@@ -931,7 +931,7 @@ static const int included_patches[] = {
// 1553,
1552,
1551,
// 1550,
1550,
1549,
// 1548,
1547,
@@ -954,7 +954,7 @@ static const int included_patches[] = {
1530,
1529,
1528,
// 1527,
1527,
1526,
// 1525,
1524,
@@ -1222,7 +1222,7 @@ static const int included_patches[] = {
1262,
1261,
1260,
// 1259,
1259,
1258,
1257,
1256,
@@ -1345,7 +1345,7 @@ static const int included_patches[] = {
1139,
1138,
1137,
// 1136,
1136,
1135,
1134,
1133,
@@ -1398,7 +1398,7 @@ static const int included_patches[] = {
1086,
1085,
1084,
// 1083,
1083,
1082,
1081,
1080,

View File

@@ -0,0 +1,174 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local t_lsp = require('test.functional.plugin.lsp.testutil')
local retry = t.retry
local eq = t.eq
local dedent = t.dedent
local exec_lua = n.exec_lua
local insert = n.insert
local feed = n.feed
local clear_notrace = t_lsp.clear_notrace
local create_server_definition = t_lsp.create_server_definition
describe('vim.lsp.on_type_formatting', function()
local text = dedent([[
int main() {
int hi
}]])
before_each(function()
clear_notrace()
exec_lua(create_server_definition)
exec_lua(function()
_G.server = _G._create_server({
capabilities = {
documentOnTypeFormattingProvider = {
firstTriggerCharacter = '=',
},
},
handlers = {
---@param params lsp.DocumentOnTypeFormattingParams
---@param callback fun(err?: lsp.ResponseError, result?: lsp.TextEdit[])
['textDocument/onTypeFormatting'] = function(_, params, callback)
callback(nil, {
{
newText = ';',
range = {
start = params.position,
['end'] = params.position,
},
},
})
end,
},
})
_G.server_id = vim.lsp.start({
name = 'dummy',
cmd = _G.server.cmd,
})
vim.lsp.on_type_formatting.enable(true, { client_id = _G.server_id })
end)
insert(text)
end)
it('enables formatting on type', function()
exec_lua(function()
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_set_cursor(win, { 2, 0 })
end)
feed('A = 5')
retry(nil, 100, function()
eq(
{
'int main() {',
' int hi = 5;',
'}',
},
exec_lua(function()
return vim.api.nvim_buf_get_lines(0, 0, -1, false)
end)
)
end)
end)
it('works with multiple clients', function()
exec_lua(function()
vim.lsp.on_type_formatting.enable(true)
_G.server2 = _G._create_server({
capabilities = {
documentOnTypeFormattingProvider = {
firstTriggerCharacter = '.',
moreTriggerCharacter = { '=' },
},
},
handlers = {
---@param params lsp.DocumentOnTypeFormattingParams
---@param callback fun(err?: lsp.ResponseError, result?: lsp.TextEdit[])
['textDocument/onTypeFormatting'] = function(_, params, callback)
callback(nil, {
{
newText = ';',
range = {
start = params.position,
['end'] = params.position,
},
},
})
end,
},
})
vim.lsp.start({
name = 'dummy2',
cmd = _G.server2.cmd,
})
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_set_cursor(win, { 2, 0 })
end)
feed('A =')
retry(nil, 100, function()
eq(
{
'int main() {',
' int hi =;;',
'}',
},
exec_lua(function()
return vim.api.nvim_buf_get_lines(0, 0, -1, false)
end)
)
end)
end)
it('can be disabled', function()
exec_lua(function()
vim.lsp.on_type_formatting.enable(false, { client_id = _G.server_id })
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_set_cursor(win, { 2, 0 })
end)
feed('A = 5')
eq(
{
'int main() {',
' int hi = 5',
'}',
},
exec_lua(function()
return vim.api.nvim_buf_get_lines(0, 0, -1, false)
end)
)
end)
it('attaches to new buffers', function()
exec_lua(function()
local buf = vim.api.nvim_create_buf(true, false)
vim.api.nvim_set_current_buf(buf)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, {
'int main() {',
' int hi',
'}',
})
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_set_cursor(win, { 2, 0 })
vim.lsp.buf_attach_client(buf, _G.server_id)
end)
feed('A = 5')
retry(nil, 100, function()
eq(
{
'int main() {',
' int hi = 5;',
'}',
},
exec_lua(function()
return vim.api.nvim_buf_get_lines(0, 0, -1, false)
end)
)
end)
end)
end)