Hi,
I think that I found a zsh prompt display bug that can hide the
messages printed by some processes on the terminal to end users.
(Please tell me if I should report the bug elsewhere, I sent it to
this mailing list because 1. I could not find an active zsh bug
tracker and 2. both https://github.com/zsh-users/zsh's README and
https://sourceforge.net/p/zsh/bugs/ told me to write the bug
report here.)
I am no zsh expert so please tell me if this behavior is expected
and if a configuration option exists to prevent such message loss.
# Bug description
It seems that the way zsh displays its prompt enables the loss of
messages written on the terminal in some cases.
As the bug is visual, I recorded what has been printed on terminal
session there: https://asciinema.org/a/543461
The attached MWE program `nowait.c` can be compiled with `gcc
-std=c11 -D_POSIX_C_SOURCE=199309L -Wall -Wextra -O2 -o nowait
nowait.c` and enables to reproduce the error. It has the following
behavior.
- The initial process writes a message on the terminal, then
creates a subprocess (via libc `fork()`), then exits.
- The subprocess sleeps for a given number of milliseconds (or
does not sleep at all if `argv[1] == 0`), then writes another
message on the terminal. The written message is terminated by a
newline if and only if `argv[2] == 1`.
If the subprocess writes on the terminal between the termination
of the initial process and the writing of the prompt, the content
of its message is erased by the prompt.
If the message is newline-terminated this is not a big deal, but
otherwise the whole message will be hidden from the end user of
the terminal.
I had the issue on the theme I use regularly (that uses
`prompt_subst`), but I could also reproduce the issue from the
default theme.
To do so, I made the prompt message generation slow by setting
`PROMPT="prompt $(sleep 2)"` and by enabling `prompt_subst`.
# Desired behavior
I think that messages displayed by processes on the terminal
should not be hidden by the shell.
IMHO keeping the printed messages before the prompt would be
reasonable, but anything that prevents message loss would be an
improvement (e.g., to copy the messages after erasing the prompt
then writing the prompt if you think this is better).
# Execution environment
I could reproduce the problem on several environments.
On my laptop (dell latitude 3420, x86-64, linux-5.15.72, NixOS
22.05, zsh-5.9) both on a tty and on the kitty-0.26.2 graphical
terminal emulator. Zsh used my configuration there.
On a [Grid'5000 econome
machine](https://www.grid5000.fr/w/Nantes:Hardware#econome),
x86-64, linux-5.10.0-19-amd64, Debian 5.10.149-2 (2022-10-21),
zsh-5.9. This machine has an empty zsh configuration. I was
connected on the machine remotely via ssh.
Best regards,
-- Millian Poquet, MCF (Associate Prof), Univ. Toulouse III FSI, Dpt. INFO ; IRIT, Sepia team https://mpoquet.github.io Room 469, IRIT2, cours Rose Dieng-Kuntz, Campus Univ. Toulouse III
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "usage: nowait <DELAY-MILLISECONDS> <CHILD-NEWLINE>\n"); exit(1); } unsigned int delay_ms = atoi(argv[1]); int child_newline = atoi(argv[2]); struct timespec delay; delay.tv_sec = delay_ms / 1000; delay.tv_nsec = (delay_ms % 1000) * 1000000; printf("msg from parent process\n"); fflush(stdout); switch(fork()) { case -1: perror("fork"); return 1; case 0: if (delay_ms > 0) nanosleep(&delay, NULL); if (child_newline) printf("msg from child process\n"); else printf("msg from child process"); fflush(stdout); return 0; } return 0; }