On Thu, Oct 14, 2021 at 04:28:14PM +0100, Bram Moolenaar <
Br...@moolenaar.net> wrote:
> > > Since more than one person complained about this, and it still doesn't
> > > fully work with zsh, I'll revert 8.2.2919. For zsh we need to find a
> > > different solution.
> >
> > Thanks. Maybe blocking SIGHUP would fix the original problem with
> > background processes?
>
> Hopefully someone can find out what the actualy problem is and find a
> solution that works and does not cause new problems.
Hmm, SIGHUP is already ignored in the gui.
My guess is that the original problem is that most
shells inherit gvim's ignoring of SIGHUP, but zsh
doesn't. So the command being executed doesn't ignore
SIGHUP either, and it dies when zsh terminates, rather
than when it's finished. But that is just a guess.
It's strange. The original bug report was for Arch Linux.
But it works fine on Debian Linux. It doesn't work on macOS.
I tried the following things on macOS:
- Append "; wait" to the command
- Prepend "setopt NO_HUP; " to the command
- Prepend "trap '' HUP; " to the command
- Prepend "setopt NO_HUP; trap '' HUP; " to the command
- set shellcmdflag=-o\ nohup\ -c
The only thing that "fixed" it was appending "; wait"
to the command. Below is a patch that does that,
only when the gui is running and the shell is zsh and
there's an ampersand in the command (so "&&" will be a
false positive).
diff --git a/src/misc2.c b/src/misc2.c
index 8e01434ea..20c56edde 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1766,6 +1766,29 @@ call_shell(char_u *cmd, int opt)
proftime_T wait_time;
#endif
+#ifdef FEAT_GUI
+ // Workaround a problem when executing a backgrounded command
+ // with zsh from the gui, by telling zsh to wait for it to complete.
+ // Otherwise, the command fails to function. Theory: Other shells
+ // inherit gvim's ignoring of SIGHUP, but maybe zsh is not ignoring it.
+
+ char_u *modified_cmd = NULL;
+
+ if (cmd != NULL && gui.in_use && strstr((char *)gettail(p_sh), "zsh") != NULL && vim_strchr(cmd, (int)'&'))
+ {
+ const char *suffix = "; wait";
+ size_t suffix_len = strlen(suffix);
+ size_t cmd_len = strlen((const char *)cmd);
+
+ modified_cmd = vim_strnsave(cmd, cmd_len + suffix_len);
+ if (modified_cmd != NULL)
+ {
+ memcpy(modified_cmd + cmd_len, suffix, suffix_len + 1); // "+ 1" is not necessary
+ cmd = modified_cmd;
+ }
+ }
+#endif
+
if (p_verbose > 3)
{
verbose_enter();
@@ -1843,6 +1866,10 @@ call_shell(char_u *cmd, int opt)
if (do_profiling == PROF_YES)
prof_child_exit(&wait_time);
# endif
+#endif
+#ifdef FEAT_GUI
+ if (modified_cmd != NULL)
+ vim_free(modified_cmd);
#endif
return retval;
But it's awful and hacky. It "fixes" the problem by
effectively disabling the ability to background a
process in zsh. And since it isn't a problem on Debian
Linux, it would make things slightly worse on some
systems, but only for commands that actually take a
long time to execute.
Unfortunately, dtruss on macOS isn't working well
enough for me to trace what's happening. Perhaps
someone with Arch Linux can use strace to investigate.
Until then, the most practical solution is to just:
set shell=/bin/bash
That fixes it on macOS.
cheers,
raf