mirror of
https://github.com/neovim/neovim.git
synced 2026-07-12 04:19:45 +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.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -3730,6 +3730,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',
|
||||
@@ -3770,6 +3772,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,
|
||||
@@ -3797,12 +3810,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',
|
||||
@@ -3814,7 +3828,7 @@ describe('LSP', function()
|
||||
},
|
||||
},
|
||||
},
|
||||
}, result[3])
|
||||
}, messages[3])
|
||||
|
||||
eq({
|
||||
method = 'workspace/didChangeWatchedFiles',
|
||||
@@ -3826,7 +3840,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