mirror of
https://github.com/neovim/neovim.git
synced 2026-08-01 05:09:08 +00:00
Some servers register `workspace/didChangeWatchedFiles` watchers for URI
schemes that cannot be watched locally. Skipping the unsupported glob
and keep the rest of the registration batch active.
(cherry picked from commit 4d9e5acfb5)
This commit is contained in:
committed by
github-actions[bot]
parent
1b9159a695
commit
fd27246f67
@@ -1,11 +1,53 @@
|
||||
local bit = require('bit')
|
||||
local glob = vim.glob
|
||||
local watch = vim._watch
|
||||
local log = require('vim.lsp.log')
|
||||
local protocol = require('vim.lsp.protocol')
|
||||
local lpeg = vim.lpeg
|
||||
|
||||
local M = {}
|
||||
|
||||
-- Use a bounded set to suppress repeat warnings without unbounded growth.
|
||||
---@type table<string, true>
|
||||
local logged_invalid_patterns = {}
|
||||
---@type string[]
|
||||
local logged_invalid_pattern_keys = {}
|
||||
local logged_invalid_pattern_key_index = 1
|
||||
|
||||
---@param key string
|
||||
local function remember_invalid_pattern(key)
|
||||
local old_key = logged_invalid_pattern_keys[logged_invalid_pattern_key_index]
|
||||
if old_key then
|
||||
logged_invalid_patterns[old_key] = nil
|
||||
end
|
||||
logged_invalid_patterns[key] = true
|
||||
logged_invalid_pattern_keys[logged_invalid_pattern_key_index] = key
|
||||
logged_invalid_pattern_key_index = logged_invalid_pattern_key_index % 20 + 1
|
||||
end
|
||||
|
||||
--- Parses a glob pattern and logs invalid patterns once.
|
||||
---@param pattern string
|
||||
---@param client vim.lsp.Client
|
||||
---@return vim.lpeg.Pattern?
|
||||
local function glob_to_lpeg(pattern, client)
|
||||
local ok, pattern_or_err = pcall(glob.to_lpeg, pattern)
|
||||
if ok then
|
||||
return pattern_or_err
|
||||
end
|
||||
local key = string.format('%d:%s', client.id, pattern)
|
||||
if not logged_invalid_patterns[key] then
|
||||
log.error(
|
||||
string.format(
|
||||
'LSP[%s] skipping invalid workspace/didChangeWatchedFiles globPattern',
|
||||
client.name
|
||||
),
|
||||
pattern,
|
||||
pattern_or_err
|
||||
)
|
||||
remember_invalid_pattern(key)
|
||||
end
|
||||
end
|
||||
|
||||
if vim.fn.has('win32') == 1 or vim.fn.has('mac') == 1 then
|
||||
M._watchfunc = watch.watch
|
||||
elseif vim.fn.executable('inotifywait') == 1 then
|
||||
@@ -62,24 +104,22 @@ function M.register(reg, client_id)
|
||||
local glob_pattern = w.globPattern
|
||||
|
||||
if type(glob_pattern) == 'string' then
|
||||
local pattern = glob.to_lpeg(glob_pattern)
|
||||
if not pattern then
|
||||
error('Cannot parse pattern: ' .. glob_pattern)
|
||||
end
|
||||
for _, folder in ipairs(client.workspace_folders) do
|
||||
local base_dir = vim.uri_to_fname(folder.uri)
|
||||
table.insert(watch_regs[base_dir], { pattern = pattern, kind = kind })
|
||||
local pattern = glob_to_lpeg(glob_pattern, client)
|
||||
if pattern then
|
||||
for _, folder in ipairs(client.workspace_folders) do
|
||||
local base_dir = vim.uri_to_fname(folder.uri)
|
||||
table.insert(watch_regs[base_dir], { pattern = pattern, kind = kind })
|
||||
end
|
||||
end
|
||||
else
|
||||
local base_uri = glob_pattern.baseUri
|
||||
local uri = type(base_uri) == 'string' and base_uri or base_uri.uri
|
||||
local base_dir = vim.uri_to_fname(uri)
|
||||
local pattern = glob.to_lpeg(glob_pattern.pattern)
|
||||
if not pattern then
|
||||
error('Cannot parse pattern: ' .. glob_pattern.pattern)
|
||||
local pattern = glob_to_lpeg(glob_pattern.pattern, client)
|
||||
if pattern then
|
||||
local relative_pattern = lpeg.P(base_dir .. '/') * pattern --[[@as vim.lpeg.Pattern]]
|
||||
table.insert(watch_regs[base_dir], { pattern = relative_pattern, kind = kind })
|
||||
end
|
||||
pattern = lpeg.P(base_dir .. '/') * pattern
|
||||
table.insert(watch_regs[base_dir], { pattern = pattern, kind = kind })
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -3683,6 +3683,8 @@ describe('LSP', function()
|
||||
|
||||
exec_lua(create_server_definition)
|
||||
local result = exec_lua(function()
|
||||
local logfile = vim.lsp.log.get_filename()
|
||||
vim.fn.writefile({ '' }, logfile)
|
||||
local server = _G._create_server()
|
||||
local client_id = assert(vim.lsp.start({
|
||||
name = 'watchfiles-test',
|
||||
@@ -3723,6 +3725,17 @@ describe('LSP', function()
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
registerOptions = {
|
||||
watchers = {
|
||||
{
|
||||
globPattern = 'a/**b',
|
||||
kind = 7,
|
||||
},
|
||||
{
|
||||
globPattern = {
|
||||
baseUri = vim.uri_from_fname(root_dir),
|
||||
pattern = '{foo}',
|
||||
},
|
||||
kind = 7,
|
||||
},
|
||||
{
|
||||
globPattern = '**/watch',
|
||||
kind = 7,
|
||||
@@ -3750,12 +3763,13 @@ describe('LSP', function()
|
||||
|
||||
vim.lsp.get_client_by_id(client_id):stop()
|
||||
|
||||
return server.messages
|
||||
return { logfile = logfile, messages = server.messages }
|
||||
end)
|
||||
|
||||
local uri = vim.uri_from_fname(root_dir .. '/watch')
|
||||
local messages = result.messages
|
||||
|
||||
eq(6, #result)
|
||||
eq(6, #messages)
|
||||
|
||||
eq({
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
@@ -3767,7 +3781,7 @@ describe('LSP', function()
|
||||
},
|
||||
},
|
||||
},
|
||||
}, result[3])
|
||||
}, messages[3])
|
||||
|
||||
eq({
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
@@ -3779,7 +3793,18 @@ describe('LSP', function()
|
||||
},
|
||||
},
|
||||
},
|
||||
}, result[4])
|
||||
}, messages[4])
|
||||
|
||||
t.assert_log(
|
||||
'%[ERROR%].-skipping invalid workspace/didChangeWatchedFiles globPattern.-'
|
||||
.. pesc('a/**b'),
|
||||
result.logfile
|
||||
)
|
||||
t.assert_log(
|
||||
'%[ERROR%].-skipping invalid workspace/didChangeWatchedFiles globPattern.-'
|
||||
.. pesc('{foo}'),
|
||||
result.logfile
|
||||
)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user