我将 zsh 和 zsh/curses 用于小型命令行界面。当窗口大小改变时,视图的内容应该自动调整。我尝试了使用 trap SIGWINCH 的解决方案,但是使用 zsh(我在 Ubuntu 和 macOS 上尝试过)trap SIGWINCH 显然不起作用。因此,我使用了一个带有繁忙循环的后台 shell(请参阅下面的
monitorwindowsize
),该循环将 SIGUSR1 发送到父 shell 以向其发出信号以调整窗口大小。我发现让内部循环等待一段时间的唯一解决方案是调用 sleep
(例如,调用 read -t 10
在这里不起作用),但是 - 你知道 - sleep 每次被调用时都会创建一个新进程。当然,我想尽可能快地调用 resize 函数,所以我有兴趣保持睡眠时间尽可能短,即经常调用 sleep 。所以我的问题是,在 zsh 下是否有在子 shell 中工作的睡眠替代方案。或者有没有比使用这个 zsh/curses 代码的繁忙循环更好的解决方案。
代码:
#!/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
景色:
调整窗口大小后:
您也许可以使用
zselect
。来自zshmodules
手册页:
可以在没有文件描述符和非零的情况下调用
用作“睡眠”的更细粒度替代品的超时;笔记, 但是,超时返回状态始终为 1。zselect
这里对
zselect
的调用确实出现了半秒的休眠:
> zmodload zsh/zselect
> type zselect
zselect is a shell builtin
> zselect -t 50
>
我现在找到了使 SIGWINCH 陷阱起作用的方法:
#!/bin/zsh
zmodload zsh/curses
loop ()
{
view
while true; do
unset raw
unset key
zcurses timeout mywin 50
zcurses input mywin raw key
now=$(date)
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
}
TRAPWINCH() {
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
这取决于
now=$(date)
(也许另一个命令也可以),如果缺少now=$(date)
,陷阱将不起作用,窗口将不会重绘。