history-search-multi-word/history-search-multi-word
Sebastian Gniazdowski 2bef2b9343 *highlight: Optimization – save options outside main highlighting fun
Lower 18xx are being seen, like below:

Running time: 1.8632000000
num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)  350        1855,72     5,30  100,00%   1376,89     3,93   74,19%  -hsmw-highlight-process
 2) 2800         342,38     0,12   18,45%    342,38     0,12   18,45%  -hsmw-highlight-string
 3) 2450          80,16     0,03    4,32%     80,16     0,03    4,32%  -hsmw-highlight-check-path
 4) 1400          38,99     0,03    2,10%     38,99     0,03    2,10%  -hsmw-highlight-main-type
 5)  350           9,83     0,03    0,53%      9,83     0,03    0,53%  -hsmw-highlight-stack-pop
 6)  350           7,47     0,02    0,40%      7,47     0,02    0,40%  -hsmw-highlight-path-separators
 7)    1           0,07     0,07    0,00%      0,07     0,07    0,00%  -hsmw-highlight-fill-option-variables
 8)    1           0,01     0,01    0,00%      0,01     0,01    0,00%  -hsmw-highlight-init
2016-10-25 16:17:39 +02:00

324 lines
12 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# To use (when not using as plugin) copy to site-functions and issue
# (add to ~/.zshrc):
#
# autoload history-search-multi-word
# zle -N history-search-multi-word
# zle -N history-search-multi-word-backwards history-search-multi-word
# zle -N history-search-multi-word-pbackwards history-search-multi-word
# zle -N history-search-multi-word-pforwards history-search-multi-word
# bindkey "^R" history-search-multi-word
#
# This will bind to Ctrl-R
#
# Zstyles:
# zstyle ":history-search-multi-word" page-size "8"
# zstyle ":history-search-multi-word" highlight-color "fg=yellow,bold"
# zstyle ":plugin:history-search-multi-word" synhl "yes"
[[ "$__HSMW_MH_SOURCED" != "1" ]] && source "$HSMW_REPO_DIR/hsmw-highlight"
local right_brace_is_recognised_everywhere
integer path_dirs_was_set multi_func_def ointeractive_comments
-hsmw-highlight-fill-option-variables
emulate -LR zsh
setopt typesetsilent extendedglob noshortloops localtraps
# When an error, then no cursor keys bindings
zmodload zsh/terminfo 2>/dev/null
zmodload zsh/termcap 2>/dev/null
autoload is-at-least
typeset -g __hsmw_hcw_index
typeset -g __hsmw_hcw_widget_name __hsmw_hcw_restart __hsmw_hcw_call_count
typeset -g __hsmw_page_size __hsmw_hl_color __hsmw_synhl __hsmw_active
typeset -ga __hsmw_disp_list
typeset -gi __hsmw_page_start_idx
typeset -gaU __hsmw_hcw_found
(( __hsmw_hcw_call_count ++ ))
trap '(( __hsmw_hcw_call_count -- )); return 0;' INT
_hsmw_main() {
# First call or restart?
if [[ "$__hsmw_hcw_call_count" -le 1 || "$__hsmw_hcw_restart" = "1" ]]; then
if [[ "$__hsmw_hcw_call_count" -le 1 ]]; then
# Read configuration data
zstyle -s ':history-search-multi-word' page-size __hsmw_page_size || __hsmw_page_size=$(( LINES / 3 ))
zstyle -s ':history-search-multi-word' highlight-color __hsmw_hl_color || __hsmw_hl_color="fg=yellow,bold"
zstyle -s ":plugin:history-search-multi-word" synhl __hsmw_synhl || __hsmw_synhl="yes"
zstyle -s ":plugin:history-search-multi-word" active __hsmw_active || __hsmw_active="underline"
[[ "$__hsmw_synhl" != "1" && "$__hsmw_synhl" != "yes" && "$__hsmw_synhl" != "true" ]] && __hsmw_synhl="no" || __hsmw_synhl="yes"
-hsmw-highlight-init
fi
# '0' will get changed into $to_display limit
[[ "$WIDGET" = *-word || "$WIDGET" = *-pforwards ]] && __hsmw_hcw_index="1"
[[ "$WIDGET" = *-backwards || "$WIDGET" = *-pbackwards ]] && __hsmw_hcw_index="0"
__hsmw_hcw_widget_name="${${${WIDGET%-backwards}-pbackwards}-pforwards}"
__hsmw_hcw_found=( )
__hsmw_hcw_finished="0"
__hsmw_hcw_restart="0"
__hsmw_page_start_idx=0
else
# Consecutive call
[[ "$WIDGET" = *-word ]] && (( __hsmw_hcw_index ++ ))
[[ "$WIDGET" = *-backwards ]] && (( __hsmw_hcw_index -- ))
[[ "$WIDGET" = *-pforwards ]] && (( __hsmw_hcw_index = __hsmw_hcw_index + __hsmw_page_size ))
[[ "$WIDGET" = *-pbackwards ]] && (( __hsmw_hcw_index = __hsmw_hcw_index - __hsmw_page_size ))
fi
# Find history entries matching pattern *word1*~^*word2*~^*word3* etc.
local search_buffer="${BUFFER%% ##}" search_pattern="" colsearch_pattern=""
search_buffer="${search_buffer## ##}"
search_buffer="${search_buffer//(#m)[][*?|#~^()><\\]/\\$MATCH}"
# Pattern will be *foo*~^*bar* (inventor: Mikael Magnusson)
# It's: foo and not what doesn't contain bar, etc.
search_pattern="${search_buffer// ##/*~^*}"
colsearch_pattern="${search_buffer// ##/|}"
if [[ "${#__hsmw_hcw_found[@]}" -eq "0" ]]; then
# The repeat will make the matching work on a fresh heap arena
repeat 1; do
# Tip: these are equal:
#__hsmw_hcw_found=( "${(@M)history:#(#i)*$~search_pattern*}" )
__hsmw_hcw_found=( "${(@)history[(R)(#i)*$~search_pattern*]}" )
done
fi
integer max_index="${#__hsmw_hcw_found[@]}"
if [[ "$max_index" -le "0" ]]; then
POSTDISPLAY=$'\n'"No matches found"
return 0
fi
#
# Pagination, index value guards
#
integer page_size="$__hsmw_page_size"
[[ "$page_size" -gt "$max_index" ]] && page_size="$max_index"
[[ "$__hsmw_hcw_index" -le 0 ]] && __hsmw_hcw_index="$max_index"
[[ "$__hsmw_hcw_index" -gt "$max_index" ]] && __hsmw_hcw_index=1
integer page_start_idx=$(( ((__hsmw_hcw_index-1)/page_size)*page_size+1 ))
integer on_page_idx=$(( (__hsmw_hcw_index-1) % page_size + 1 ))
#
# Prepare display
#
(( page_start_idx != __hsmw_page_start_idx )) && {
__hsmw_disp_list=( "${(@)__hsmw_hcw_found[page_start_idx,page_start_idx+page_size-1]}" )
# All entries should have multilines replaced
__hsmw_disp_list=( "${(@)__hsmw_disp_list//$'\n'/\\n}" )
# ... and truncated to display width, and
# also preceeded by two spaces
__hsmw_disp_list=( "${(@)__hsmw_disp_list/(#m)*/ ${MATCH[1,COLUMNS-8]}}" )
__hsmw_page_start_idx=page_start_idx
}
#
# Detect where "> .." entry starts, add the ">" mark
#
local txt_before="${(F)${(@)__hsmw_disp_list[1,on_page_idx-1]}}"
local entry="${__hsmw_disp_list[on_page_idx]}"
local text="${(F)__hsmw_disp_list}"
integer replace_idx=${#txt_before}+2
(( replace_idx == 2 )) && replace_idx=1
text[replace_idx]=">"
#
# Colorify
#
local preamble=$'\n'"Searching for: $BUFFER"$'\n'"Element #$__hsmw_hcw_index of $max_index"$'\n'
integer offset=${#preamble}+${#BUFFER}
POSTDISPLAY="$preamble$text"
region_highlight=( )
if [[ "$__hsmw_synhl" = "yes" ]]; then
integer pre_index=0
local line
for line in "${__hsmw_disp_list[@]}"; do
reply=( )
-hsmw-highlight-process "$line"
region_highlight+=( "${reply[@]//(#b)([[:digit:]]##) ([[:digit:]]##)/$(( ${match[1]} + pre_index + offset )) $(( ${match[2]} + pre_index + offset ))}" )
pre_index+=${#line}+1
done
fi
if [ -n "$colsearch_pattern" ]; then
local nl=$'\n'
# Following line is taken from Zaw (GH zsh-users/zaw)  license is named "Zaw", it is in LICENSE file
region_highlight+=( "${(f)${(S)text//*(#bi)(${~colsearch_pattern})/$(( offset + mbegin[1] - 1 )) $(( offset + mend[1] )) ${__hsmw_hl_color}${nl}}%$nl*}" )
fi
region_highlight+=( "$(( offset + ${#txt_before} )) $(( offset + ${#txt_before} + ${#entry} + 1 )) $__hsmw_active" )
}
_hsmw_main
_hsmw_simulate_widget() {
(( __hsmw_hcw_call_count ++ ))
_hsmw_main
}
_hsmw_self_insert() {
LBUFFER+="${KEYS[-1]}"
__hsmw_hcw_restart="1"
_hsmw_simulate_widget
}
_hsmw_backward_delete_char() {
LBUFFER="${LBUFFER%?}"
__hsmw_hcw_restart="1"
_hsmw_simulate_widget
}
_hsmw_delete_char() {
RBUFFER="${RBUFFER#?}"
__hsmw_hcw_restart="1"
_hsmw_simulate_widget
}
_hsmw_cancel_accept() {
BUFFER=""
__hsmw_hcw_index=-1
zle .accept-line
}
if [ "$__hsmw_hcw_call_count" -eq "1" ]; then
# Make the hsmw keymap a copy of the current main
bindkey -N hsmw emacs
local down_widget="${${${WIDGET%-backwards}%-pbackwards}-pforwards}"
local up_widget="${down_widget}-backwards"
local pdown_widget="${down_widget}-pforwards"
local pup_widget="${down_widget}-pbackwards"
# Manual, termcap, terminfo
bindkey -M hsmw '^[OA' "$up_widget"
bindkey -M hsmw '^[OB' "$down_widget"
bindkey -M hsmw '^[[A' "$up_widget"
bindkey -M hsmw '^[[B' "$down_widget"
[ -n "$termcap[ku]" ] && bindkey -M hsmw "$termcap[ku]" "$up_widget"
[ -n "$termcap[kd]" ] && bindkey -M hsmw "$termcap[kd]" "$down_widget"
[ -n "$termcap[kD]" ] && bindkey -M hsmw "$termcap[kD]" .delete-char
[ -n "$terminfo[kcuu1]" ] && bindkey -M hsmw "$terminfo[kcuu1]" "$up_widget"
[ -n "$terminfo[kcud1]" ] && bindkey -M hsmw "$terminfo[kcud1]" "$down_widget"
[ -n "$terminfo[kdch1]" ] && bindkey -M hsmw "$terminfo[kdch1]" .delete-char
# More bindkeys, to remove influence of plugins that overload things (z-sy-h, z-au-s)
bindkey -M hsmw '^[[D' .backward-char
bindkey -M hsmw '^[[C' .forward-char
[ -n "$termcap[kl]" ] && bindkey -M hsmw "$termcap[kl]" .backward-char
[ -n "$termcap[kr]" ] && bindkey -M hsmw "$termcap[kr]" .forward-char
[ -n "$terminfo[kcub1]" ] && bindkey -M hsmw "$terminfo[kcub1]" .backward-char
[ -n "$terminfo[kcuf1]" ] && bindkey -M hsmw "$terminfo[kcuf1]" .forward-char
# Now Home/End keys, first few recorded in my .zshrc during the years sequences
bindkey -M hsmw "\e[1~" .beginning-of-line
bindkey -M hsmw "\e[7~" .beginning-of-line
bindkey -M hsmw "\e[H" .beginning-of-line
bindkey -M hsmw "\e[4~" .end-of-line
bindkey -M hsmw "\e[F" .end-of-line
bindkey -M hsmw "\e[8~" .end-of-line
[ -n "$termcap[kh]" ] && bindkey -M hsmw "$termcap[kh]" .beginning-of-line
[ -n "$termcap[@7]" ] && bindkey -M hsmw "$termcap[@7]" .end-of-line
[ -n "$terminfo[khome]" ] && bindkey -M hsmw "$terminfo[khome]" .beginning-of-line
[ -n "$terminfo[kend]" ] && bindkey -M hsmw "$terminfo[kend]" .end-of-line
# The same for Ctrl-E, Ctrl-F
bindkey -M hsmw '^A' .beginning-of-line
bindkey -M hsmw '^E' .end-of-line
# Additional keys
bindkey -M hsmw '^[b' .backward-word
bindkey -M hsmw '^[B' .backward-word
bindkey -M hsmw '^[f' .forward-word
bindkey -M hsmw '^[F' .forward-word
bindkey -M hsmw '^[w' .forward-word
bindkey -M hsmw '^[W' .forward-word
# Additional keys
bindkey -M hsmw '^P' "$up_widget"
bindkey -M hsmw '^N' "$down_widget"
# Page Up, Page Down keys
[ -n "$termcap[kP]" ] && bindkey -M hsmw "$termcap[kP]" "$pup_widget"
[ -n "$termcap[kN]" ] && bindkey -M hsmw "$termcap[kN]" "$pdown_widget"
[ -n "$terminfo[kpp]" ] && bindkey -M hsmw "$terminfo[kpp]" "$pup_widget"
[ -n "$terminfo[knp]" ] && bindkey -M hsmw "$terminfo[knp]" "$pdown_widget"
# Needed for Fedora 23, zsh-5.1.1
bindkey -M hsmw ' ' self-insert
# Removal of default Ctrl-R binding
bindkey -M hsmw '^R' "$down_widget"
# Substitute self-insert, backward-delete-char, delete-char
zle -A self-insert saved-self-insert
zle -A backward-delete-char saved-backward-delete-char
zle -A delete-char saved-delete-char
zle -N self-insert _hsmw_self_insert
zle -N backward-delete-char _hsmw_backward_delete_char
zle -N delete-char _hsmw_delete_char
# Override ourselves with what we actually are
# because zsh-autosuggestions change us
zle -A "$down_widget" saved-"$down_widget"
zle -A "$up_widget" saved-"$up_widget"
zle -N "$down_widget" _hsmw_simulate_widget
zle -N "$up_widget" _hsmw_simulate_widget
zle -A "$pdown_widget" saved-"$pdown_widget"
zle -A "$pup_widget" saved-"$pup_widget"
zle -N "$pdown_widget" _hsmw_simulate_widget
zle -N "$pup_widget" _hsmw_simulate_widget
# Add Ctrl-V binding to cancel search
# A workaround for Zsh versions like 5.0.2
zle -N _hsmw_cancel_accept
bindkey -M hsmw "^V" _hsmw_cancel_accept
bindkey -M hsmw "^[" _hsmw_cancel_accept
# Trap INT to manually interrupt Zle to work around a bug
trap 'zle && zle .send-break' INT
if zle .recursive-edit -K hsmw; then
if [[ "$__hsmw_hcw_index" -gt "0" ]]; then
BUFFER="${__hsmw_hcw_found[__hsmw_hcw_index]}"
CURSOR="${#BUFFER}"
else
BUFFER=""
fi
else
BUFFER=""
fi
POSTDISPLAY=""
# Restore self-insert, backward-delete-char, delete-char
zle -A saved-self-insert self-insert
zle -A saved-backward-delete-char backward-delete-char
zle -A saved-delete-char delete-char
zle -D saved-self-insert saved-backward-delete-char saved-delete-char
# Restore ourselves
zle -A saved-"$down_widget" "$down_widget"
zle -A saved-"$up_widget" "$up_widget"
zle -D saved-"$down_widget" saved-"$up_widget"
zle -A saved-"$pdown_widget" "$pdown_widget"
zle -A saved-"$pup_widget" "$pup_widget"
zle -D saved-"$pdown_widget" saved-"$pup_widget"
# Full reinitialisation at next call
__hsmw_hcw_call_count="0"
# Free memory
#__hsmw_hcw_found=( )
elif (( __hsmw_hcw_call_count > 0 )); then
(( __hsmw_hcw_call_count -- ))
fi
# vim:ft=zsh