"vscode:/vscode.git/clone" did not exist on "6ca57e035cc7c199ca7c1d893594270ec570f4d3"
Commit 4c292ea2 authored by Sebastian Gniazdowski's avatar Sebastian Gniazdowski
Browse files

Initial commit of Zsh Navigation Tools

parent 9c08641d
These are skeletons, configuration is read from ~/.config/znt/*
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
# local active_text=underline
# Hotlist
local hotlist
hotlist=(
/usr/share/zsh/site-functions
/usr/share/zsh
/usr/local/share/zsh/site-functions
/usr/local/share/zsh
/usr/local/bin
/usr/lib
)
# Suppress adding (to directory stack) directories visited by n-cd
# Value 0 is the default (directories will be added to dirstack)
local NCD_DONT_PUSHD=0
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
# local active_text=underline
# Colorize last segments of the paths
# (#s) is ^, (#e) is $, # is *, ## is + (comparing to regex)
local NLIST_COLORING_PATTERN="[a-zA-Z0-9 ._-]##/#(#e)"
local NLIST_COLORING_COLOR=$'\x1b[00;33m'
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
# local active_text=underline
# (#s) is ^, (#e) is $, # is *, ## is + (comparing to regex)
local NLIST_COLORING_PATTERN="[a-zA-Z0-9_]##"
local NLIST_COLORING_MATCH_MULTIPLE=0
# Which editor to use, zed or vared
# vared is the default
local feditor="zed"
# local feditor="vared"
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
# local active_text=underline
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
local active_text=underline
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
# local active_text=underline
# Colorize first number column and last path segment
# This doesn't cover scripts named "[0-9]## *", which should be very rare
# (#s) is ^, (#e) is $, # is *, ## is + (comparing to regex)
# | is alternative, but only in ()
local NLIST_COLORING_PATTERN="((#s) #[0-9]## |[[][^]]#](#e)|[^ 0-9/?\\\\][^/\\\\]#(#e)|[^ /\\\\]##[^0-9/\\\\ ]##[^/\\\\]#(#e))"
local NLIST_COLORING_COLOR=$'\x1b[00;33m'
local NLIST_COLORING_MATCH_MULTIPLE=1
# Should the list (text, borders) be drawn in bold
# Value 1 is the default
local bold=1
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
# local active_text=underline
# How should be current element of the list drawn. Possible values: reverse,
# underline. Default (without option set) is reverse
# On Linux virtual terminal this will be enforced to reverse (because of poor
# underline support on that terminal)
# local active_text=underline
This diff is collapsed.
# Zsh Navigation Tools
http://imageshack.com/a/img633/7967/ps6rKR.png
A tool generating a selectable curses-based list of elements that has access to
current Zsh session, i.e. has broad capabilities to work together with it.
That's n-list. The files n-cd, n-env, n-kill, etc. are applications of
the tool. Feature highlights include incremental multi-word searching, ANSI
coloring, unique mode, horizontal scroll, non-selectable elements, grepping and
various integrations with Zsh.
## History Widget
To have n-history as the incremental searcher bound to Ctrl-R copy znt-*
files into the */site-functions dir (unless you use Oh My Zsh) and
add:
autoload znt-history-widget
zle -N znt-history-widget
bindkey "^R" znt-history-widget
to .zshrc. This is done automatically when using Oh My Zsh. Two other
widgets exist, znt-cd-widget and znt-kill-widget, they can be too assigned
to key combinations:
zle -N znt-cd-widget
bindkey "^T" znt-cd-widget
zle -N znt-kill-widget
bindkey "^Y" znt-kill-widget
## Introduction
The tools are:
- n-aliases - browses aliases, relegates editing to vared
- n-cd - browses dirstack and bookmarked directories, allows to enter selected directory
- n-functions - browses functions, relegates editing to zed or vared
- n-history - browses history, allows to edit and run commands from it
- n-kill - browses processes list, allows to send signal to selected process
- n-env - browses environment, relegates editing to vared
- n-options - browses options, allows to toggle their state
- n-panelize - loads output of given command into the list for browsing
All tools support horizontal scroll with <,>, {,}, h,l or left and right
cursors. Other keys are:
- [,] - jump directory bookmarks in n-cd and typical signals in n-kill
- Ctrl-d, Ctrl-u - half page up or down
- Ctrl-p, Ctrl-n - previous and next (also done with vim's j,k)
- Ctrl-l - redraw of whole display
- g, G - beginning and end of the list
- Ctrl-o, o - enter uniq mode (no duplicate lines)
- / - start incremental search
- Enter - finish incremental search, retaining filter
- Esc - exit incremental search, clearing filter
- Ctrl-w (in incremental search) - delete whole word
- Ctrl-k (in incremental search) - delete whole line
## Programming
The function n-list is used as follows:
n-list {element1} [element2] ... [elementN]
This is all that is needed to be done to have the features like ANSI coloring,
incremental multi-word search, unique mode, horizontal scroll, non-selectable
elements (grepping is done outside n-list, see the tools for how it can be
done). To set up non-selectable entries add their indices into array
NLIST_NONSELECTABLE_ELEMENTS:
typeset -a NLIST_NONSELECTABLE_ELEMENTS
NLIST_NONSELECTABLE_ELEMENTS=( 1 )
Result is stored as $reply[REPLY] ($ isn't needed before REPLY because
of arithmetic context inside []). The returned array might be different from
input arguments as n-list can process them via incremental search or uniq
mode. $REPLY is the index in that possibly processed array. If $REPLY
equals -1 it means that no selection have been made (user quitted via q
key).
To set up entries that can be jumped to with [,] keys add their indices to
NLIST_HOP_INDEXES array:
typeset -a NLIST_HOP_INDEXES
NLIST_HOP_INDEXES=( 1 10 )
n-list can automatically colorize entries according to a Zsh pattern.
Following example will colorize all numbers with blue:
local NLIST_COLORING_PATTERN="[0-9]##"
local NLIST_COLORING_COLOR=$'\x1b[00;34m'
local NLIST_COLORING_END_COLOR=$'\x1b[0m'
local NLIST_COLORING_MATCH_MULTIPLE=1
n-list "This is a number 123" "This line too has a number: 456"
Blue is the default color, it doesn't have to be set. See zshexpn man page
for more information on Zsh patterns. Briefly, comparing to regular
expressions, (#s) is ^, (#e) is $, # is *, ## is +. Alternative
will work when in parenthesis, i.e. (a|b). BTW by using this method you can
colorize output of the tools, via their config files (check out e.g. n-cd.conf,
it uses this).
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-aliases` to .zshrc
#
# This function allows to choose an alias for edition with vared
#
# Uses n-list
emulate -L zsh
setopt extendedglob
zmodload zsh/curses
zmodload zsh/parameter
local IFS="
"
unset NLIST_COLORING_PATTERN
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
[ -f ~/.config/znt/n-aliases.conf ] && . ~/.config/znt/n-aliases.conf
local list
local selected
NLIST_REMEMBER_STATE=0
list=( "${(@k)aliases}" )
list=( "${(@M)list:#(#i)*$1*}" )
local NLIST_GREP_STRING="$1"
if [ "$#list" -eq 0 ]; then
echo "No matching aliases"
return 1
fi
list=( "${(@i)list}" )
n-list "$list[@]"
if [ "$REPLY" -gt 0 ]; then
selected="$reply[REPLY]"
echo "Editing \`$selected':"
print -rs "vared aliases\\[$selected\\]"
vared aliases\[$selected\]
fi
# vim: set filetype=zsh:
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-cd` to .zshrc
#
# This function allows to choose a directory from pushd stack
#
# Uses n-list
emulate -L zsh
setopt extendedglob pushdignoredups
zmodload zsh/curses
local IFS="
"
# Unset before configuration is read
unset NLIST_COLORING_PATTERN
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
[ -f ~/.config/znt/n-cd.conf ] && . ~/.config/znt/n-cd.conf
local list
local selected
NLIST_REMEMBER_STATE=0
list=( `dirs -p` )
list=( "${(@M)list:#(#i)*$1*}" )
local NLIST_GREP_STRING="$1"
[ "$#list" -eq 0 ] && echo "No matching directories"
if [ "$#hotlist" -ge 1 ]; then
typeset -a NLIST_NONSELECTABLE_ELEMENTS NLIST_HOP_INDEXES
local tmp_list_size="$#list"
NLIST_NONSELECTABLE_ELEMENTS=( $(( tmp_list_size+1 )) $(( tmp_list_size+2 )) )
list=( "$list[@]" "" $'\x1b[00;31m'"Hotlist"$'\x1b[00;00m': "$hotlist[@]" )
(( tmp_list_size+=3 ))
local middle_hop=$(( (tmp_list_size+$#list) / 2 ))
[[ "$middle_hop" -eq $tmp_list_size || "$middle_hop" -eq $#list ]] && middle_hop=""
[ "$tmp_list_size" -eq $#list ] && tmp_list_size=""
NLIST_HOP_INDEXES=( 1 $tmp_list_size $middle_hop $#list )
else
[ "$#list" -eq 0 ] && return 1
fi
n-list "${list[@]}"
if [ "$REPLY" -gt 0 ]; then
selected="$reply[REPLY]"
selected="${selected/#\~/$HOME}"
(( NCD_DONT_PUSHD )) && setopt NO_AUTO_PUSHD
cd "$selected"
(( NCD_DONT_PUSHD )) && setopt AUTO_PUSHD
# ZLE?
if [ "${(t)CURSOR}" = "integer-local-special" ]; then
zle -M "You have selected $selected"
else
echo "You have selected $selected"
fi
else
[ "${(t)CURSOR}" = "integer-local-special" ] && zle redisplay
fi
# vim: set filetype=zsh:
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-env` to .zshrc
#
# This function allows to choose an environment variable
# for edition with vared
#
# Uses n-list
emulate -L zsh
setopt extendedglob
unsetopt equals
zmodload zsh/curses
local IFS="
"
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
[ -f ~/.config/znt/n-env.conf ] && . ~/.config/znt/n-env.conf
local list
local selected
NLIST_REMEMBER_STATE=0
list=( `env` )
list=( "${(@M)list:#(#i)*$1*}" )
local NLIST_GREP_STRING="$1"
if [ "$#list" -eq 0 ]; then
echo "No matching variables"
return 1
fi
list=( "${(@i)list}" )
n-list "$list[@]"
if [ "$REPLY" -gt 0 ]; then
selected="$reply[REPLY]"
selected="${selected%%=*}"
echo "Editing \`$selected':"
print -rs "vared \"$selected\""
vared "$selected"
fi
# vim: set filetype=zsh:
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-functions` to .zshrc
#
# This function allows to choose a function for edition with vared
#
# Uses n-list
emulate -L zsh
setopt extendedglob
zmodload zsh/curses
zmodload zsh/parameter
local IFS="
"
unset NLIST_COLORING_PATTERN
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
[ -f ~/.config/znt/n-functions.conf ] && . ~/.config/znt/n-functions.conf
local list
local selected
NLIST_REMEMBER_STATE=0
list=( "${(@k)functions}" )
list=( "${(@M)list:#(#i)*$1*}" )
local NLIST_GREP_STRING="$1"
if [ "$#list" -eq 0 ]; then
echo "No matching functions"
return 1
fi
list=( "${(@i)list}" )
n-list "$list[@]"
if [ "$REPLY" -gt 0 ]; then
selected="$reply[REPLY]"
if [ "$feditor" = "zed" ]; then
echo "Editing \`$selected' (ESC ZZ or Ctrl-x-w to finish):"
autoload zed
print -rs "zed -f -- \"$selected\""
zed -f -- "$selected"
else
echo "Editing \`$selected':"
print -rs "vared functions\\[$selected\\]"
vared functions\[$selected\]
fi
fi
# vim: set filetype=zsh:
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-history` to .zshrc
#
# This function allows to browse Z shell's history and use the
# entries
#
# Uses n-list
emulate -L zsh
setopt extendedglob
zmodload zsh/curses
local IFS="
"
unset NLIST_COLORING_PATTERN
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
[ -f ~/.config/znt/n-history.conf ] && . ~/.config/znt/n-history.conf
local list
local selected
NLIST_REMEMBER_STATE=0
list=( `builtin history -rn 1` )
list=( "${(@M)list:#(#i)*$1*}" )
local NLIST_GREP_STRING="$1"
if [ "$#list" -eq 0 ]; then
echo "No matching history entries"
return 1
fi
n-list "${list[@]}"
if [ "$REPLY" -gt 0 ]; then
selected="$reply[REPLY]"
# ZLE?
if [ "${(t)CURSOR}" = "integer-local-special" ]; then
zle redisplay
zle kill-whole-line
zle -U "$selected"
else
print -zr "$selected"
fi
else
[ "${(t)CURSOR}" = "integer-local-special" ] && zle redisplay
fi
# vim: set filetype=zsh:
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-kill` to .zshrc
#
# This function allows to choose a process and a signal to send to it
#
# Uses n-list
emulate -L zsh
setopt extendedglob
zmodload zsh/curses
local IFS="
"
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
[ -f ~/.config/znt/n-kill.conf ] && . ~/.config/znt/n-kill.conf
typeset -A signals
signals=(
1 "1 - HUP"
2 "2 - INT"
3 "3 - QUIT"
6 "6 - ABRT"
9 "9 - KILL"
14 "14 - ALRM"
15 "15 - TERM"
17 "17 - STOP"
19 "19 - CONT"
)
local list
local selected
local signal
local -a signal_names
local title
NLIST_REMEMBER_STATE=0
typeset -a NLIST_NONSELECTABLE_ELEMENTS
NLIST_NONSELECTABLE_ELEMENTS=( 1 )
type ps 2>/dev/null 1>&2 || { echo >&2 "Error: \`ps' not found"; return 1 }
case "$(uname)" in
CYGWIN*) list=( `command ps -Wa` ) ;;
*) list=( `command ps -o pid,uid,command -A` ) ;;
esac
# Ask of PID
title=$'\x1b[00;31m'"${list[1]}"$'\x1b[00;00m\0'
shift list
list=( "$title" "${(@M)list:#(#i)*$1*}" )
local NLIST_GREP_STRING="$1"
if [ "$#list" -eq 1 ]; then
echo "No matching processes"
return 1
fi
n-list "$list[@]"
# Got answer? (could be Ctrl-C or 'q')
if [ "$REPLY" -gt 0 ]; then
selected="$reply[REPLY]"
selected="${selected## #}"
pid="${selected%% *}"
# Now ask of signal
signal_names=( ${(vin)signals} )
typeset -a NLIST_HOP_INDEXES
NLIST_HOP_INDEXES=( 3 6 8 )
unset NLIST_COLORING_PATTERN
n-list $'\x1b[00;31mSelect signal:\x1b[00;00m' "$signal_names[@]"
if [ "$REPLY" -gt 0 ]; then
selected="$reply[REPLY]"
signal="${(k)signals[(r)$selected]}"
# ZLE?
if [ "${(t)CURSOR}" = "integer-local-special" ]; then
zle redisplay
zle kill-whole-line
zle -U "kill -$signal $pid"
else
print -zr "kill -$signal $pid"
fi
else
[ "${(t)CURSOR}" = "integer-local-special" ] && zle redisplay
fi
else
[ "${(t)CURSOR}" = "integer-local-special" ] && zle redisplay
fi
# vim: set filetype=zsh:
# $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
#
# 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="-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_coloring_list_into_col_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
col_list=( "${(@)list//(#mi)$~NLIST_COLORING_PATTERN/$col${MATCH}$reset}" )
else
col_list=( "${(@)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"
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 col_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
# 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
# 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 [ "$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
zcurses bg main white/black
zcurses bg inner white/black
if [ "$NLIST_IS_SEARCH_MODE" -ne 1 ]; then
_nlist_cursor_visibility 0
fi
#
# Listening for input
#
local key keypad
# Clear input buffer
zcurses timeout main 0
zcurses input main key keypad
zcurses timeout main -1
key=""
keypad=""
list=( "$@" )
last_element="$#list"
integer is_colored=0
if [[ -z "$NLIST_SEARCH_BUFFER" && -n "$NLIST_COLORING_PATTERN" ]]; then
is_colored=1
_nlist_coloring_list_into_col_list
fi
while (( 1 )); do
# Do searching (filtering with string)
if [ -n "$NLIST_SEARCH_BUFFER" ]; then
# Compute new list, col_list ?
if [[ "$NLIST_SEARCH_BUFFER" != "$prev_search_buffer" || "$NLIST_IS_UNIQ_MODE" -ne "$prev_uniq_mode" ]]; then
prev_search_buffer="$NLIST_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
list=( "$@" )
# Remove non-selectable elements
[ "$#NLIST_NONSELECTABLE_ELEMENTS" -gt 0 ] && for i in "${(nO)NLIST_NONSELECTABLE_ELEMENTS[@]}"; do
list[$i]=()
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}"
if [ -n "$search_buffer" ]; then
# Patterns will be *foo*~^*bar* and foo|bar)
local search_pattern="${search_buffer// ##/*~^*}"
local colsearch_pattern="${search_buffer// ##/|}"
list=( "${(@M)list:#(#i)*$~search_pattern*}" )
last_element="$#list"
local red=$'\x1b[00;31m' reset=$'\x1b[00;00m'
col_list=( "${(@)list//(#mi)($~colsearch_pattern)/$red${MATCH}$reset}" )
else
col_list=( "$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=( "${(@)col_list[NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN, end_idx]}" )
fi
# Output colored list
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 (maybe also col_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
list=( "$@" )
# 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
list[$i]=()
done
# Remove duplicates when in uniq mode
[ "$NLIST_IS_UNIQ_MODE" -eq 1 ] && typeset -U list
# Apply coloring pattern (when not with search query)
is_colored=0
if [ -n "$NLIST_COLORING_PATTERN" ]; then
is_colored=1
_nlist_coloring_list_into_col_list
fi
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 [ "$is_colored" -eq 0 ]; then
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]}" )
fi
else
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=( "${(@)col_list[NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN, end_idx]}" )
fi
fi
# Output the list
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
if [ "$NLIST_IS_SEARCH_MODE" = "1" ]; then
local _txt2=""
[ "$NLIST_IS_UNIQ_MODE" -eq 1 ] && _txt2="[-UNIQ-] "
_nlist_status_msg "${_txt2}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="" _txt2=""
[ -n "$NLIST_GREP_STRING" ] && _txt=" [$NLIST_GREP_STRING]"
[ "$NLIST_IS_UNIQ_MODE" -eq 1 ] && _txt2="[-UNIQ-] "
_nlist_status_msg "${_txt2}Current #$NLIST_USER_CURRENT_IDX (of #$NLIST_USER_LAST_ELEMENT entries)$_txt"
else
_nlist_status_msg ""
fi
zcurses border main
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"
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]"
if [ "$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
fi
done
# vim: set filetype=zsh:
# Copy this file into /usr/share/zsh/site-functions/
# and add 'autoload n-list-draw` to .zshrc
#
# This is an internal function not for direct use
emulate -L zsh
zmodload zsh/curses
setopt typesetsilent extendedglob
_nlist_print_with_ansi() {
local win="$1" text="$2" out col chunk Xout
integer text_offset="$3" max_text_len="$4" text_len=0 no_match=0 nochunk_text_len to_skip_from_chunk to_chop_off_from_chunk before_len
# 1 - non-escaped text, 2 - first number in the escaped text, with ;
# 3 - second number, 4 - text after whole escape text
typeset -a c
c=( black red green yellow blue magenta cyan white )
while [[ -n "$text" && "$no_match" -eq 0 ]]; do
if [[ "$text" = (#b)([^$'\x1b']#)$'\x1b'\[([0-9](#c0,2))(#B)(\;|)(#b)([0-9](#c0,2))m(*) ]]; then
# Text for further processing
text="$match[4]"
# Text chunk to output now
out="$match[1]"
# Save color
col="$match[2]"
(( match[3] >= 30 && match[3] <= 37 )) && col="$match[3]"
else
out="$text"
no_match=1
fi
if [ -n "$out" ]; then
################ Expand tabs ################
chunk="$out"
before_len="$text_len"
Xout=""
while [ -n "$chunk" ]; do
[[ "$chunk" = (#b)([^$'\t']#)$'\t'(*) ]] && {
(( all_text_len=((before_len+${#match[1]})/8+1)*8 ))
Xout+="${(r:all_text_len-before_len:: :)match[1]}"
before_len+=all_text_len-before_len
chunk="$match[2]"
} || {
Xout+="$chunk"
break
}
done
#############################################
# Input text length without the current chunk
nochunk_text_len=text_len
# Input text length up to current chunk
text_len+="$#Xout"
# Should start displaying with this chunk?
# I.e. stop skipping left part of the input text?
if (( text_len > text_offset )); then
to_skip_from_chunk=text_offset-nochunk_text_len
# LEFT - is chunk off the left skip boundary? +1 for 1-based index in string
(( to_skip_from_chunk > 0 )) && Xout="${Xout[to_skip_from_chunk+1,-1]}"
# RIGHT - is text off the screen?
if (( text_len-text_offset > max_text_len )); then
to_chop_off_from_chunk=0+(text_len-text_offset)-max_text_len
Xout="${Xout[1,-to_chop_off_from_chunk-1]}"
fi
[ -n "$Xout" ] && zcurses string "$win" "$Xout"
fi
fi
if (( no_match == 0 )); then
if (( col >= 30 && col <= 37 )); then
zcurses attr "$win" $c[col-29]/black
elif [[ "$col" -eq 0 ]]; then
zcurses attr "$win" white/black
fi
fi
done
}
integer highlight="$1"
integer page_height="$2"
integer page_width="$3"
local y_offset="$4"
local x_offset="$5"
local text_offset="$6"
local win="$7"
shift 7
integer max_text_len=page_width-x_offset
[ "$bold" = "0" ] && bold="" || bold="+bold"
[[ "$active_text" = "underline" || "$active_text" = "reverse" ]] || active_text="reverse"
# With Linux terminal underline won't work properly
[ "$TERM" = "linux" ] && active_text="reverse"
integer max_idx=page_height
integer end_idx=max_idx
[ "$end_idx" -gt "$#" ] && end_idx="$#"
integer y=y_offset
zcurses attr "$win" $bold white/black
integer i text_len
local text
for (( i=1; i<=end_idx; i++ )); do
zcurses move "$win" $y "$x_offset"
[ "$i" = "$highlight" ] && zcurses attr "$win" +"$active_text"
_nlist_print_with_ansi "$win" "$@[i]" "$text_offset" "$max_text_len"
zcurses clear "$win" eol
[ "$i" = "$highlight" ] && zcurses attr "$win" -"$active_text"
y+=1
done
if [ "$end_idx" -lt "$max_idx" ]; then
zcurses move "$win" $y "$x_offset"
zcurses clear "$win" eol
fi
zcurses attr "$win" white/black
# vim: set filetype=zsh:
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment