I use zsh (zsh 5.9 (x86_64-apple-darwin22.0)) and zsh/curses for a small command line interface. The content of the view should automatically adjust when the window size changes. I tried a solution with trap SIGWINCH, but with zsh (I tried it on Ubuntu and macOS) trap SIGWINCH obviously doesn’t work. So I use a background shell with a busy loop (see monitorwindowsize
below) that sends SIGUSR1 to the parent shell to signal it to resize the window. The only solution I’ve found to make the inner loop wait a while is to call sleep
(e.g. call read -t 10
does not work here), but – you know – sleep creates a new process each time it’s called. And of course I want to call the resize function as fast as possible, so I’m interested in keeping the sleep time as short as possible, i.e. calling sleep quite often. So my question is if there is an alternative for sleep under zsh that works in a sub-shell. Or is there a better solution than using the busy loop with this zsh/curses code.
The code:
#!/bin/zsh
zmodload zsh/curses
loop ()
{
monitorwindowsize $1 &
view
while true; do
read -t 1000
done
}
view ()
{
zcurses addwin mywin $(( LINES-4 )) $(( COLUMNS-4 )) 2 2
zcurses clear mywin
zcurses border mywin
zcurses refresh mywin
zcurses move mywin $(( (LINES-4)/2 )) $(( (COLUMNS-8)/2 ))
zcurses string mywin "Box"
zcurses refresh mywin
}
resetview ()
{
zcurses end
tput clear
zcurses clear mywin
zcurses refresh mywin
zcurses delwin mywin
view
}
monitorwindowsize ()
{
currentLines=$LINES
currentColumns=$COLUMNS
while true; do
if (( currentLines != LINES || currentColumns != COLUMNS )); then
currentLines=$LINES
currentColumns=$COLUMNS
kill -SIGUSR1 $1
fi
sleep 0.1
done
}
TRAPUSR1() {
resetview
}
TRAPINT() {
for jobs in $jobstates ; do
jobid=${${jobs##*:*:}%=*}
kill ${${jobs##*:*:}%=*}
done
zcurses end
exit
}
zcurses init
loop $$
for jobs in $jobstates ; do
jobid=${${jobs##*:*:}%=*}
kill ${${jobs##*:*:}%=*}
done
zcurses end
The view:
After resizing the window:
2
Answers
I have now found a way to make the SIGWINCH trap work:
I now use
zcurses input
instead ofread
. But the strange thing is that it also depends onnow=$(date)
(maybe another command works too). Ifnow=$(date)
is missing, the SIGWINCH trap will not work and the window will not be redrawn.You may be able to use
zselect
. From thezshmodules
man page:The call to
zselect
here does appear to sleep for half a second: