Merge #40516 from justinmk/health

This commit is contained in:
Justin M. Keyes
2026-07-01 07:45:47 -04:00
committed by GitHub
7 changed files with 150 additions and 86 deletions

View File

@@ -6588,24 +6588,20 @@ A jump table for the options with a short description can be found at |Q_op|.
*'swapfile'* *'swf'* *'noswapfile'* *'noswf'*
'swapfile' 'swf' boolean (default on)
local to buffer
Use a swapfile for the buffer. This option can be reset when a
swapfile is not wanted for a specific buffer. For example, with
confidential information that even root must not be able to access.
Careful: All text will be in memory:
- Don't use this for big files.
- Recovery will be impossible!
A swapfile will only be present when 'updatecount' is non-zero and
'swapfile' is set.
When 'swapfile' is reset, the swap file for the current buffer is
immediately deleted. When 'swapfile' is set, and 'updatecount' is
non-zero, a swap file is immediately created.
Also see |swap-file|.
If you want to open a new buffer without creating a swap file for it,
use the |:noswapfile| modifier.
See 'directory' for where the swap file is created.
Use a |swap-file| for the buffer (if 'updatecount' is non-zero). The
'directory' option decides where swapfiles are stored.
This option is used together with 'bufhidden' and 'buftype' to
specify special kinds of buffers. See |special-buffers|.
To open a new buffer without creating a swapfile, use |:noswapfile|.
To disable for an existing buffer, reset its 'swapfile' option.
Careful:
- Recovery will be impossible!
- The entire file will be in memory.
When reset, the swapfile for the current buffer is immediately
deleted. When re-enabled (and 'updatecount' is non-zero), a swapfile
is immediately created.
Used with 'bufhidden' and 'buftype' to specify |special-buffers|.
*'switchbuf'* *'swb'*
'switchbuf' 'swb' string (default "uselast")
@@ -7135,17 +7131,15 @@ A jump table for the options with a short description can be found at |Q_op|.
*'updatecount'* *'uc'*
'updatecount' 'uc' number (default 200)
global
After typing this many characters the swap file will be written to
disk. When zero, no swap file will be created at all (see chapter on
recovery |crash-recovery|). 'updatecount' is set to zero by starting
Vim with the "-n" option, see |startup|. When editing in readonly
mode this option will be initialized to 10000.
The swapfile can be disabled per buffer with 'swapfile'.
When 'updatecount' is set from zero to non-zero, swap files are
created for all buffers that have 'swapfile' set. When 'updatecount'
is set to zero, existing swap files are not deleted.
This option has no meaning in buffers where 'buftype' is "nofile" or
"nowrite".
The |swap-file| will be written after typing this many characters.
- Ignored in buffers where 'buftype' is "nofile" or "nowrite".
- Initialized to 10000 when editing in readonly |-R| mode.
- To disable swapfiles per-buffer, unset the 'swapfile' option.
- To disable swapfiles globally, set this option to zero (or start
with |-n|). See |crash-recovery|. Existing swapfiles are not deleted.
- When re-enabled (from zero to non-zero), swapfiles are created for
all buffers that have 'swapfile' set.
*'updatetime'* *'ut'*
'updatetime' 'ut' number (default 4000)

View File

@@ -0,0 +1,20 @@
-- OS/process utils.
local M = {}
--- Counts (approximate) open file descriptors for this process. Works on Linux/macOS/BSD.
---@return integer? # Number of open fds, or nil if `/dev/fd` failed (fds exhausted, or unavailable/Windows).
function M.count_open_fds()
local n = 0
for _, _, err in vim.fs.dir('/dev/fd', { err = true }) do
-- If `/dev/fd` scan failed (e.g. EMFILE when fds exhausted), count would be misleading.
if err then
return nil
end
n = n + 1
end
-- Discount the scan's own descriptor.
return math.max(0, n - 1)
end
return M

View File

@@ -7023,24 +7023,20 @@ vim.o.sua = vim.o.suffixesadd
vim.bo.suffixesadd = vim.o.suffixesadd
vim.bo.sua = vim.bo.suffixesadd
--- Use a swapfile for the buffer. This option can be reset when a
--- swapfile is not wanted for a specific buffer. For example, with
--- confidential information that even root must not be able to access.
--- Careful: All text will be in memory:
--- - Don't use this for big files.
--- - Recovery will be impossible!
--- A swapfile will only be present when 'updatecount' is non-zero and
--- 'swapfile' is set.
--- When 'swapfile' is reset, the swap file for the current buffer is
--- immediately deleted. When 'swapfile' is set, and 'updatecount' is
--- non-zero, a swap file is immediately created.
--- Also see `swap-file`.
--- If you want to open a new buffer without creating a swap file for it,
--- use the `:noswapfile` modifier.
--- See 'directory' for where the swap file is created.
--- Use a `swap-file` for the buffer (if 'updatecount' is non-zero). The
--- 'directory' option decides where swapfiles are stored.
---
--- This option is used together with 'bufhidden' and 'buftype' to
--- specify special kinds of buffers. See `special-buffers`.
--- To open a new buffer without creating a swapfile, use `:noswapfile`.
--- To disable for an existing buffer, reset its 'swapfile' option.
--- Careful:
--- - Recovery will be impossible!
--- - The entire file will be in memory.
---
--- When reset, the swapfile for the current buffer is immediately
--- deleted. When re-enabled (and 'updatecount' is non-zero), a swapfile
--- is immediately created.
---
--- Used with 'bufhidden' and 'buftype' to specify `special-buffers`.
---
--- @type boolean
vim.o.swapfile = true
@@ -7702,17 +7698,15 @@ vim.o.ur = vim.o.undoreload
vim.go.undoreload = vim.o.undoreload
vim.go.ur = vim.go.undoreload
--- After typing this many characters the swap file will be written to
--- disk. When zero, no swap file will be created at all (see chapter on
--- recovery `crash-recovery`). 'updatecount' is set to zero by starting
--- Vim with the "-n" option, see `startup`. When editing in readonly
--- mode this option will be initialized to 10000.
--- The swapfile can be disabled per buffer with 'swapfile'.
--- When 'updatecount' is set from zero to non-zero, swap files are
--- created for all buffers that have 'swapfile' set. When 'updatecount'
--- is set to zero, existing swap files are not deleted.
--- This option has no meaning in buffers where 'buftype' is "nofile" or
--- "nowrite".
--- The `swap-file` will be written after typing this many characters.
---
--- - Ignored in buffers where 'buftype' is "nofile" or "nowrite".
--- - Initialized to 10000 when editing in readonly `-R` mode.
--- - To disable swapfiles per-buffer, unset the 'swapfile' option.
--- - To disable swapfiles globally, set this option to zero (or start
--- with `-n`). See `crash-recovery`. Existing swapfiles are not deleted.
--- - When re-enabled (from zero to non-zero), swapfiles are created for
--- all buffers that have 'swapfile' set.
---
--- @type integer
vim.o.updatecount = 200

View File

@@ -208,6 +208,61 @@ local function check_watchers()
)
end
--- Reads a single integer from a file (e.g. a `/proc/sys` entry).
---@param path string
---@return integer?
local function read_int(path)
local ok, lines = pcall(vim.fn.readfile, path, '', 1)
local v = ok and lines[1] and tonumber(lines[1])
return v or nil
end
-- Note: this is part of check_performance().
local function check_limits()
-- 'ulimit -n' (RLIMIT_NOFILE): each Nvim buffer may hold an open swapfile. Sockets, channels, filewatchers also consume file descriptors.
if vim.fn.has('win32') == 0 then
local ok, out = system({ 'sh', '-c', 'ulimit -Sn' }) -- Must use a shell.
out = vim.trim(out or '')
local soft = tonumber(out)
local used = require('vim._core.proc').count_open_fds()
local used_str = used and (', currently open: %d'):format(used) or ''
local raise_advice = {
'\'swapfile\' buffers, sockets, channels, and file-watchers consume file descriptors. A low limit causes "(libuv) kqueue(): Too many open files" (EMFILE) errors.',
'Increase the limit: add `ulimit -n 8192` to your shell rc. On macOS see also `launchctl limit maxfiles`; on Linux see `/etc/security/limits.conf` and systemd `LimitNOFILE`.',
}
if out == 'unlimited' then
health.ok(('ulimit -n (max open files): unlimited%s'):format(used_str))
elseif not ok or soft == nil then
health.info(('ulimit -n (max open files): unknown (%s)%s'):format(out, used_str))
elseif soft < 1024 then
health.warn(('ulimit -n (max open files) is low: %d%s'):format(soft, used_str), raise_advice)
elseif used and used > soft * 0.8 then
health.warn(
('Open files near the limit: %d of %d (ulimit -n)'):format(used, soft),
raise_advice
)
else
health.ok(('ulimit -n (max open files): %d%s'):format(soft, used_str))
end
end
-- Linux inotify limits filewatchers (LSP, vim._watch). Exhausting them reports ENOSPC ("no space on device").
if vim.uv.os_uname().sysname == 'Linux' then
local watches = read_int('/proc/sys/fs/inotify/max_user_watches')
local instances = read_int('/proc/sys/fs/inotify/max_user_instances')
if watches and watches < 8192 then
health.warn(('fs.inotify.max_user_watches is low: %d'):format(watches), {
'Filewatchers may fail with ENOSPC. To increase the limit: `sysctl fs.inotify.max_user_watches=524288` (persist in /etc/sysctl.conf).',
})
end
if instances and instances < 128 then
health.warn(('fs.inotify.max_user_instances is low: %d'):format(instances), {
'To increase the limit: `sysctl fs.inotify.max_user_instances=512` (persist in /etc/sysctl.conf).',
})
end
end
end
local function check_performance()
health.start('Performance')
@@ -240,6 +295,7 @@ local function check_performance()
end
check_watchers()
check_limits()
end
-- Load the remote plugin manifest file and check for unregistered plugins

View File

@@ -243,8 +243,13 @@ local function check_plug_dir()
local is_good = true
local plug_dir = get_plug_dir()
for plug_name, _ in vim.fs.dir(plug_dir) do
is_good = check_installed_plugin(plug_name) and is_good
for plug_name, _, err in vim.fs.dir(plug_dir, { err = true }) do
if err then
health.error(err)
is_good = false
else
is_good = check_installed_plugin(plug_name) and is_good
end
end
if is_good then

View File

@@ -9071,24 +9071,20 @@ local options = {
cb = 'did_set_swapfile',
defaults = true,
desc = [=[
Use a swapfile for the buffer. This option can be reset when a
swapfile is not wanted for a specific buffer. For example, with
confidential information that even root must not be able to access.
Careful: All text will be in memory:
- Don't use this for big files.
- Recovery will be impossible!
A swapfile will only be present when 'updatecount' is non-zero and
'swapfile' is set.
When 'swapfile' is reset, the swap file for the current buffer is
immediately deleted. When 'swapfile' is set, and 'updatecount' is
non-zero, a swap file is immediately created.
Also see |swap-file|.
If you want to open a new buffer without creating a swap file for it,
use the |:noswapfile| modifier.
See 'directory' for where the swap file is created.
Use a |swap-file| for the buffer (if 'updatecount' is non-zero). The
'directory' option decides where swapfiles are stored.
This option is used together with 'bufhidden' and 'buftype' to
specify special kinds of buffers. See |special-buffers|.
To open a new buffer without creating a swapfile, use |:noswapfile|.
To disable for an existing buffer, reset its 'swapfile' option.
Careful:
- Recovery will be impossible!
- The entire file will be in memory.
When reset, the swapfile for the current buffer is immediately
deleted. When re-enabled (and 'updatecount' is non-zero), a swapfile
is immediately created.
Used with 'bufhidden' and 'buftype' to specify |special-buffers|.
]=],
full_name = 'swapfile',
redraw = { 'statuslines' },
@@ -9942,17 +9938,15 @@ local options = {
cb = 'did_set_updatecount',
defaults = 200,
desc = [=[
After typing this many characters the swap file will be written to
disk. When zero, no swap file will be created at all (see chapter on
recovery |crash-recovery|). 'updatecount' is set to zero by starting
Vim with the "-n" option, see |startup|. When editing in readonly
mode this option will be initialized to 10000.
The swapfile can be disabled per buffer with 'swapfile'.
When 'updatecount' is set from zero to non-zero, swap files are
created for all buffers that have 'swapfile' set. When 'updatecount'
is set to zero, existing swap files are not deleted.
This option has no meaning in buffers where 'buftype' is "nofile" or
"nowrite".
The |swap-file| will be written after typing this many characters.
- Ignored in buffers where 'buftype' is "nofile" or "nowrite".
- Initialized to 10000 when editing in readonly |-R| mode.
- To disable swapfiles per-buffer, unset the 'swapfile' option.
- To disable swapfiles globally, set this option to zero (or start
with |-n|). See |crash-recovery|. Existing swapfiles are not deleted.
- When re-enabled (from zero to non-zero), swapfiles are created for
all buffers that have 'swapfile' set.
]=],
full_name = 'updatecount',
scope = { 'global' },

View File

@@ -228,6 +228,7 @@ describe('vim._core', function()
'vim._core.help',
'vim._core.log',
'vim._core.options',
'vim._core.proc',
'vim._core.server',
'vim._core.shared',
'vim._core.spell',