mirror of
https://github.com/ohmyzsh/ohmyzsh.git
synced 2026-03-27 03:14:56 +01:00
1239 lines
31 KiB
Bash
1239 lines
31 KiB
Bash
# The preamble comments apply when using ZNT as autoload functions
|
||
# https://github.com/psprint/zsh-navigation-tools
|
||
# License is GPLv3
|
||
# ff7aa5840399c624ab753b58e2f3b18ef8ffebd3 refs/heads/master
|
||
|
||
n-aliases() {
|
||
# 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 localoptions extendedglob
|
||
zmodload zsh/curses
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.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:
|
||
}
|
||
alias naliases=n-aliases
|
||
|
||
n-cd() {
|
||
# 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 localoptions extendedglob pushdignoredups
|
||
|
||
zmodload zsh/curses
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.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"
|
||
|
||
[ -f ~/.config/znt/n-cd.conf ] && . ~/.config/znt/n-cd.conf
|
||
if [ "$#hotlist" -gt 1 ]; then
|
||
typeset -a NLIST_NONSELECTABLE_ELEMENTS NLIST_HOP_INDEXES
|
||
integer 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[@]" )
|
||
NLIST_HOP_INDEXES=( 1 $(( tmp_list_size+3 )) $#list )
|
||
else
|
||
[ "$#list" -eq 0 ] && return 1
|
||
fi
|
||
|
||
n-list "${list[@]}"
|
||
|
||
if [ "$REPLY" -gt 0 ]; then
|
||
selected="$reply[$REPLY]"
|
||
selected="${selected/#\~/$HOME}"
|
||
echo "You have selected $selected"
|
||
(( NCD_DONT_PUSHD )) && setopt NO_AUTO_PUSHD
|
||
cd "$selected"
|
||
(( NCD_DONT_PUSHD )) && setopt AUTO_PUSHD
|
||
fi
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias ncd=n-cd
|
||
|
||
n-env() {
|
||
# 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 localoptions extendedglob
|
||
unsetopt equals
|
||
zmodload zsh/curses
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.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:
|
||
}
|
||
alias nenv=n-env
|
||
|
||
n-functions() {
|
||
# 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 localoptions extendedglob
|
||
zmodload zsh/curses
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
|
||
|
||
local list
|
||
local selected
|
||
|
||
NLIST_REMEMBER_STATE=0
|
||
|
||
# Read configuration
|
||
[ -f ~/.config/znt/n-functions.conf ] && . ~/.config/znt/n-functions.conf
|
||
|
||
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:
|
||
}
|
||
alias nfunctions=n-functions
|
||
|
||
n-history() {
|
||
# 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 localoptions extendedglob
|
||
zmodload zsh/curses
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.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]"
|
||
print -zr "$selected"
|
||
fi
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias nhistory=n-history
|
||
|
||
n-kill() {
|
||
# 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
|
||
|
||
zmodload zsh/curses
|
||
|
||
setopt localoptions
|
||
setopt extendedglob
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.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 "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'
|
||
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 )
|
||
n-list $'\x1b[00;31mSelect signal:\x1b[00;00m' "$signal_names[@]"
|
||
|
||
if [ "$REPLY" -gt 0 ]; then
|
||
selected="$reply[$REPLY]"
|
||
signal="${(k)signals[(r)$selected]}"
|
||
|
||
# Will change so that the command actually
|
||
# executes when function is more tested
|
||
print -zr "kill -$signal $pid"
|
||
fi
|
||
fi
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias nkill=n-kill
|
||
|
||
n-list() {
|
||
# $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 localoptions typesetsilent localtraps extendedglob noshortloops
|
||
|
||
zmodload zsh/curses
|
||
|
||
trap "return" TERM INT QUIT
|
||
trap "_nlist_exit" EXIT
|
||
|
||
# Drawing and input
|
||
autoload n-list-draw n-list-input
|
||
|
||
# Cleanup before any exit
|
||
_nlist_exit() {
|
||
[[ "$REPLY" = <-> ]] || REPLY="-1"
|
||
zcurses 2>/dev/null delwin inner
|
||
zcurses 2>/dev/null delwin main
|
||
zcurses 2>/dev/null refresh
|
||
zcurses end
|
||
}
|
||
|
||
# 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"
|
||
}
|
||
|
||
#
|
||
# Main code
|
||
#
|
||
|
||
# Check if there is proper input
|
||
if [ "$#" -lt 1 ]; then
|
||
echo "Usage: n-list element_1 ..."
|
||
return 1
|
||
fi
|
||
|
||
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-2
|
||
integer page_height=inner_height
|
||
integer page_width=inner_width
|
||
|
||
typeset -a list col_list
|
||
integer last_element=$#
|
||
local action
|
||
local final_key
|
||
integer selection
|
||
local prev_search_buffer=""
|
||
|
||
# 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_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
|
||
|
||
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 1
|
||
zcurses bg main white/black
|
||
zcurses bg inner white/black
|
||
|
||
#
|
||
# 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="$#"
|
||
|
||
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" ]; then
|
||
prev_search_buffer="$NLIST_SEARCH_BUFFER"
|
||
|
||
list=( "$@" )
|
||
last_element="$#"
|
||
|
||
# First remove non-selectable elements
|
||
[ "$#NLIST_NONSELECTABLE_ELEMENTS" -gt 0 ] && for i in "${(nO)NLIST_NONSELECTABLE_ELEMENTS[@]}"; do
|
||
list[$i]=()
|
||
done
|
||
|
||
# Next do the filtering
|
||
list=( "${(@M)list:#(#i)*$NLIST_SEARCH_BUFFER*}" )
|
||
last_element="$#list"
|
||
[ "$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 ))
|
||
|
||
local red=$'\x1b[00;31m' reset=$'\x1b[00;00m'
|
||
col_list=( "${(@)list//(#bi)($NLIST_SEARCH_BUFFER)/$red${match[1]}$reset}" )
|
||
fi
|
||
|
||
integer end_idx=$(( NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN + page_height - 1 ))
|
||
[ "$end_idx" -gt "$last_element" ] && end_idx=last_element
|
||
|
||
# Output colored list
|
||
n-list-draw "$(( (NLIST_CURRENT_IDX-1) % page_height + 1 ))" \
|
||
"$page_height" "$page_width" 0 1 "$NLIST_TEXT_OFFSET" inner ansi \
|
||
"${(@)col_list[NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN, end_idx]}"
|
||
else
|
||
# There is no search, but there was in previous loop
|
||
# Enter non-search mode with fresh list array
|
||
if [ -n "$prev_search_buffer" ]; then
|
||
prev_search_buffer=""
|
||
list=( "$@" )
|
||
last_element="$#"
|
||
fi
|
||
|
||
integer end_idx=$(( NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN + page_height - 1 ))
|
||
[ "$end_idx" -gt "$last_element" ] && end_idx=last_element
|
||
|
||
# Output the list
|
||
n-list-draw "$(( (NLIST_CURRENT_IDX-1) % page_height + 1 ))" \
|
||
"$page_height" "$page_width" 0 1 "$NLIST_TEXT_OFFSET" inner ansi \
|
||
"${(@)list[NLIST_FROM_WHAT_IDX_LIST_IS_SHOWN, end_idx]}"
|
||
fi
|
||
|
||
if [ "$NLIST_IS_SEARCH_MODE" = "1" ]; then
|
||
_nlist_status_msg "Filtering with: $NLIST_SEARCH_BUFFER"
|
||
elif [[ ${NLIST_NONSELECTABLE_ELEMENTS[(r)$NLIST_CURRENT_IDX]} != $NLIST_CURRENT_IDX ]]; then
|
||
local _txt=""
|
||
[ -n "$NLIST_GREP_STRING" ] && _txt=" [$NLIST_GREP_STRING]"
|
||
_nlist_status_msg "Current #$NLIST_USER_CURRENT_IDX (of #$NLIST_USER_LAST_ELEMENT entries)$_txt"
|
||
else
|
||
_nlist_status_msg ""
|
||
fi
|
||
|
||
zcurses border main
|
||
zcurses refresh main inner
|
||
|
||
# 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"
|
||
|
||
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_USER_CURRENT_IDX="$reply[8]"
|
||
NLIST_USER_LAST_ELEMENT="$reply[9]"
|
||
|
||
if [ "$action" = "SELECT" ]; then
|
||
REPLY="$selection"
|
||
reply=( "$list[@]" )
|
||
break
|
||
elif [ "$action" = "QUIT" ]; then
|
||
REPLY=-1
|
||
break
|
||
elif [ "$action" = "REDRAW" ]; then
|
||
zcurses clear main redraw
|
||
zcurses clear inner redraw
|
||
fi
|
||
done
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias nlist=n-list
|
||
|
||
n-list-draw() {
|
||
# Copy this file into /usr/share/zsh/site-functions/
|
||
# and add 'autoload n-list-draw` to .zshrc
|
||
|
||
emulate -L zsh
|
||
|
||
zmodload zsh/curses
|
||
|
||
setopt localoptions typesetsilent extendedglob
|
||
|
||
_nlist_expand_tabs() {
|
||
local chunk="$1"
|
||
integer before_len="$2"
|
||
REPLY=""
|
||
|
||
while [ -n "$chunk" ]; do
|
||
[[ "$chunk" = (#b)([^$'\t']#)$'\t'(*) ]] && {
|
||
(( all_text_len=((before_len+${#match[1]})/8+1)*8 ))
|
||
|
||
REPLY+="${(r:all_text_len-before_len:: :)match[1]}"
|
||
|
||
before_len+=all_text_len-before_len
|
||
chunk="$match[2]"
|
||
} || {
|
||
REPLY+="$chunk"
|
||
break
|
||
}
|
||
done
|
||
}
|
||
|
||
|
||
_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'\[(#B)([0-9][0-9]\;|)(#b)([0-9][0-9]|)m(*) ]]; then
|
||
# Text for further processing
|
||
text="$match[3]"
|
||
# Text chunk to output now
|
||
out="$match[1]"
|
||
# Save color
|
||
col="$match[2]"
|
||
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"
|
||
local ansi_mode="$8"
|
||
shift 8
|
||
integer max_text_len=page_width-x_offset
|
||
|
||
[ "$bold" = "0" ] && bold="" || bold="+bold"
|
||
[ "$ansi_mode" = "ansi" ] && zcurses attr "$win" $bold white/black
|
||
|
||
integer end_idx=1+page_height-1
|
||
[ "$end_idx" -gt "$#" ] && end_idx="$#"
|
||
integer y=y_offset
|
||
|
||
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" +reverse
|
||
if [ "$ansi_mode" != "ansi" ]; then
|
||
# TODO horizontal scroll
|
||
_nlist_expand_tabs "$@[i]"
|
||
text="$REPLY"
|
||
text_len="${#text}"
|
||
|
||
[ "$text_len" -gt "$max_text_len" ] && text="${text[1,$max_text_len]}"
|
||
zcurses string "$win" "$text"
|
||
else
|
||
_nlist_print_with_ansi "$win" "$@[i]" "$text_offset" "$max_text_len"
|
||
fi
|
||
[ "$i" = "$highlight" ] && zcurses attr "$win" -reverse
|
||
|
||
y+=1
|
||
done
|
||
|
||
zcurses attr "$win" white/black
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias nlist-draw=n-list-draw
|
||
|
||
n-list-input() {
|
||
# Copy this file into /usr/share/zsh/site-functions/
|
||
# and add 'autoload n-list-input` to .zshrc
|
||
|
||
emulate -L zsh
|
||
|
||
zmodload zsh/curses
|
||
|
||
setopt localoptions
|
||
setopt typesetsilent
|
||
|
||
# Compute first to show index
|
||
_nlist_compute_first_to_show_idx() {
|
||
from_what_idx_list_is_shown=0+((current_idx-1)/page_height)*page_height+1
|
||
}
|
||
|
||
_nlist_compute_user_vars_difference() {
|
||
if [[ "${(t)NLIST_NONSELECTABLE_ELEMENTS}" != "array" &&
|
||
"${(t)NLIST_NONSELECTABLE_ELEMENTS}" != "array-local" ||
|
||
-n "$buffer" ]]
|
||
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 "$current_idx" ] && current_difference+=1 || break
|
||
done
|
||
fi
|
||
}
|
||
|
||
integer current_difference
|
||
integer last_element_difference
|
||
typeset -ga reply
|
||
reply=( -1 '' 1 1 )
|
||
integer current_idx="$1"
|
||
integer from_what_idx_list_is_shown="$2"
|
||
integer page_height="$3"
|
||
integer page_width="$4"
|
||
integer last_element="$5"
|
||
integer hscroll="$6"
|
||
local key="$7"
|
||
integer search="$8"
|
||
local buffer="$9"
|
||
|
||
#
|
||
# Listening for input
|
||
#
|
||
|
||
if [ "$search" = "0" ]; then
|
||
|
||
case "$key" in
|
||
(UP|k|)
|
||
# Are there any elements before the current one?
|
||
[ "$current_idx" -gt 1 ] && current_idx=current_idx-1;
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
(DOWN|j|)
|
||
# Are there any elements after the current one?
|
||
[ "$current_idx" -lt "$last_element" ] && current_idx=current_idx+1;
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
(PPAGE)
|
||
current_idx=current_idx-page_height
|
||
[ "$current_idx" -lt 1 ] && current_idx=1;
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
(NPAGE|" ")
|
||
current_idx=current_idx+page_height
|
||
[ "$current_idx" -gt "$last_element" ] && current_idx=last_element;
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
()
|
||
current_idx=current_idx-page_height/2
|
||
[ "$current_idx" -lt 1 ] && current_idx=1;
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
()
|
||
current_idx=current_idx+page_height/2
|
||
[ "$current_idx" -gt "$last_element" ] && current_idx=last_element;
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
(HOME|g)
|
||
current_idx=1
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
(END|G)
|
||
current_idx=last_element
|
||
_nlist_compute_first_to_show_idx
|
||
;;
|
||
($'\n')
|
||
# Is that element selectable?
|
||
# Check for this only when there is no search
|
||
if [[ "$NLIST_SEARCH_BUFFER" != "" || ${NLIST_NONSELECTABLE_ELEMENTS[(r)$current_idx]} != $current_idx ]]; then
|
||
# Save current element in the result variable
|
||
reply=( $current_idx SELECT )
|
||
fi
|
||
;;
|
||
(q)
|
||
reply=( -1 QUIT )
|
||
;;
|
||
(/)
|
||
search=1
|
||
;;
|
||
($'\t')
|
||
reply=( $current_idx LEAVE )
|
||
;;
|
||
()
|
||
reply=( -1 REDRAW )
|
||
;;
|
||
(\])
|
||
[[ "${(t)NLIST_HOP_INDEXES}" = "array" || "${(t)NLIST_HOP_INDEXES}" = "array-local" ]] &&
|
||
[ -z "$NLIST_SEARCH_BUFFER" ] && for idx in "${(n)NLIST_HOP_INDEXES[@]}"; do
|
||
if [ "$idx" -gt "$current_idx" ]; then
|
||
current_idx=$idx
|
||
_nlist_compute_first_to_show_idx
|
||
break
|
||
fi
|
||
done
|
||
;;
|
||
(\[)
|
||
[[ "${(t)NLIST_HOP_INDEXES}" = "array" || "${(t)NLIST_HOP_INDEXES}" = "array-local" ]] &&
|
||
[ -z "$NLIST_SEARCH_BUFFER" ] && for idx in "${(nO)NLIST_HOP_INDEXES[@]}"; do
|
||
if [ "$idx" -lt "$current_idx" ]; then
|
||
current_idx=$idx
|
||
_nlist_compute_first_to_show_idx
|
||
break
|
||
fi
|
||
done
|
||
;;
|
||
('<'|'{')
|
||
hscroll=hscroll-7
|
||
[ "$hscroll" -lt 0 ] && hscroll=0
|
||
;;
|
||
('>'|'}')
|
||
hscroll+=7
|
||
;;
|
||
(*)
|
||
;;
|
||
esac
|
||
|
||
else
|
||
|
||
case "$key" in
|
||
($'\n')
|
||
search=0
|
||
;;
|
||
($'\b'||BACKSPACE)
|
||
buffer="${buffer%?}"
|
||
;;
|
||
()
|
||
[ "$buffer" = "${buffer% *}" ] && buffer="" || buffer="${buffer% *}"
|
||
;;
|
||
(*)
|
||
buffer+="$key"
|
||
;;
|
||
esac
|
||
|
||
reply=( -1 SEARCH )
|
||
|
||
fi
|
||
|
||
_nlist_compute_user_vars_difference
|
||
|
||
reply[3]="$current_idx"
|
||
reply[4]="$from_what_idx_list_is_shown"
|
||
reply[5]="$hscroll"
|
||
reply[6]="$search"
|
||
reply[7]="$buffer"
|
||
reply[8]=$(( current_idx - current_difference ))
|
||
reply[9]=$(( last_element - last_element_difference ))
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias nlist-input=n-list-input
|
||
|
||
n-options() {
|
||
# Copy this file into /usr/share/zsh/site-functions/
|
||
# and add 'autoload n-options` to .zshrc
|
||
#
|
||
# This function allows to browse and toggle shell's options
|
||
#
|
||
# Uses n-list
|
||
|
||
#emulate -L zsh
|
||
|
||
zmodload zsh/curses
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
|
||
|
||
# TODO restore options
|
||
unsetopt localoptions
|
||
setopt kshoptionprint
|
||
|
||
local list
|
||
local selected
|
||
local option
|
||
local state
|
||
|
||
# 0 - don't remember, 1 - remember, 2 - init once, then remember
|
||
NLIST_REMEMBER_STATE=2
|
||
|
||
local NLIST_GREP_STRING="${1:=}"
|
||
|
||
while (( 1 )); do
|
||
list=( `setopt` )
|
||
list=( "${(M)list[@]:#*${1:=}*}" )
|
||
|
||
if [ "$#list" -eq 0 ]; then
|
||
echo "No matching options"
|
||
break
|
||
fi
|
||
|
||
local red=$'\x1b[00;31m' green=$'\x1b[00;32m' reset=$'\x1b[00;00m'
|
||
list=( "${list[@]/ off/${red} off$reset}" )
|
||
#list=( "${list[@]/ on/${green} on$reset}" )
|
||
list=( "${(i)list[@]}" )
|
||
|
||
n-list "${list[@]}"
|
||
|
||
if [ "$REPLY" -gt 0 ]; then
|
||
[[ -o ksharrays ]] && selected="${reply[$(( REPLY - 1 ))]}" || selected="${reply[$REPLY]}"
|
||
option="${selected%% *}"
|
||
state="${selected##* }"
|
||
|
||
if [[ -o globsubst ]]; then
|
||
unsetopt globsubst
|
||
state="${state%$reset}"
|
||
setopt globsubst
|
||
else
|
||
state="${state%$reset}"
|
||
fi
|
||
|
||
# Toggle the option
|
||
if [ "$state" = "on" ]; then
|
||
echo "Setting |$option| to off"
|
||
unsetopt "$option"
|
||
else
|
||
echo "Setting |$option| to on"
|
||
setopt "$option"
|
||
fi
|
||
else
|
||
break
|
||
fi
|
||
done
|
||
|
||
NLIST_REMEMBER_STATE=0
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias noptions=n-options
|
||
|
||
n-panelize() {
|
||
# Copy this file into /usr/share/zsh/site-functions/
|
||
# and add 'autoload n-panelize` to .zshrc
|
||
#
|
||
# This function somewhat reminds the panelize feature from Midnight Commander
|
||
# It allows browsing output of arbitrary command. Example usage:
|
||
# v-panelize ls /usr/local/bin
|
||
#
|
||
# Uses n-list
|
||
|
||
emulate -L zsh
|
||
|
||
zmodload zsh/curses
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
|
||
|
||
local list
|
||
local selected
|
||
|
||
NLIST_REMEMBER_STATE=0
|
||
|
||
# Check if there is proper input
|
||
if [ "$#" -lt 1 ]; then
|
||
echo "Usage: n-panelize command ..."
|
||
return 1
|
||
fi
|
||
|
||
list=( `"$@"` )
|
||
[ "$?" -ne 0 ] && return $?
|
||
|
||
n-list "${list[@]}"
|
||
|
||
if [ "$REPLY" -gt 0 ]; then
|
||
selected="$reply[$REPLY]"
|
||
echo "You have selected $selected"
|
||
fi
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias npanelize=n-panelize
|
||
|
||
n-preview() {
|
||
# Copy this file into /usr/share/zsh/site-functions/
|
||
# and add 'autoload n-preview` to .zshrc
|
||
#
|
||
# This is partially a test if n-list-draw and n-list-input can be
|
||
# used multiple times to create multiple lists. It might become
|
||
# more usable if someone adds more features like previewing of
|
||
# archive contents.
|
||
|
||
emulate -L zsh
|
||
|
||
zmodload zsh/curses
|
||
zmodload zsh/zprof
|
||
|
||
setopt localoptions typesetsilent localtraps extendedglob
|
||
trap "return" TERM INT QUIT
|
||
trap "_vpreview_exit" EXIT
|
||
|
||
local IFS="
|
||
"
|
||
|
||
[ -f ~/.config/znt/n-list.conf ] && . ~/.config/znt/n-list.conf
|
||
|
||
# Drawing and input
|
||
autoload n-list-draw n-list-input
|
||
|
||
# Cleanup before any exit
|
||
_vpreview_exit() {
|
||
zcurses 2>/dev/null delwin files
|
||
zcurses 2>/dev/null delwin body
|
||
zcurses 2>/dev/null delwin status
|
||
zcurses 2>/dev/null refresh
|
||
zcurses end
|
||
|
||
zprof
|
||
}
|
||
|
||
# Outputs a message in the bottom of the screen
|
||
_vpreview_status_msg() {
|
||
zcurses move status 1 2
|
||
zcurses clear status eol
|
||
zcurses string status "$1"
|
||
}
|
||
|
||
#
|
||
# Main code
|
||
#
|
||
|
||
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 status_height=3
|
||
integer status_width=term_width
|
||
integer status_page_height=1
|
||
integer status_page_width=term_width-2
|
||
|
||
integer files_height=term_height-status_height
|
||
integer files_width=term_width/5
|
||
integer files_page_height=files_height-2
|
||
integer files_page_width=files_width-2
|
||
|
||
integer body_height=term_height-status_height
|
||
integer body_width=term_width-files_width
|
||
integer body_page_height=body_height-2
|
||
integer body_page_width=body_width
|
||
|
||
integer _from_what_idx_list_is_shown_1=1
|
||
integer current_1=1
|
||
|
||
integer _from_what_idx_list_is_shown_2=1
|
||
integer current_2=1
|
||
integer hscroll_2=0
|
||
|
||
integer active_window=0
|
||
|
||
local ansi_mode="ansi"
|
||
[ -f ~/.config/znt/n-preview.conf ] && . ~/.config/znt/n-preview.conf
|
||
typeset -a hcmd
|
||
#if type pygmentize 2>/dev/null 1>&2; then
|
||
# hcmd=( pygmentize -g )
|
||
if type highlight 2>/dev/null 1>&2; then
|
||
hcmd=( highlight -q --force -O ansi )
|
||
elif type source-highlight 2>/dev/null 1>&2; then
|
||
# Warning: source-highlight can have problems
|
||
hcmd=( source-highlight --failsafe -fesc -o STDOUT -i )
|
||
else
|
||
ansi_mode="noansi"
|
||
fi
|
||
|
||
zcurses init
|
||
zcurses addwin status "$status_height" "$status_width" $(( term_height - status_height )) 0
|
||
zcurses addwin files "$files_height" "$files_width" 0 0
|
||
zcurses addwin body "$body_height" "$body_width" 0 "$files_width"
|
||
zcurses bg status white/black
|
||
zcurses bg files white/black
|
||
zcurses bg body white/black
|
||
|
||
#
|
||
# Listening for input
|
||
#
|
||
|
||
local key keypad
|
||
|
||
# Clear input buffer
|
||
zcurses timeout status 0
|
||
zcurses input status key keypad
|
||
zcurses timeout status -1
|
||
key=""
|
||
keypad=""
|
||
|
||
typeset -a filenames
|
||
integer last_element_1
|
||
|
||
typeset -a body
|
||
integer last_element_2
|
||
|
||
filenames=( *(N) )
|
||
filenames=( "${(@M)filenames:#(#i)*$1*}" )
|
||
|
||
local NLIST_GREP_STRING="$1"
|
||
|
||
integer last_element_1="$#filenames"
|
||
integer last_element_2=0
|
||
|
||
local selection action final_key
|
||
|
||
while (( 1 )); do
|
||
# Output the lists
|
||
integer end_idx=$(( _from_what_idx_list_is_shown_1 + files_page_height - 1 ))
|
||
[ "$end_idx" -gt "$last_element_1" ] && end_idx=last_element_1
|
||
|
||
n-list-draw "$(( (current_1 -1) % files_page_height + 1 ))" \
|
||
"$files_page_height" "$files_page_width" 1 2 0 files noansi \
|
||
"${(@)filenames[_from_what_idx_list_is_shown_1, end_idx]}"
|
||
|
||
if [ "$#body" -ge 1 ]; then
|
||
end_idx=$(( _from_what_idx_list_is_shown_2 + body_page_height - 1 ))
|
||
[ "$end_idx" -gt "$last_element_2" ] && end_idx=last_element_2
|
||
|
||
n-list-draw "$(( (current_2 -1) % body_page_height + 1 ))" \
|
||
"$body_page_height" "$body_page_width" 1 0 "$hscroll_2" body "$ansi_mode" \
|
||
"${(@)body[_from_what_idx_list_is_shown_2, end_idx]}"
|
||
fi
|
||
|
||
[[ "$active_window" -eq 0 ]] && zcurses border files
|
||
zcurses border status
|
||
zcurses refresh files body status
|
||
|
||
# Wait for input
|
||
zcurses input status 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
|
||
_vpreview_status_msg "Inproper input detected"
|
||
zcurses refresh status
|
||
fi
|
||
|
||
if [ "$active_window" -eq 0 ]; then
|
||
zcurses clear files
|
||
n-list-input "$current_1" "$_from_what_idx_list_is_shown_1" "$files_page_height" \
|
||
"$files_page_width" "$last_element_1" 0 "$final_key"
|
||
|
||
selection="$reply[1]"
|
||
action="$reply[2]"
|
||
current_1="$reply[3]"
|
||
_from_what_idx_list_is_shown_1="$reply[4]"
|
||
|
||
if [ "$action" = "SELECT" ]; then
|
||
# Load new file and refresh the displaying window
|
||
local filename="$filenames[$selection]"
|
||
if [ "$ansi_mode" = "ansi" ]; then
|
||
body=( "${(@f)"$( "$hcmd[@]" "$filename" )"}" )
|
||
else
|
||
body=( "${(@f)"$(<$filename)"}" )
|
||
fi
|
||
last_element_2="$#body"
|
||
current_2=1
|
||
_from_what_idx_list_is_shown_2=1
|
||
zcurses clear body
|
||
fi
|
||
elif [ "$active_window" -eq 1 ]; then
|
||
zcurses clear body
|
||
n-list-input "$current_2" "$_from_what_idx_list_is_shown_2" "$body_page_height" \
|
||
"$body_page_width" "$last_element_2" "$hscroll_2" "$final_key"
|
||
|
||
selection="$reply[1]"
|
||
action="$reply[2]"
|
||
current_2="$reply[3]"
|
||
_from_what_idx_list_is_shown_2="$reply[4]"
|
||
hscroll_2="$reply[5]"
|
||
|
||
fi
|
||
|
||
if [ "$action" = "LEAVE" ]; then
|
||
active_window=1-active_window
|
||
elif [ "$action" = "QUIT" ]; then
|
||
break
|
||
elif [ "$action" = "REDRAW" ]; then
|
||
zcurses clear files redraw
|
||
zcurses clear body redraw
|
||
zcurses clear status redraw
|
||
fi
|
||
done
|
||
|
||
# vim: set filetype=zsh:
|
||
}
|
||
alias npreview=n-preview
|
||
|