commit 1a1a60bd0526b76ae232cc59cd1eaf5ad3ce9e77
parent a17d39314d1bda465449cf133e6700abe5abf46f
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sat, 14 Feb 2026 10:49:39 +0800
fix(terminal): resuming doesn't work with command in fish (#37857)
Problem: Resuming terminal process doesn't work with command in fish.
Solution: Send SIGCONT to the entire process group.
Use killpg() like what bash and zsh do on `fg`:
https://cgit.git.savannah.gnu.org/cgit/bash.git/tree/jobs.c?id=637f5c8696a6adc9b4519f1cd74aa78492266b7f#n3928
https://sourceforge.net/p/zsh/code/ci/77045ef899e53b9598bebc5a41db93a548a40ca6/tree/Src/jobs.c#l2674
https://sourceforge.net/p/zsh/code/ci/77045ef899e53b9598bebc5a41db93a548a40ca6/tree/Src/signals.c#l538
Install fish on CI to test this.
Diffstat:
4 files changed, 48 insertions(+), 7 deletions(-)
diff --git a/.github/scripts/install_deps.sh b/.github/scripts/install_deps.sh
@@ -31,7 +31,7 @@ if [[ $OS == Linux ]]; then
fi
if [[ -n $TEST ]]; then
- sudo apt-get install -y locales-all cpanminus attr libattr1-dev gdb inotify-tools xdg-utils
+ sudo apt-get install -y locales-all cpanminus attr libattr1-dev fish gdb inotify-tools xdg-utils
# Use default CC to avoid compilation problems when installing Python modules
CC=cc python3 -m pip -q install --user --upgrade --break-system-packages pynvim
@@ -47,7 +47,7 @@ elif [[ $OS == Darwin ]]; then
brew update --quiet
brew install ninja
if [[ -n $TEST ]]; then
- brew install cpanminus fswatch
+ brew install cpanminus fish fswatch
npm install -g neovim
npm link neovim
diff --git a/src/nvim/os/pty_proc_unix.c b/src/nvim/os/pty_proc_unix.c
@@ -241,7 +241,9 @@ void pty_proc_resize(PtyProc *ptyproc, uint16_t width, uint16_t height)
void pty_proc_resume(PtyProc *ptyproc)
{
- kill(((Proc *)ptyproc)->pid, SIGCONT);
+ // Send SIGCONT to the entire process group, as some shells (e.g. fish) don't
+ // propagate SIGCONT to suspended child processes.
+ killpg(((Proc *)ptyproc)->pid, SIGCONT);
}
void pty_proc_close(PtyProc *ptyproc)
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
@@ -612,6 +612,46 @@ end)
describe(':terminal buffer', function()
before_each(clear)
+ it('can resume suspended PTY process running in fish', function()
+ skip(is_os('win'), 'N/A for Windows')
+ skip(fn.executable('fish') == 0, 'missing "fish" command')
+
+ local screen = Screen.new(50, 7)
+ screen:add_extra_attr_ids({
+ [100] = {
+ foreground = Screen.colors.NvimDarkGrey2,
+ background = Screen.colors.NvimLightGrey2,
+ },
+ [101] = {
+ foreground = Screen.colors.NvimLightGrey4,
+ background = Screen.colors.NvimLightGrey2,
+ },
+ [102] = {
+ foreground = Screen.colors.NvimDarkGrey2,
+ background = Screen.colors.NvimLightGrey4,
+ },
+ })
+ command('set shell=fish termguicolors')
+ command(('terminal %s -u NONE -i NONE'):format(fn.shellescape(nvim_prog)))
+ command('startinsert')
+ local s0 = [[
+ {100:^ }|
+ {101:~ }|*3
+ {102:[No Name] 0,0-1 All}|
+ {100: }|
+ {5:-- TERMINAL --} |
+ ]]
+ screen:expect(s0)
+ feed('<C-Z>')
+ screen:expect([[
+ |*5
+ ^[Process suspended] |
+ {5:-- TERMINAL --} |
+ ]])
+ feed('<Space>')
+ screen:expect(s0)
+ end)
+
it('term_close() use-after-free #4393', function()
command('terminal yes')
feed('<Ignore>') -- Add input to separate two RPC requests
diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
@@ -24,6 +24,7 @@ local eval = n.eval
local command = n.command
local write_file = t.write_file
local api = n.api
+local fn = n.fn
local sleep = vim.uv.sleep
local assert_alive = n.assert_alive
local poke_eventloop = n.poke_eventloop
@@ -88,10 +89,8 @@ describe('backtick expansion', function()
end)
it('with shell=fish', function()
- if eval("executable('fish')") == 0 then
- pending('missing "fish" command')
- return
- end
+ t.skip(fn.executable('fish') == 0, 'missing "fish" command')
+
command('set shell=fish')
command(':silent args `echo ***2`')
eq({ 'file2' }, eval('argv()'))