|
| 1 | +# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- |
| 2 | +# vim: ft=zsh sw=2 ts=2 et |
| 3 | + |
| 4 | +builtin emulate -L zsh ${=${options[xtrace]:#off}:+-o xtrace} |
| 5 | +builtin setopt extended_glob warn_create_global typeset_silent no_short_loops rc_quotes no_auto_pushd |
| 6 | + |
| 7 | +# When an error, then no cursor keys bindings |
| 8 | +zmodload zsh/terminfo 2>/dev/null |
| 9 | +zmodload zsh/termcap 2>/dev/null |
| 10 | + |
| 11 | +# Prepare output variables for zew-process-buffer |
| 12 | +local ZEW_PB_WORDS ZEW_PB_WORDS_BEGINNINGS ZEW_PB_SPACES |
| 13 | +local ZEW_PB_SELECTED_WORD ZEW_PB_LEFT ZEW_PB_RIGHT |
| 14 | + |
| 15 | +local MATCH; integer MBEGIN MEND |
| 16 | +local -a match mbegin mend |
| 17 | + |
| 18 | +typeset -g __zew_hcw_index __zew_hcw_left __zew_hcw_right __zew_hcw_call_count |
| 19 | +typeset -g __zew_hcw_widget_name __zew_hcw_restart __zew_hcw_finished |
| 20 | +typeset -gaU __zew_hcw_found |
| 21 | + |
| 22 | +(( __zew_hcw_call_count ++ )) |
| 23 | + |
| 24 | +_zhcw_main() { |
| 25 | + |
| 26 | +autoload zew-process-buffer |
| 27 | +zew-process-buffer "$BUFFER" "$CURSOR" |
| 28 | + |
| 29 | +# First call or restart? |
| 30 | +if [[ "$__zew_hcw_call_count" -le 1 || "$__zew_hcw_restart" = "1" ]]; then |
| 31 | + # '0' will get changed into $to_display limit |
| 32 | + [[ "$WIDGET" != *-backwards ]] && __zew_hcw_index="1" || __zew_hcw_index="0" |
| 33 | + __zew_hcw_widget_name="${WIDGET%-backwards}" |
| 34 | + __zew_hcw_left="$ZEW_PB_LEFT" |
| 35 | + __zew_hcw_right="$ZEW_PB_RIGHT" |
| 36 | + __zew_hcw_found=( ) |
| 37 | + __zew_hcw_finished="0" |
| 38 | + __zew_hcw_restart="0" |
| 39 | +else |
| 40 | + # Consecutive call |
| 41 | + [[ "$WIDGET" != *-backwards ]] && (( __zew_hcw_index ++ )) || (( __zew_hcw_index -- )) |
| 42 | +fi |
| 43 | + |
| 44 | +# Find history words matching $left ... $right |
| 45 | +if [ "$#__zew_hcw_found" -eq "0" ]; then |
| 46 | + repeat 1; do |
| 47 | + __zew_hcw_found=( "${(@M)historywords:#(#i)$__zew_hcw_left*$__zew_hcw_right}" ) |
| 48 | + done |
| 49 | + # The first result should be always $__zew_hcw_left$__zew_hcw_right |
| 50 | + if [ "$__zew_hcw_found[1]" != "$__zew_hcw_left$__zew_hcw_right" ]; then |
| 51 | + __zew_hcw_found=( "$__zew_hcw_left$__zew_hcw_right" "$__zew_hcw_found[@]" ) |
| 52 | + fi |
| 53 | +fi |
| 54 | + |
| 55 | +if [ "$#__zew_hcw_found" -le "0" ]; then |
| 56 | + zle -M "No matches found" |
| 57 | + return 0 |
| 58 | +fi |
| 59 | + |
| 60 | +# Pagination, index value guards |
| 61 | +integer page_size=$(( LINES / 2 )) |
| 62 | +integer max_index="$#__zew_hcw_found" |
| 63 | +[ "$page_size" -gt "$max_index" ] && page_size="$max_index" |
| 64 | +[ "$__zew_hcw_index" -le 0 ] && __zew_hcw_index="$max_index" |
| 65 | +[ "$__zew_hcw_index" -gt "$max_index" ] && __zew_hcw_index=1 |
| 66 | +integer page_start_idx=$(( ((__zew_hcw_index-1)/page_size)*page_size+1 )) |
| 67 | +integer on_page_idx=$(( (__zew_hcw_index-1) % page_size + 1 )) |
| 68 | + |
| 69 | +# Display matches |
| 70 | +typeset -a disp_list |
| 71 | +disp_list=( "${(@)__zew_hcw_found[page_start_idx,page_start_idx+page_size-1]}" ) |
| 72 | + |
| 73 | +# Add two spaces before every element |
| 74 | +disp_list=( "${(@)disp_list/(#m)*/ ${MATCH}}" ) |
| 75 | + |
| 76 | +# Add > before active element |
| 77 | +local entry="${disp_list[on_page_idx]}" |
| 78 | +entry[1]='>' |
| 79 | +disp_list[on_page_idx]="$entry" |
| 80 | + |
| 81 | +zle -M -- \ |
| 82 | +"Searching for '${__zew_hcw_left}_${__zew_hcw_right}'. "\ |
| 83 | +"Element #$__zew_hcw_index of $max_index"$'\n'"${(F)disp_list}" |
| 84 | + |
| 85 | +# Regenerate command line |
| 86 | +local buf="" |
| 87 | +integer nwords="${#ZEW_PB_WORDS}" |
| 88 | +for (( i=1; i<=nwords; i++ )); do |
| 89 | + if [ "$i" = "$ZEW_PB_SELECTED_WORD" ]; then |
| 90 | + buf+="${ZEW_PB_SPACES[i]}${__zew_hcw_found[__zew_hcw_index]}" |
| 91 | + else |
| 92 | + buf+="${ZEW_PB_SPACES[i]}${ZEW_PB_WORDS[i]}" |
| 93 | + fi |
| 94 | +done |
| 95 | + |
| 96 | +if [[ "$nwords" = "0" && "$ZEW_PB_SELECTED_WORD" = "0" ]]; then |
| 97 | + buf+="${__zew_hcw_found[__zew_hcw_index]}" |
| 98 | +fi |
| 99 | + |
| 100 | +# Add trailing spaces |
| 101 | +buf+="$ZEW_PB_SPACES[i]" |
| 102 | + |
| 103 | +# Set command line |
| 104 | +BUFFER="$buf" |
| 105 | + |
| 106 | +} |
| 107 | + |
| 108 | +_zhcw_self_insert() { |
| 109 | + LBUFFER+="${KEYS[-1]}" |
| 110 | + __zew_hcw_restart="1" |
| 111 | + _zhcw_main |
| 112 | +} |
| 113 | + |
| 114 | +_zhcw_backward_delete_char() { |
| 115 | + LBUFFER="${LBUFFER%?}" |
| 116 | + __zew_hcw_restart="1" |
| 117 | + _zhcw_main |
| 118 | +} |
| 119 | + |
| 120 | +_zhcw_delete_char() { |
| 121 | + RBUFFER="${RBUFFER#?}" |
| 122 | + __zew_hcw_restart="1" |
| 123 | + _zhcw_main |
| 124 | +} |
| 125 | + |
| 126 | +_zhcw_main |
| 127 | + |
| 128 | +if [ "$__zew_hcw_call_count" -eq "1" ]; then |
| 129 | + # Make the zhcw keymap a copy of the current main |
| 130 | + bindkey -N zhcw emacs |
| 131 | + local down_widget="${WIDGET%-backwards}" |
| 132 | + local up_widget="${down_widget}-backwards" |
| 133 | + # Manual, termcap, terminfo |
| 134 | + bindkey -M zhcw '^[OA' "$up_widget" |
| 135 | + bindkey -M zhcw '^[OB' "$down_widget" |
| 136 | + bindkey -M zhcw '^[[A' "$up_widget" |
| 137 | + bindkey -M zhcw '^[[B' "$down_widget" |
| 138 | + [ -n "$termcap[ku]" ] && bindkey -M zhcw "$termcap[ku]" "$up_widget" |
| 139 | + [ -n "$termcap[kd]" ] && bindkey -M zhcw "$termcap[kd]" "$down_widget" |
| 140 | + [ -n "$termcap[kD]" ] && bindkey -M zhcw "$termcap[kD]" delete-char |
| 141 | + [ -n "$terminfo[kcuu1]" ] && bindkey -M zhcw "$terminfo[kcuu1]" "$up_widget" |
| 142 | + [ -n "$terminfo[kcud1]" ] && bindkey -M zhcw "$terminfo[kcud1]" "$down_widget" |
| 143 | + [ -n "$terminfo[kdch1]" ] && bindkey -M zhcw "$terminfo[kdch1]" delete-char |
| 144 | + # Needed for Fedora 23, zsh-5.1.1 |
| 145 | + bindkey -M zhcw ' ' self-insert |
| 146 | + # Substitute self-insert, backward-delete-char, delete-char |
| 147 | + zle -A self-insert saved-self-insert |
| 148 | + zle -A backward-delete-char saved-backward-delete-char |
| 149 | + zle -A delete-char saved-delete-char |
| 150 | + zle -N self-insert _zhcw_self_insert |
| 151 | + zle -N backward-delete-char _zhcw_backward_delete_char |
| 152 | + zle -N delete-char _zhcw_delete_char |
| 153 | + zle recursive-edit -K zhcw |
| 154 | + zle -M "" |
| 155 | + zle -A saved-self-insert self-insert |
| 156 | + zle -A saved-backward-delete-char backward-delete-char |
| 157 | + zle -A saved-delete-char delete-char |
| 158 | + zle -D saved-self-insert saved-backward-delete-char saved-delete-char |
| 159 | + # Full initialization at next call |
| 160 | + __zew_hcw_call_count="0" |
| 161 | +fi |
0 commit comments