我正在寻找一个这样的程序less
,我可以传递多行文本并让用户以交互方式选择一行。
这将用于查看和选择 shell 历史记录,尽管我很可能会想出其他用途。
有人知道这样的程序吗?
我正在考虑使用 zcurses zsh 模块来创建它,但那会很麻烦。如果有其他更简单的选择那就更好了。
答案1
使用 zcurses 模块比我想象的要容易得多。这就是我想到的。
#!/bin/zsh
#
# Usage:
# Call `many.init [listname] [values]` then `many.loop` when it returns REPLY
# will be set to the selected value.
#
# Example:
# many.init History $history
# many.loop
# echo $REPLY
#
##
zmodload zsh/curses
(( size=LINES ))
typeset -i selected pos
pos=1
selected=$size
many.init ()
{
name=$1
shift
elements=( "$@" )
zcurses init
many.draw
}
many.loop ()
{
while true; do
zcurses input stdscr raw key
many.read $raw $key || return
done
}
many.read ()
{
case $1 in
'q')
zcurses end
typeset -g REPLY
REPLY=$elements[selected]
return 1
;;
"UP")
if (( selected > 1 )); then
(( selected <= pos)) && (( pos-- ))
(( selected-- ))
fi
;;
"DOWN")
if (( selected < ${#elements} )); then
(( selected >= pos+size-1)) && (( pos++ ))
(( selected++ ))
fi
;;
"PPAGE")
(( pos=pos-size, selected=selected-size ))
(( pos < 1 )) && pos=1
(( selected < 1 )) && selected=1
;;
"NPAGE")
(( pos=pos+size, selected=selected+size ))
(( pos > ${#elements} )) && pos=${#elements}
(( selected > ${#elements} )) && selected=${#elements}
;;
esac
many.draw
}
many.draw ()
{
typeset -i offset
offset=0
zcurses clear stdscr
for (( i=0; i+offset < size; i++ )); do
if (( i+pos == selected )); then
zcurses attr stdscr black/white
lines=( ${(@fr:$COLUMNS:)elements[i+pos]} )
zcurses string stdscr "${(j::)lines}"
(( offset=offset+${#lines}-1 ))
zcurses attr stdscr default/default
else
zcurses string stdscr "${elements[i+pos]/
*/...}
"
fi
done
zcurses attr stdscr white/black
zcurses string stdscr "$name line $selected (Press 'q' to select)"
zcurses attr stdscr default/default
zcurses refresh
}