2024-04-20 08:44:13 -07:00
|
|
|
local t = require('test.testutil')
|
|
|
|
local n = require('test.functional.testnvim')()
|
|
|
|
|
2024-04-08 02:03:20 -07:00
|
|
|
local eq = t.eq
|
2024-04-20 08:44:13 -07:00
|
|
|
local exec_lua = n.exec_lua
|
|
|
|
local clear = n.clear
|
2024-04-08 02:03:20 -07:00
|
|
|
local is_ci = t.is_ci
|
|
|
|
local is_os = t.is_os
|
|
|
|
local skip = t.skip
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
-- Create a file via a rename to avoid multiple
|
|
|
|
-- events which can happen with some backends on some platforms
|
|
|
|
local function touch(path)
|
2024-04-08 02:03:20 -07:00
|
|
|
local tmp = t.tmpname()
|
2024-02-07 04:24:44 -07:00
|
|
|
assert(vim.uv.fs_rename(tmp, path))
|
|
|
|
end
|
|
|
|
|
2023-03-04 23:52:27 -07:00
|
|
|
describe('vim._watch', function()
|
|
|
|
before_each(function()
|
|
|
|
clear()
|
|
|
|
end)
|
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
local function run(watchfunc)
|
fix(watch): ignore nonexistent paths (ENOENT)
Problem:
The `_watch.watch()` strategy may fail if the given path does not exist:
…/vim/_watch.lua:101: ENOENT: no such file or directory
stack traceback:
[C]: in function 'assert'
…/vim/_watch.lua:101: in function <…/vim/_watch.lua:61>
[string "<nvim>"]:5: in main chunk
- `_watch.watch()` actively asserts any error returned by `handle:start()`.
- whereas `_watch.watchdirs()` just ignores the result of `root_handle:start()`.
Servers may send "client/registerCapability" with "workspace/didChangeWatchedFiles"
item(s) (`baseUri`) which do not actually exist on the filesystem:
https://github.com/neovim/neovim/issues/28058#issuecomment-2189929424
{
method = "client/registerCapability",
params = {
registrations = { {
method = "workspace/didChangeWatchedFiles",
registerOptions = {
watchers = { {
globPattern = {
baseUri = "file:///Users/does/not/exist",
pattern = "**/*.{ts,js,mts,mjs,cjs,cts,json,svelte}"
}
},
...
}
Solution:
- Remove the assert in `_watch.watch()`.
- Show a once-only message for both cases.
- More detailed logging is blocked until we have `nvim_log` / `vim.log`.
fix #28058
2024-09-30 06:25:44 -07:00
|
|
|
-- Monkey-patches vim.notify_once so we can "spy" on it.
|
|
|
|
local function spy_notify_once()
|
|
|
|
exec_lua [[
|
|
|
|
_G.__notify_once_msgs = {}
|
|
|
|
vim.notify_once = (function(overridden)
|
|
|
|
return function(msg, level, opts)
|
|
|
|
table.insert(_G.__notify_once_msgs, msg)
|
|
|
|
return overridden(msg, level, opts)
|
|
|
|
end
|
|
|
|
end)(vim.notify_once)
|
|
|
|
]]
|
|
|
|
end
|
|
|
|
|
|
|
|
local function last_notify_once_msg()
|
|
|
|
return exec_lua 'return _G.__notify_once_msgs[#_G.__notify_once_msgs]'
|
|
|
|
end
|
|
|
|
|
|
|
|
local function do_watch(root_dir, watchfunc_)
|
|
|
|
exec_lua(
|
|
|
|
[[
|
|
|
|
local root_dir, watchfunc = ...
|
|
|
|
|
|
|
|
_G.events = {}
|
|
|
|
|
|
|
|
_G.stop_watch = vim._watch[watchfunc](root_dir, {
|
|
|
|
debounce = 100,
|
|
|
|
include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1,
|
|
|
|
exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'),
|
|
|
|
}, function(path, change_type)
|
|
|
|
table.insert(_G.events, { path = path, change_type = change_type })
|
|
|
|
end)
|
|
|
|
]],
|
|
|
|
root_dir,
|
|
|
|
watchfunc_
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it(watchfunc .. '() ignores nonexistent paths', function()
|
|
|
|
if watchfunc == 'inotify' then
|
|
|
|
skip(n.fn.executable('inotifywait') == 0, 'inotifywait not found')
|
|
|
|
skip(is_os('bsd'), 'inotifywait on bsd CI seems to expect path to exist?')
|
|
|
|
end
|
|
|
|
|
|
|
|
local msg = ('watch.%s: ENOENT: no such file or directory'):format(watchfunc)
|
|
|
|
|
|
|
|
spy_notify_once()
|
|
|
|
do_watch('/i am /very/funny.go', watchfunc)
|
|
|
|
|
|
|
|
if watchfunc ~= 'inotify' then -- watch.inotify() doesn't (currently) call vim.notify_once.
|
|
|
|
t.retry(nil, 2000, function()
|
|
|
|
t.eq(msg, last_notify_once_msg())
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
eq(0, exec_lua [[return #_G.events]])
|
|
|
|
|
|
|
|
exec_lua [[_G.stop_watch()]]
|
|
|
|
end)
|
|
|
|
|
|
|
|
it(watchfunc .. '() detects file changes', function()
|
2024-07-06 02:44:19 -07:00
|
|
|
if watchfunc == 'inotify' then
|
2024-03-28 15:26:01 -07:00
|
|
|
skip(is_os('win'), 'not supported on windows')
|
2024-02-07 04:28:35 -07:00
|
|
|
skip(is_os('mac'), 'flaky test on mac')
|
fix(watch): ignore nonexistent paths (ENOENT)
Problem:
The `_watch.watch()` strategy may fail if the given path does not exist:
…/vim/_watch.lua:101: ENOENT: no such file or directory
stack traceback:
[C]: in function 'assert'
…/vim/_watch.lua:101: in function <…/vim/_watch.lua:61>
[string "<nvim>"]:5: in main chunk
- `_watch.watch()` actively asserts any error returned by `handle:start()`.
- whereas `_watch.watchdirs()` just ignores the result of `root_handle:start()`.
Servers may send "client/registerCapability" with "workspace/didChangeWatchedFiles"
item(s) (`baseUri`) which do not actually exist on the filesystem:
https://github.com/neovim/neovim/issues/28058#issuecomment-2189929424
{
method = "client/registerCapability",
params = {
registrations = { {
method = "workspace/didChangeWatchedFiles",
registerOptions = {
watchers = { {
globPattern = {
baseUri = "file:///Users/does/not/exist",
pattern = "**/*.{ts,js,mts,mjs,cjs,cts,json,svelte}"
}
},
...
}
Solution:
- Remove the assert in `_watch.watch()`.
- Show a once-only message for both cases.
- More detailed logging is blocked until we have `nvim_log` / `vim.log`.
fix #28058
2024-09-30 06:25:44 -07:00
|
|
|
skip(not is_ci() and n.fn.executable('inotifywait') == 0, 'inotifywait not found')
|
2024-02-07 04:28:35 -07:00
|
|
|
end
|
|
|
|
|
fix(watch): ignore nonexistent paths (ENOENT)
Problem:
The `_watch.watch()` strategy may fail if the given path does not exist:
…/vim/_watch.lua:101: ENOENT: no such file or directory
stack traceback:
[C]: in function 'assert'
…/vim/_watch.lua:101: in function <…/vim/_watch.lua:61>
[string "<nvim>"]:5: in main chunk
- `_watch.watch()` actively asserts any error returned by `handle:start()`.
- whereas `_watch.watchdirs()` just ignores the result of `root_handle:start()`.
Servers may send "client/registerCapability" with "workspace/didChangeWatchedFiles"
item(s) (`baseUri`) which do not actually exist on the filesystem:
https://github.com/neovim/neovim/issues/28058#issuecomment-2189929424
{
method = "client/registerCapability",
params = {
registrations = { {
method = "workspace/didChangeWatchedFiles",
registerOptions = {
watchers = { {
globPattern = {
baseUri = "file:///Users/does/not/exist",
pattern = "**/*.{ts,js,mts,mjs,cjs,cts,json,svelte}"
}
},
...
}
Solution:
- Remove the assert in `_watch.watch()`.
- Show a once-only message for both cases.
- More detailed logging is blocked until we have `nvim_log` / `vim.log`.
fix #28058
2024-09-30 06:25:44 -07:00
|
|
|
-- Note: because this is not `elseif`, BSD is skipped for *all* cases...?
|
2024-02-07 04:24:44 -07:00
|
|
|
if watchfunc == 'watch' then
|
2024-03-28 04:05:28 -07:00
|
|
|
skip(is_os('mac'), 'flaky test on mac')
|
2024-02-07 04:24:44 -07:00
|
|
|
skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38')
|
2024-10-02 07:36:50 -07:00
|
|
|
elseif watchfunc == 'watchdirs' and is_os('mac') then
|
|
|
|
-- Bump this (or fix the bug) if CI continues to fail in future versions of macos CI.
|
2024-10-05 10:03:11 -07:00
|
|
|
skip(is_ci() and vim.uv.os_uname().release == '24.0.0', 'weird failure for macOS arm 15 CI')
|
2024-02-07 04:24:44 -07:00
|
|
|
else
|
|
|
|
skip(
|
|
|
|
is_os('bsd'),
|
|
|
|
'kqueue only reports events on watched folder itself, not contained files #26110'
|
|
|
|
)
|
|
|
|
end
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
local expected_events = 0
|
fix(watch): ignore nonexistent paths (ENOENT)
Problem:
The `_watch.watch()` strategy may fail if the given path does not exist:
…/vim/_watch.lua:101: ENOENT: no such file or directory
stack traceback:
[C]: in function 'assert'
…/vim/_watch.lua:101: in function <…/vim/_watch.lua:61>
[string "<nvim>"]:5: in main chunk
- `_watch.watch()` actively asserts any error returned by `handle:start()`.
- whereas `_watch.watchdirs()` just ignores the result of `root_handle:start()`.
Servers may send "client/registerCapability" with "workspace/didChangeWatchedFiles"
item(s) (`baseUri`) which do not actually exist on the filesystem:
https://github.com/neovim/neovim/issues/28058#issuecomment-2189929424
{
method = "client/registerCapability",
params = {
registrations = { {
method = "workspace/didChangeWatchedFiles",
registerOptions = {
watchers = { {
globPattern = {
baseUri = "file:///Users/does/not/exist",
pattern = "**/*.{ts,js,mts,mjs,cjs,cts,json,svelte}"
}
},
...
}
Solution:
- Remove the assert in `_watch.watch()`.
- Show a once-only message for both cases.
- More detailed logging is blocked until we have `nvim_log` / `vim.log`.
fix #28058
2024-09-30 06:25:44 -07:00
|
|
|
--- Waits for a new event, or fails if no events are triggered.
|
2024-02-07 04:24:44 -07:00
|
|
|
local function wait_for_event()
|
2023-03-04 23:52:27 -07:00
|
|
|
expected_events = expected_events + 1
|
2024-02-07 04:24:44 -07:00
|
|
|
exec_lua(
|
|
|
|
[[
|
|
|
|
local expected_events = ...
|
|
|
|
assert(
|
|
|
|
vim.wait(3000, function()
|
|
|
|
return #_G.events == expected_events
|
|
|
|
end),
|
|
|
|
string.format(
|
|
|
|
'Timed out waiting for expected event no. %d. Current events seen so far: %s',
|
|
|
|
expected_events,
|
|
|
|
vim.inspect(events)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
]],
|
|
|
|
expected_events
|
|
|
|
)
|
2023-03-04 23:52:27 -07:00
|
|
|
end
|
|
|
|
|
fix(watch): ignore nonexistent paths (ENOENT)
Problem:
The `_watch.watch()` strategy may fail if the given path does not exist:
…/vim/_watch.lua:101: ENOENT: no such file or directory
stack traceback:
[C]: in function 'assert'
…/vim/_watch.lua:101: in function <…/vim/_watch.lua:61>
[string "<nvim>"]:5: in main chunk
- `_watch.watch()` actively asserts any error returned by `handle:start()`.
- whereas `_watch.watchdirs()` just ignores the result of `root_handle:start()`.
Servers may send "client/registerCapability" with "workspace/didChangeWatchedFiles"
item(s) (`baseUri`) which do not actually exist on the filesystem:
https://github.com/neovim/neovim/issues/28058#issuecomment-2189929424
{
method = "client/registerCapability",
params = {
registrations = { {
method = "workspace/didChangeWatchedFiles",
registerOptions = {
watchers = { {
globPattern = {
baseUri = "file:///Users/does/not/exist",
pattern = "**/*.{ts,js,mts,mjs,cjs,cts,json,svelte}"
}
},
...
}
Solution:
- Remove the assert in `_watch.watch()`.
- Show a once-only message for both cases.
- More detailed logging is blocked until we have `nvim_log` / `vim.log`.
fix #28058
2024-09-30 06:25:44 -07:00
|
|
|
local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX')
|
2024-02-07 04:24:44 -07:00
|
|
|
local unwatched_path = root_dir .. '/file.unwatched'
|
|
|
|
local watched_path = root_dir .. '/file'
|
2023-03-04 23:52:27 -07:00
|
|
|
|
fix(watch): ignore nonexistent paths (ENOENT)
Problem:
The `_watch.watch()` strategy may fail if the given path does not exist:
…/vim/_watch.lua:101: ENOENT: no such file or directory
stack traceback:
[C]: in function 'assert'
…/vim/_watch.lua:101: in function <…/vim/_watch.lua:61>
[string "<nvim>"]:5: in main chunk
- `_watch.watch()` actively asserts any error returned by `handle:start()`.
- whereas `_watch.watchdirs()` just ignores the result of `root_handle:start()`.
Servers may send "client/registerCapability" with "workspace/didChangeWatchedFiles"
item(s) (`baseUri`) which do not actually exist on the filesystem:
https://github.com/neovim/neovim/issues/28058#issuecomment-2189929424
{
method = "client/registerCapability",
params = {
registrations = { {
method = "workspace/didChangeWatchedFiles",
registerOptions = {
watchers = { {
globPattern = {
baseUri = "file:///Users/does/not/exist",
pattern = "**/*.{ts,js,mts,mjs,cjs,cts,json,svelte}"
}
},
...
}
Solution:
- Remove the assert in `_watch.watch()`.
- Show a once-only message for both cases.
- More detailed logging is blocked until we have `nvim_log` / `vim.log`.
fix #28058
2024-09-30 06:25:44 -07:00
|
|
|
do_watch(root_dir, watchfunc)
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
if watchfunc ~= 'watch' then
|
|
|
|
vim.uv.sleep(200)
|
|
|
|
end
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
touch(watched_path)
|
|
|
|
touch(unwatched_path)
|
|
|
|
wait_for_event()
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
os.remove(watched_path)
|
|
|
|
os.remove(unwatched_path)
|
|
|
|
wait_for_event()
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
exec_lua [[_G.stop_watch()]]
|
|
|
|
-- No events should come through anymore
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
vim.uv.sleep(100)
|
|
|
|
touch(watched_path)
|
2024-02-07 04:28:35 -07:00
|
|
|
vim.uv.sleep(100)
|
2024-02-07 04:24:44 -07:00
|
|
|
os.remove(watched_path)
|
|
|
|
vim.uv.sleep(100)
|
2023-03-04 23:52:27 -07:00
|
|
|
|
2024-02-07 04:24:44 -07:00
|
|
|
eq({
|
2023-11-19 06:25:32 -07:00
|
|
|
{
|
2024-02-07 04:24:44 -07:00
|
|
|
change_type = exec_lua([[return vim._watch.FileChangeType.Created]]),
|
2023-11-19 06:25:32 -07:00
|
|
|
path = root_dir .. '/file',
|
|
|
|
},
|
|
|
|
{
|
2024-02-07 04:24:44 -07:00
|
|
|
change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]),
|
2023-11-19 06:25:32 -07:00
|
|
|
path = root_dir .. '/file',
|
|
|
|
},
|
2024-02-07 04:24:44 -07:00
|
|
|
}, exec_lua [[return _G.events]])
|
2023-03-04 23:52:27 -07:00
|
|
|
end)
|
2024-02-07 04:24:44 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
run('watch')
|
|
|
|
run('watchdirs')
|
2024-07-06 02:44:19 -07:00
|
|
|
run('inotify')
|
2023-03-04 23:52:27 -07:00
|
|
|
end)
|