feat: ignore swapfile for running Nvim processes #25336

Problem:
The swapfile "E325: ATTENTION" dialog is displayed when editing a file
already open in another (running) Nvim. Usually this behavior is
annoying and irrelevant:
- "Recover" and the other options ("Open readonly", "Quit", "Abort") are
  almost never wanted.
- swapfiles are less relevant for "multi-Nvim" since 'autoread' is
  enabled by default.
  - Even less relevant if user enables 'autowrite'.

Solution:
Define a default SwapExists handler which does the following:
1. If the swapfile is owned by a running Nvim process, automatically
   chooses "(E)dit anyway" (caveat: this creates a new, extra swapfile,
   which is mostly harmless and ignored except by `:recover` or `nvim -r`.
2. Shows a 1-line "ignoring swapfile..." message.
3. Users can disable the default SwapExists handler via `autocmd! nvim_swapfile`.
This commit is contained in:
Justin M. Keyes
2023-10-04 06:31:25 -07:00
committed by GitHub
parent 1e7e9ee91f
commit 29fe883aa9
15 changed files with 267 additions and 178 deletions

View File

@@ -118,7 +118,7 @@ manually. Mostly the screen will not scroll up, thus there is no hit-enter
prompt. When one command outputs two messages this can happen anyway.
==============================================================================
3. Removing autocommands *autocmd-remove*
3. Removing autocommands *autocmd!* *autocmd-remove*
:au[tocmd]! [group] {event} {aupat} [++once] [++nested] {cmd}
Remove all autocommands associated with {event} and

View File

@@ -7843,8 +7843,8 @@ swapinfo({fname}) *swapinfo()*
user user name
host host name
fname original file name
pid PID of the Vim process that created the swap
file
pid PID of the Nvim process that created the swap
file, or zero if not running.
mtime last modification time in seconds
inode Optional: INODE number of the file
dirty 1 if file was modified, 0 if not

View File

@@ -169,33 +169,26 @@ If you want to keep the changed buffer without saving it, switch on the
2. Editing a file *edit-a-file*
*:e* *:edit* *reload*
:e[dit] [++opt] [+cmd] Edit the current file. This is useful to re-edit the
:e[dit][!] [++opt] [+cmd]
Edit the current file. This is useful to re-edit the
current file, when it has been changed outside of Vim.
This fails when changes have been made to the current
buffer and 'autowriteall' isn't set or the file can't
be written.
Also see |++opt| and |+cmd|.
*:edit!* *discard*
:e[dit]! [++opt] [+cmd]
Edit the current file always. Discard any changes to
the current buffer. This is useful if you want to
start all over again.
If [!] is given, unsaved changes in the current buffer
are discarded. Without [!] the command fails if there
are unsaved changes, unless 'autowriteall' is set and
the file can be written.
Also see |++opt| and |+cmd|.
*:edit_f*
:e[dit] [++opt] [+cmd] {file}
:e[dit][!] [++opt] [+cmd] {file}
Edit {file}.
This fails when changes have been made to the current
buffer, unless 'hidden' is set or 'autowriteall' is
set and the file can be written.
*:edit!_f*
If [!] is given, unsaved changes in the current buffer
are discarded. Without [!] the command fails if there
are unsaved changes, unless 'hidden' is set or
'autowriteall' is set and the file can be written.
Also see |++opt| and |+cmd|.
*:edit!_f*
:e[dit]! [++opt] [+cmd] {file}
Edit {file} always. Discard any changes to the
current buffer.
Also see |++opt| and |+cmd|.
*:edit_#* *:e#*
:e[dit] [++opt] [+cmd] #[count]
Edit the [count]th buffer (as shown by |:files|).
@@ -1224,10 +1217,10 @@ MULTIPLE WINDOWS AND BUFFERS *window-exit*
*:confirm* *:conf*
:conf[irm] {command} Execute {command}, and use a dialog when an
operation has to be confirmed. Can be used on the
|:q|, |:qa| and |:w| commands (the latter to override
a read-only setting), and any other command that can
fail in such a way, such as |:only|, |:buffer|,
|:bdelete|, etc.
|:edit|, |:q|, |:qa| and |:w| commands (the latter to
override a read-only setting), and any commands that
can fail because of unsaved changes, such as |:only|,
|:buffer|, |:bdelete|, etc.
Examples: >
:confirm w foo

View File

@@ -2276,12 +2276,13 @@ v:stderr |channel-id| corresponding to stderr. The value is always 2;
:call chansend(v:stderr, "error: toaster empty\n")
<
*v:swapname* *swapname-variable*
v:swapname Only valid when executing |SwapExists| autocommands: Name of
the swap file found. Read-only.
v:swapname Name of the swapfile found.
Only valid during |SwapExists| event.
Read-only.
*v:swapchoice* *swapchoice-variable*
v:swapchoice |SwapExists| autocommands can set this to the selected choice
for handling an existing swap file:
for handling an existing swapfile:
'o' Open read-only
'e' Edit anyway
'r' Recover

View File

@@ -114,6 +114,12 @@ The following new APIs and features were added.
• Builtin TUI can now recognize "super" (|<D-|) and "meta" (|<T-|) modifiers in a
terminal emulator that supports |tui-csiu|.
• Editor
• By default, the swapfile "ATTENTION" |E325| dialog is skipped if the
swapfile is owned by a running Nvim process, instead of prompting. If you
always want the swapfile dialog, delete the default SwapExists handler:
`autocmd! nvim_swapfile`. |default-autocmds|
• LSP
• LSP method names are available in |vim.lsp.protocol.Methods|.
• Implemented LSP inlay hints: |vim.lsp.inlay_hint()|

View File

@@ -83,6 +83,15 @@ Detecting an existing swap file ~
You can find this in the user manual, section |11.3|.
*W325*
The default |SwapExists| handler (|default-autocmds|) skips the |E325| prompt
(selects "(E)dit") if the swapfile owner process (1) is still running and (2)
was started by the current user. This presumes that you normally don't want
to be bothered with the |ATTENTION| message just because you happen to edit
the same file from multiple Nvim instances. In the worst case (a system
crash) there will be more than one swapfile for the file; use |:recover| to
inspect all of its swapfiles.
Updating the swapfile ~

View File

@@ -139,6 +139,11 @@ nvim_terminal:
nvim_cmdwin:
- CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|.
nvim_swapfile:
- SwapExists: Skips the swapfile prompt (sets |v:swapchoice| to "e") when the
swapfile is owned by a running Nvim process. Shows |W325| "Ignoring
swapfile…" message.
==============================================================================
New Features *nvim-features*

View File

@@ -1147,11 +1147,28 @@ function vim._init_default_autocmds()
end
end,
})
vim.api.nvim_create_autocmd({ 'CmdwinEnter' }, {
pattern = '[:>]',
group = vim.api.nvim_create_augroup('nvim_cmdwin', {}),
command = 'syntax sync minlines=1 maxlines=1',
})
vim.api.nvim_create_autocmd({ 'SwapExists' }, {
pattern = '*',
group = vim.api.nvim_create_augroup('nvim_swapfile', {}),
callback = function()
local info = vim.fn.swapinfo(vim.v.swapname)
local user = vim.uv.os_get_passwd().username
local iswin = 1 == vim.fn.has('win32')
if info.error or info.pid <= 0 or (not iswin and info.user ~= user) then
vim.v.swapchoice = '' -- Show the prompt.
return
end
vim.v.swapchoice = 'e' -- Choose "(E)dit".
vim.notify(('W325: Ignoring swapfile from Nvim process %d'):format(info.pid))
end,
})
end
function vim._init_defaults()

View File

@@ -9312,8 +9312,8 @@ function vim.fn.swapfilelist() end
--- user user name
--- host host name
--- fname original file name
--- pid PID of the Vim process that created the swap
--- file
--- pid PID of the Nvim process that created the swap
--- file, or zero if not running.
--- mtime last modification time in seconds
--- inode Optional: INODE number of the file
--- dirty 1 if file was modified, 0 if not