This repository has been archived on 2025-01-31. You can view files and clone it, but cannot push or open issues or pull requests.
Files
.bin
.config
.local
.ncmpcpp
.oh-my-zsh
lib
plugins
adb
ant
apache2-macports
arcanist
archlinux
asdf
autoenv
autojump
autopep8
aws
battery
bbedit
bgnotify
boot2docker
bower
branch
brew
bundler
bwana
cabal
cake
cakephp3
capistrano
cargo
cask
catimg
celery
chruby
chucknorris
cloudapp
codeclimate
coffee
colemak
colored-man-pages
colorize
command-not-found
common-aliases
compleat
composer
copybuffer
copydir
copyfile
cp
cpanm
debian
dircycle
dirhistory
dirpersist
django
dnf
docker
docker-compose
dotenv
droplr
emacs
ember-cli
emoji
emoji-clock
emotty
encode64
extract
fabric
fancy-ctrl-z
fasd
fastfile
fbterm
fedora
firewalld
forklift
fossil
frontend-search
gas
gb
geeknote
gem
git
git-extras
git-flow
git-flow-avh
git-hubflow
git-prompt
git-remote-branch
gitfast
github
gitignore
glassfish
globalias
gnu-utils
go
golang
gpg-agent
gradle
grails
grunt
gulp
heroku
history
history-substring-search
httpie
iwhois
jake-node
jhbuild
jira
jruby
jsontools
jump
kate
kitchen
knife
knife_ssh
kubectl
laravel
laravel4
laravel5
last-working-dir
lein
lighthouse
lol
macports
man
marked2
mercurial
meteor
mix
mix-fast
mosh
mvn
mysql-macports
n98-magerun
nanoc
ng
nmap
node
nomad
npm
nvm
nyan
osx
pass
paver
pep8
per-directory-history
perl
perms
phing
pip
pj
pod
postgres
pow
powder
powify
profiles
pyenv
pylint
python
rails
rake
rake-fast
rand-quote
rbenv
rbfu
react-native
rebar
redis-cli
repo
rsync
ruby
rust
rvm
safe-paste
sbt
scala
scd
screen
scw
sfffe
shrink-path
singlechar
spring
sprunge
ssh-agent
stack
sublime
sudo
supervisor
suse
svn
svn-fast-info
swiftpm
symfony
symfony2
systemadmin
systemd
taskwarrior
terminalapp
terminitor
terraform
textastic
textmate
thefuck
themes
thor
tig
tmux
tmux-cssh
tmuxinator
torrent
tugboat
ubuntu
urltools
vagrant
vault
vi-mode
vim-interaction
virtualenv
virtualenvwrapper
vundle
wakeonlan
wd
web-search
wp-cli
xcode
yarn
yii
yii2
yum
z
zeus
zsh-navigation-tools
.config
LICENSE
NEWS
README.md
_n-kill
n-aliases
n-cd
n-env
n-functions
n-help
n-history
n-kill
n-list
n-list-draw
n-list-input
n-options
n-panelize
znt-cd-widget
znt-history-widget
znt-kill-widget
znt-tmux.zsh
znt-usetty-wrapper
zsh-navigation-tools.plugin.zsh
zsh_reload
templates
themes
tools
CONTRIBUTING.md
LICENSE.txt
README.md
oh-my-zsh.sh
.themes
.vim
.Xdefaults
.Xresources
.bash_profile
.profile
.vimrc
.xinitrc
.xsessionrc
.zshrc
README.md
home/.oh-my-zsh/plugins/zsh-navigation-tools/n-list

516 lines
17 KiB
Bash

# $1, $2, ... - elements of the list
# $NLIST_NONSELECTABLE_ELEMENTS - array of indexes (1-based) that cannot be selected
# $REPLY is the output variable - contains index (1-based) or -1 when no selection
# $reply (array) is the second part of the output - use the index (REPLY) to get selected element
#
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-list` to .zshrc
#
# This function outputs a list of elements that can be
# navigated with keyboard. Uses curses library
emulate -LR zsh
setopt typesetsilent extendedglob noshortloops
_nlist_has_terminfo=0
zmodload zsh/curses
zmodload zsh/terminfo 2>/dev/null && _nlist_has_terminfo=1
trap "REPLY=-2; reply=(); return" TERM INT QUIT
trap "_nlist_exit" EXIT
# Drawing and input
autoload n-list-draw n-list-input
# Cleanup before any exit
_nlist_exit() {
setopt localoptions
setopt extendedglob
[[ "$REPLY" = -(#c0,1)[0-9]## || "$REPLY" = F<-> || "$REPLY" = "EDIT" || "$REPLY" = "HELP" ]] || REPLY="-1"
zcurses 2>/dev/null delwin inner
zcurses 2>/dev/null delwin main
zcurses 2>/dev/null refresh
zcurses end
_nlist_alternate_screen 0
_nlist_cursor_visibility 1
unset _nlist_has_terminfo
}
# Outputs a message in the bottom of the screen
_nlist_status_msg() {
# -1 for border, -1 for 0-based indexing
zcurses move main $(( term_height - 1 - 1 )) 2
zcurses clear main eol
zcurses string main "$1"
#status_msg_strlen is localized in caller
status_msg_strlen=$#1
}
# Prefer tput, then module terminfo
_nlist_cursor_visibility() {
if type tput 2>/dev/null 1>&2; then
[ "$1" = "1" ] && { tput cvvis; tput cnorm }
[ "$1" = "0" ] && tput civis
elif [ "$_nlist_has_terminfo" = "1" ]; then
[ "$1" = "1" ] && { [ -n $terminfo[cvvis] ] && echo -n $terminfo[cvvis];
[ -n $terminfo[cnorm] ] && echo -n $terminfo[cnorm] }
[ "$1" = "0" ] && [ -n $terminfo[civis] ] && echo -n $terminfo[civis]
fi
}
# Reason for this function is that on some systems
# smcup and rmcup are not knowing why left empty
_nlist_alternate_screen() {
[ "$_nlist_has_terminfo" -ne "1" ] && return
[[ "$1" = "1" && -n "$terminfo[smcup]" ]] && return
[[ "$1" = "0" && -n "$terminfo[rmcup]" ]] && return
case "$TERM" in
*rxvt*)
[ "$1" = "1" ] && echo -n $'\x1b7\x1b[?47h'
[ "$1" = "0" ] && echo -n $'\x1b[2J\x1b[?47l\x1b8'
;;
*)
[ "$1" = "1" ] && echo -n $'\x1b[?1049h'
[ "$1" = "0" ] && echo -n $'\x1b[?1049l'
# just to remember two other that work: $'\x1b7\x1b[r\x1b[?47h', $'\x1b[?47l\x1b8'
;;
esac
}
_nlist_compute_user_vars_difference() {
if [[ "${(t)NLIST_NONSELECTABLE_ELEMENTS}" != "array" &&
"${(t)NLIST_NONSELECTABLE_ELEMENTS}" != "array-local" ]]
then
last_element_difference=0
current_difference=0
else
last_element_difference=$#NLIST_NONSELECTABLE_ELEMENTS
current_difference=0
local idx
for idx in "${(n)NLIST_NONSELECTABLE_ELEMENTS[@]}"; do
[ "$idx" -le "$NLIST_CURRENT_IDX" ] && current_difference+=1 || break
done
fi
}
# List was processed, check if variables aren't off range
_nlist_verify_vars() {
[ "$NLIST_CURRENT_IDX" -gt "$last_element" ] && NLIST_CURRENT_IDX="$last_element"
[[ "$NLIST_CURRENT_IDX" -eq 0 && "$last_element" -ne 0 ]] && NLIST_CURRENT_IDX=1
(( NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=0+((NLIST_CURRENT_IDX-1)/page_height)*page_height+1 ))
}
# Compute the variables which are shown to the user
_nlist_setup_user_vars() {
if [ "$1" = "1" ]; then
# Basic values when there are no non-selectables
NLIST_USER_CURRENT_IDX="$NLIST_CURRENT_IDX"
NLIST_USER_LAST_ELEMENT="$last_element"
else
_nlist_compute_user_vars_difference
NLIST_USER_CURRENT_IDX=$(( NLIST_CURRENT_IDX - current_difference ))
NLIST_USER_LAST_ELEMENT=$(( last_element - last_element_difference ))
fi
}
_nlist_colorify_disp_list() {
local col=$'\x1b[00;34m' reset=$'\x1b[0m'
[ -n "$NLIST_COLORING_COLOR" ] && col="$NLIST_COLORING_COLOR"
[ -n "$NLIST_COLORING_END_COLOR" ] && reset="$NLIST_COLORING_END_COLOR"
if [ "$NLIST_COLORING_MATCH_MULTIPLE" -eq 1 ]; then
disp_list=( "${(@)disp_list//(#mi)$~NLIST_COLORING_PATTERN/$col${MATCH}$reset}" )
else
disp_list=( "${(@)disp_list/(#mi)$~NLIST_COLORING_PATTERN/$col${MATCH}$reset}" )
fi
}
#
# Main code
#
# Check if there is proper input
if [ "$#" -lt 1 ]; then
echo "Usage: n-list element_1 ..."
return 1
fi
REPLY="-1"
typeset -ga reply
reply=()
integer term_height="$LINES"
integer term_width="$COLUMNS"
if [[ "$term_height" -lt 1 || "$term_width" -lt 1 ]]; then
local stty_out=$( stty size )
term_height="${stty_out% *}"
term_width="${stty_out#* }"
fi
integer inner_height=term_height-3
integer inner_width=term_width-3
integer page_height=inner_height
integer page_width=inner_width
typeset -a list disp_list
integer last_element=$#
local action
local final_key
integer selection
integer last_element_difference=0
integer current_difference=0
local prev_search_buffer=""
integer prev_uniq_mode=0
integer prev_start_idx=-1
local MBEGIN MEND MATCH mbegin mend match
# Iteration over predefined keywords
integer curkeyword nkeywords
local keywordisfresh="0"
if [[ "${(t)keywords}" != *array* ]]; then
local -a keywords
keywords=()
fi
curkeyword=0
nkeywords=${#keywords}
# Iteration over themes
integer curtheme nthemes
local themeisfresh="0"
if [[ "${(t)themes}" != *array* ]]; then
local -a themes
themes=()
fi
curtheme=0
nthemes=${#themes}
# Ability to remember the list between calls
if [[ -z "$NLIST_REMEMBER_STATE" || "$NLIST_REMEMBER_STATE" -eq 0 || "$NLIST_REMEMBER_STATE" -eq 2 ]]; then
NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN=1
NLIST_CURRENT_IDX=1
NLIST_IS_SEARCH_MODE=0
NLIST_SEARCH_BUFFER=""
NLIST_TEXT_OFFSET=0
NLIST_IS_UNIQ_MODE=0
NLIST_IS_F_MODE=0
# Zero - because it isn't known, unless we
# confirm that first element is selectable
NLIST_USER_CURRENT_IDX=0
[[ ${NLIST_NONSELECTABLE_ELEMENTS[(r)1]} != 1 ]] && NLIST_USER_CURRENT_IDX=1
NLIST_USER_LAST_ELEMENT=$(( last_element - $#NLIST_NONSELECTABLE_ELEMENTS ))
# 2 is init once, then remember
[ "$NLIST_REMEMBER_STATE" -eq 2 ] && NLIST_REMEMBER_STATE=1
fi
if [ "$NLIST_START_IN_SEARCH_MODE" -eq 1 ]; then
NLIST_START_IN_SEARCH_MODE=0
NLIST_IS_SEARCH_MODE=1
fi
if [ -n "$NLIST_SET_SEARCH_TO" ]; then
NLIST_SEARCH_BUFFER="$NLIST_SET_SEARCH_TO"
NLIST_SET_SEARCH_TO=""
fi
if [ "$NLIST_START_IN_UNIQ_MODE" -eq 1 ]; then
NLIST_START_IN_UNIQ_MODE=0
NLIST_IS_UNIQ_MODE=1
fi
_nlist_alternate_screen 1
zcurses init
zcurses delwin main 2>/dev/null
zcurses delwin inner 2>/dev/null
zcurses addwin main "$term_height" "$term_width" 0 0
zcurses addwin inner "$inner_height" "$inner_width" 1 2
# From n-list.conf
[ "$colorpair" = "" ] && colorpair="white/black"
[ "$border" = "0" ] || border="1"
local background="${colorpair#*/}"
local backuptheme="$colorpair/$bold"
zcurses bg main "$colorpair"
zcurses bg inner "$colorpair"
if [ "$NLIST_IS_SEARCH_MODE" -ne 1 ]; then
_nlist_cursor_visibility 0
fi
zcurses refresh
#
# Listening for input
#
local key keypad
# Clear input buffer
zcurses timeout main 0
zcurses input main key keypad
zcurses timeout main -1
key=""
keypad=""
# This loop makes script faster on some Zsh's (e.g. 5.0.8)
repeat 1; do
list=( "$@" )
done
last_element="$#list"
while (( 1 )); do
# Do searching (filtering with string)
if [ -n "$NLIST_SEARCH_BUFFER" ]; then
# Compute new list?
if [[ "$NLIST_SEARCH_BUFFER" != "$prev_search_buffer" || "$NLIST_IS_UNIQ_MODE" -ne "$prev_uniq_mode"
|| "$NLIST_IS_F_MODE" -ne "$prev_f_mode" ]]
then
prev_search_buffer="$NLIST_SEARCH_BUFFER"
prev_uniq_mode="$NLIST_IS_UNIQ_MODE"
prev_f_mode="$NLIST_IS_F_MODE"
# regenerating list -> regenerating disp_list
prev_start_idx=-1
# Take all elements, including duplicates and non-selectables
typeset +U list
repeat 1; do
list=( "$@" )
done
# Remove non-selectable elements
[ "$#NLIST_NONSELECTABLE_ELEMENTS" -gt 0 ] && for i in "${(nO)NLIST_NONSELECTABLE_ELEMENTS[@]}"; do
if [[ "$i" = <-> ]]; then
list[$i]=()
fi
done
# Remove duplicates
[ "$NLIST_IS_UNIQ_MODE" -eq 1 ] && typeset -U list
last_element="$#list"
# Next do the filtering
local search_buffer="${NLIST_SEARCH_BUFFER%% ##}"
search_buffer="${search_buffer## ##}"
search_buffer="${search_buffer//(#m)[][*?|#~^()><\\]/\\$MATCH}"
local search_pattern=""
local colsearch_pattern=""
if [ -n "$search_buffer" ]; then
# The repeat will make the matching work on a fresh heap
repeat 1; do
if [ "$NLIST_IS_F_MODE" -eq "1" ]; then
search_pattern="${search_buffer// ##/*~^(#a1)*}"
colsearch_pattern="${search_buffer// ##/|(#a1)}"
list=( "${(@M)list:#(#ia1)*$~search_pattern*}" )
elif [ "$NLIST_IS_F_MODE" -eq "2" ]; then
search_pattern="${search_buffer// ##/*~^(#a2)*}"
colsearch_pattern="${search_buffer// ##/|(#a2)}"
list=( "${(@M)list:#(#ia2)*$~search_pattern*}" )
else
# Pattern will be *foo*~^*bar* (inventor: Mikael Magnusson)
search_pattern="${search_buffer// ##/*~^*}"
# Pattern will be (foo|bar)
colsearch_pattern="${search_buffer// ##/|}"
list=( "${(@M)list:#(#i)*$~search_pattern*}" )
fi
done
last_element="$#list"
fi
# Called after processing list
_nlist_verify_vars
fi
_nlist_setup_user_vars 1
integer end_idx=$(( NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN + page_height - 1 ))
[ "$end_idx" -gt "$last_element" ] && end_idx=last_element
if [ "$prev_start_idx" -ne "$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN" ]; then
prev_start_idx="$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN"
disp_list=( "${(@)list[NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN, end_idx]}" )
if [ -n "$colsearch_pattern" ]; then
local red=$'\x1b[00;31m' reset=$'\x1b[00;00m'
# The repeat will make the matching work on a fresh heap
repeat 1; do
if [ "$NLIST_IS_F_MODE" -eq "1" ]; then
disp_list=( "${(@)disp_list//(#mia1)($~colsearch_pattern)/$red${MATCH}$reset}" )
elif [ "$NLIST_IS_F_MODE" -eq "2" ]; then
disp_list=( "${(@)disp_list//(#mia2)($~colsearch_pattern)/$red${MATCH}$reset}" )
else
disp_list=( "${(@)disp_list//(#mi)($~colsearch_pattern)/$red${MATCH}$reset}" )
fi
done
fi
# We have display list, lets replace newlines with "\n" when needed (1/2)
[ "$NLIST_REPLACE_NEWLINES" -eq 1 ] && disp_list=( "${(@)disp_list//$'\n'/\\n}" )
fi
# Output colored list
zcurses clear inner
n-list-draw "$(( (NLIST_CURRENT_IDX-1) % page_height + 1 ))" \
"$page_height" "$page_width" 0 0 "$NLIST_TEXT_OFFSET" inner \
"$disp_list[@]"
else
# There is no search, but there was in previous loop
# OR
# Uniq mode was entered or left out
# -> compute new list
if [[ -n "$prev_search_buffer" || "$NLIST_IS_UNIQ_MODE" -ne "$prev_uniq_mode" ]]; then
prev_search_buffer=""
prev_uniq_mode="$NLIST_IS_UNIQ_MODE"
# regenerating list -> regenerating disp_list
prev_start_idx=-1
# Take all elements, including duplicates and non-selectables
typeset +U list
repeat 1; do
list=( "$@" )
done
# Remove non-selectable elements only when in uniq mode
[ "$NLIST_IS_UNIQ_MODE" -eq 1 ] && [ "$#NLIST_NONSELECTABLE_ELEMENTS" -gt 0 ] &&
for i in "${(nO)NLIST_NONSELECTABLE_ELEMENTS[@]}"; do
if [[ "$i" = <-> ]]; then
list[$i]=()
fi
done
# Remove duplicates when in uniq mode
[ "$NLIST_IS_UNIQ_MODE" -eq 1 ] && typeset -U list
last_element="$#list"
# Called after processing list
_nlist_verify_vars
fi
# "1" - shouldn't bother with non-selectables
_nlist_setup_user_vars "$NLIST_IS_UNIQ_MODE"
integer end_idx=$(( NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN + page_height - 1 ))
[ "$end_idx" -gt "$last_element" ] && end_idx=last_element
if [ "$prev_start_idx" -ne "$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN" ]; then
prev_start_idx="$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN"
disp_list=( "${(@)list[NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN, end_idx]}" )
[ -n "$NLIST_COLORING_PATTERN" ] && _nlist_colorify_disp_list
# We have display list, lets replace newlines with "\n" when needed (2/2)
[ "$NLIST_REPLACE_NEWLINES" -eq 1 ] && disp_list=( "${(@)disp_list//$'\n'/\\n}" )
fi
# Output the list
zcurses clear inner
n-list-draw "$(( (NLIST_CURRENT_IDX-1) % page_height + 1 ))" \
"$page_height" "$page_width" 0 0 "$NLIST_TEXT_OFFSET" inner \
"$disp_list[@]"
fi
local status_msg_strlen
local keywordmsg=""
if [ "$keywordisfresh" = "1" ]; then
keywordmsg="($curkeyword/$nkeywords) "
keywordisfresh="0"
fi
local thememsg=""
if [ "$themeisfresh" = "1" ]; then
local theme="$backuptheme"
[ "$curtheme" -gt 0 ] && theme="${themes[curtheme]}"
thememsg="($curtheme/$nthemes $theme) "
themeisfresh="0"
fi
local _txt2="" _txt3=""
[ "$NLIST_IS_UNIQ_MODE" -eq 1 ] && _txt2="[-UNIQ-] "
[ "$NLIST_IS_F_MODE" -eq 1 ] && _txt3="[-FIX-] "
[ "$NLIST_IS_F_MODE" -eq 2 ] && _txt3="[-FIX2-] "
if [ "$NLIST_IS_SEARCH_MODE" = "1" ]; then
_nlist_status_msg "${_txt2}${_txt3}${keywordmsg}${thememsg}Filtering with: ${NLIST_SEARCH_BUFFER// /+}"
elif [[ ${NLIST_NONSELECTABLE_ELEMENTS[(r)$NLIST_CURRENT_IDX]} != $NLIST_CURRENT_IDX ||
-n "$NLIST_SEARCH_BUFFER" || "$NLIST_IS_UNIQ_MODE" -eq 1 ]]; then
local _txt=""
[ -n "$NLIST_GREP_STRING" ] && _txt=" [$NLIST_GREP_STRING]"
_nlist_status_msg "${_txt2}${_txt3}${keywordmsg}${thememsg}Current #$NLIST_USER_CURRENT_IDX (of #$NLIST_USER_LAST_ELEMENT entries)$_txt"
else
_nlist_status_msg "${keywordmsg}${thememsg}"
fi
[ "$border" = "1" ] && zcurses border main
local top_msg=" ${(C)ZSH_NAME} $ZSH_VERSION, shell level $SHLVL "
if [[ "${NLIST_ENABLED_EVENTS[(r)F1]}" = "F1" ]]; then
top_msg=" F1-change view,$top_msg"
fi
zcurses move main 0 $(( term_width / 2 - $#top_msg / 2 ))
zcurses string main $top_msg
zcurses refresh main inner
zcurses move main $(( term_height - 1 - 1 )) $(( status_msg_strlen + 2 ))
# Wait for input
zcurses input main key keypad
# Get the special (i.e. "keypad") key or regular key
if [ -n "$key" ]; then
final_key="$key"
elif [ -n "$keypad" ]; then
final_key="$keypad"
else
_nlist_status_msg "Inproper input detected"
zcurses refresh main inner
fi
n-list-input "$NLIST_CURRENT_IDX" "$NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN" \
"$page_height" "$page_width" "$last_element" "$NLIST_TEXT_OFFSET" \
"$final_key" "$NLIST_IS_SEARCH_MODE" "$NLIST_SEARCH_BUFFER" \
"$NLIST_IS_UNIQ_MODE" "$NLIST_IS_F_MODE"
selection="$reply[1]"
action="$reply[2]"
NLIST_CURRENT_IDX="$reply[3]"
NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN="$reply[4]"
NLIST_TEXT_OFFSET="$reply[5]"
NLIST_IS_SEARCH_MODE="$reply[6]"
NLIST_SEARCH_BUFFER="$reply[7]"
NLIST_IS_UNIQ_MODE="$reply[8]"
NLIST_IS_F_MODE="$reply[9]"
if [ -z "$action" ]; then
continue
elif [ "$action" = "SELECT" ]; then
REPLY="$selection"
reply=( "$list[@]" )
break
elif [ "$action" = "QUIT" ]; then
REPLY=-1
reply=( "$list[@]" )
break
elif [ "$action" = "REDRAW" ]; then
zcurses clear main redraw
zcurses clear inner redraw
elif [[ "$action" = F<-> ]]; then
REPLY="$action"
reply=( "$list[@]" )
break
elif [[ "$action" = "EDIT" ]]; then
REPLY="EDIT"
reply=( "$list[@]" )
break
elif [[ "$action" = "HELP" ]]; then
REPLY="HELP"
reply=( "$list[@]" )
break
fi
done
# vim: set filetype=zsh: