#!/bin/zsh
# This is a Zle widget file. In general, it is s used as (without setup
# provided by the plugin):
#
# autoload browse-symbol
# zle -N browse-symbol
# zle -N browse-symbol-backwards browse-symbol
# zle -N browse-symbol-pbackwards browse-symbol
# zle -N browse-symbol-pforwards browse-symbol
# bindkey "^T" browse-symbol
#
# This will bind to Ctrl-T. The plugin binds to Ctrl-O Ctrl-K.
#
# Example zstyles:
# zstyle ":plugin:zinit:symbol-search" page-size 5
# zstyle ":plugin:zinit:symbol-search" highlight-color "fg=magenta,bold"
# zstyle ":plugin:zinit:symbol-search" heading-color "fg=18,bold"
# zstyle ":plugin:zinit:symbol-search" title-color "fg=180,bold"
# zstyle ":plugin:zinit:symbol-search" arrow-color "fg=180,bg=39,bold"
# zstyle ":plugin:zinit:symbol-search" func-color "fg=208,bold"
# zstyle ":plugin:zinit:symbol-search" var-color "fg=174,bg=39,bold"
# zstyle ":plugin:zinit:symbol-search" macro-color "fg=39,bold"
# zstyle ":plugin:zinit:symbol-search" eqdol-color "fg=183,bg=39,bold"

emulate -L zsh
setopt typesetsilent extendedglob noshortloops localtraps warncreateglobal

# When an error, then no cursor keys bindings
zmodload zsh/terminfo 2>/dev/null
zmodload zsh/termcap 2>/dev/null

typeset -gA TAG
integer -g __tfind_spe_index
integer -g __tfind_spe_restart __tfind_spe_call_count __tfind_spe_funct __tfind_spe_sort
typeset -g __tfind_page_size __tfind_high_color __tfind_heading_color \
	__tfind_title_color __tfind_arrow_color __tfind_func_color \
	__tfind_var_color __tfind_eqdol_color __tfind_macro_color
typeset -gaU __tfind_spe_found
typeset -ga __tfind_tag_data
typeset -g __tfind_git_or_project __tfind_outside_git
local mbegin mend match
local MATCH
integer MBEGIN MEND

(( __tfind_spe_call_count ++ ))
trap '(( __tfind_spe_call_count -- )); return 0;' INT

_tfind_find_index() {
    local q
    local -a p
    # Read tags file
    p=( (../)#TAGS(N) )
    TAG[file]=${${(On)p}[1]}
    [[ -f ./TAGS ]] && TAG[file]=$PWD/TAGS
    if [[ -n $TAG[file] ]]; then
        TAG[git-or-project]=${${TAG[file]:a}:h:t}
    else
        TAG[git-or-project]="<unknown>"
        #TAG[file]=
    fi

    # Pre-process found index
    TAG[file-pp]=${TAG[file]/TAGS/.TAGS}.z
    if [[ -n $TAG[file] && -f $TAG[file] && ( ! -f $TAG[file-pp] || $TAG[file] -nt $TAG[file-pp]) ]]
    then
        local sed_
        (( $+commands[sed] )) && sed_=sed
        (( $+commands[gsed] )) && sed_=gsed
        # Generate simplified file – append the filename at each line,
        # so that it's not only at the preamble line
        command $sed_ -r -n $'/^\x0c$/ { n; s/,[^,]*$//;s/^/\x02/; h; d;}; G; y/\\n/,/; p' $TAG[file] >! $TAG[file-pp]
    fi

    # Read index, and as index is found, establish git main dir for it
    __tfind_outside_git=$TAG[file]:h
    if [[ -n $TAG[file] && -f $TAG[file-pp] ]]; then
        __tfind_tag_data=( ${"${(@f)"$(<${TAG[file-pp]})"}"##[[:space:]]##} )
        # Cleanup functions and their preambles
        __tfind_tag_data=( ${__tfind_tag_data[@]/(#b)(\([^\)]#\))[[:space:]]#[\{]*($'\x7f')/$match[1]$match[2]} )
        __tfind_tag_data=( ${__tfind_tag_data[@]/(#b)[[:space:]]\#*($'\x7f')/$match[1]} )
        __tfind_outside_git="${PWD%/${$(git rev-parse --quiet --show-prefix 2>/dev/null)%/}}"
        if [[ -d $__tfind_outside_git && -n ${${(M)PWD##$__tfind_outside_git}##$HOME} ]]; then
            TAG[git-or-project]=$__tfind_outside_git:t
            TAG[repo-dir]=$__tfind_outside_git
        else
            TAG[git-or-project]=$TAG[file]:h
            TAG[repo-dir]=$TAG[file]:h
        fi
        return 0
    fi
    return 1
}

_tfind_error_msg()
{
    integer buflen=$#BUFFER
    if [[ -z $TAG[repo-dir] || $TAG[repo-dir] == . ]]; then
        POSTDISPLAY=$'\n'"Symbol index NOT found, NO DATA to show, sleeping…"
        local search_buffer=
    elif [[ $#__tfind_tag_data -eq 0 ]]; then
        POSTDISPLAY=$'\n'"The index file contains NO symbol data, forced sleeping..."
        local search_buffer=
    elif [[ $#__tfind_spe_found -eq 0 && $search_buffer == [[:space:]]# ]]; then
        POSTDISPLAY=$'\n'"No items found"
    elif [[ $search_buffer != [[:space:]]# && $#__tfind_spe_found -eq 0 ]]; then
        POSTDISPLAY=$'\n'"Found 0 matches for query: $search_buffer"
    else
        return 1
    fi
    region_highlight+=("$buflen $(( $buflen+$#POSTDISPLAY-$#search_buffer )) fg=179,bold")
    region_highlight+=("$(( $buflen+$#POSTDISPLAY-$#search_buffer ))  $(( $buflen+$#POSTDISPLAY )) fg=39,bold")
    # Number?
    [[ -n ${#${(MS)POSTDISPLAY##<->##}} ]] && \
        region_highlight+=("$((buflen+7)) $((buflen+7+${#${(MS)POSTDISPLAY##<->##}})) fg=39,bold")
    return 0

}
_tfind_main() {
    local match mbegin mend
    local MATCH
    integer MBEGIN MEND buflen=${#BUFFER}
    TAG[fun-xt-chars]='+.:@\/→↓←↑\$,_\--'
    # First call or restart?
    if [[ $__tfind_spe_call_count -le 1 || $__tfind_spe_restart = 1 ]]; then
        if [[ $__tfind_spe_call_count -le 1 ]]; then
            # Read configuration data
            zstyle -s ":plugin:zinit:symbol-search" page-size __tfind_page_size || __tfind_page_size=$(( LINES / 3 ))
            zstyle -s ":plugin:zinit:symbol-search" highlight-color __tfind_high_color || __tfind_high_color="fg=39,bold"
            zstyle -s ":plugin:zinit:symbol-search" heading-color __tfind_heading_color || __tfind_heading_color="fg=69,bold"
            zstyle -s ":plugin:zinit:symbol-search" title-color __tfind_title_color || __tfind_title_color="fg=208,bold"
            zstyle -s ":plugin:zinit:symbol-search" arrow-color __tfind_arrow_color || __tfind_arrow_color="fg=227,bg=69,bold"
            zstyle -s ":plugin:zini t:symbol-search" var-color __tfind_var_color || __tfind_var_color="fg=127,bold"
            zstyle -s ":plugin:zinit:symbol-search" func-color __tfind_func_color || __tfind_func_color="fg=70,bold"
            zstyle -s ":plugin:zinit:symbol-search" macro-color __tfind_macro_color || __tfind_macro_color="fg=208,bold"
            zstyle -s ":plugin:zinit:symbol-search" eqdol-color __tfind_eqdol_color || __tfind_eqdol_color="fg=69,bold"

        # Find the index to operate on, git dir, etc.
        _tfind_find_index || { _tfind_error_msg && return;}
       fi

        # '0' will get changed into $to_display limit
        [[ $WIDGET = *-symbol || $WIDGET = *-pforwards ]] && __tfind_spe_index=1
        [[ $WIDGET = *-backwards || $WIDGET = *-pbackwards ]] && __tfind_spe_index=0
        __tfind_spe_found=()
        __tfind_spe_restart=0
    else
        # Consecutive call
        [[ $WIDGET = *-symbol ]] && (( __tfind_spe_index ++ ))
        [[ $WIDGET = *-backwards ]] && (( __tfind_spe_index -- ))
        [[ $WIDGET = *-pforwards ]] && (( __tfind_spe_index = __tfind_spe_index + __tfind_page_size ))
        [[ $WIDGET = *-pbackwards ]] && (( __tfind_spe_index = __tfind_spe_index - __tfind_page_size ))
    fi

    # Find history entries matching pattern *word1*~^*word2*~^*word3* etc.
    local search_buffer="${BUFFER%% ##}" search_pattern="" csearch_pattern=""
    search_buffer="${${search_buffer## ##}%% ##}"
    search_buffer="${search_buffer//(#m)[][*?|#~^()><\\]/\\$MATCH}"
    search_pattern="*${search_buffer// ##/*~^*}*"
    csearch_pattern="${search_buffer// ##/|}"

    if [[ $#__tfind_spe_found -eq 0 ]]; then
        # The repeat will make the matching work on a fresh heap arena
        repeat 1; do
            # Match only before ^? ($'\177')
            __tfind_spe_found=( "${(@M)__tfind_tag_data:#(#i)$~search_pattern*$'\177'*}" )
            ((__tfind_spe_funct)) &&  __tfind_spe_found=(${(M)__tfind_spe_found:#[[:alnum:]$TAG[fun-xt-chars]]##[[:space:]]#\([^\)]#\)[[:space:]]#(\{|)*})
            ((__tfind_spe_sort)) &&  __tfind_spe_found=(${(no)__tfind_spe_found})
        done
    fi

    if ((!$#__tfind_spe_found)); then
        _tfind_error_msg && return
    fi

    #
    # Pagination, index value guards
    #

    integer page_size=$__tfind_page_size
    integer max_index="$#__tfind_spe_found"
    [[ $page_size -gt $max_index ]] && page_size=$max_index
    [[ $__tfind_spe_index -le 0 ]] && __tfind_spe_index=$max_index
    [[ $__tfind_spe_index -gt $max_index ]] && __tfind_spe_index=1
    integer page_start_idx=$(( ((__tfind_spe_index-1)/page_size)*page_size+1 ))
    integer on_page_idx=$(( (__tfind_spe_index-1) % page_size + 1 ))

    #
    # Prepare display
    #

    typeset -a disp_list
    disp_list=( "${(@)__tfind_spe_found[page_start_idx,page_start_idx+page_size-1]}" )

    # Remove meta-data from the entries
    disp_list=( "${(@)disp_list//$'\177'*/}" )

    # All entries should have multilines replaced
    disp_list=( "${(@)disp_list//$'\n'/\\n}" )
    # ... and truncated to display width, and
    # also preceeded by two spaces
    disp_list=( "${(@)disp_list/(#m)*/  ${MATCH[1,COLUMNS-8]}}" )

    local p=$'\n'
    local entry=$disp_list[on_page_idx]
    entry[1]='»'
    disp_list[on_page_idx]=$entry

    #
    # Detect where "> .." entry starts
    #

    local txt_before="${(F)${(@)disp_list[1,on_page_idx-1]}}"

    #
    # Colorify
    #
    local noun=${${${__tfind_spe_funct:#0}:+function}:-symbol}
    local preamble=$'\n'"View of ${noun}s for repo: «««${(U)TAG[git-or-project]}»»» located at: $TAG[repo-dir]:h"$'\n'"${(C)noun} no. #$__tfind_spe_index. Found $max_index ${noun}s in the index."$'\n' \
    key="Ctrl-f to toggle functions-ONLY view. Alt-s to toggle sort."$'\n'
    preamble+=$key

    local text="${(F)disp_list}"
    integer offset=${#preamble}+$buflen

    POSTDISPLAY="$preamble$text"

    region_highlight=( "$(( offset + ${#txt_before} )) $(( offset + ${#txt_before} + ${#entry} + 1 )) underline" )

    color_att() { local c;if (($4==0)){c=$__tfind_title_color;} elif (($4==1)){c=$__tfind_high_color;} elif (($4==4)){c=$__tfind_var_color;} elif (($4==7)){c=$__tfind_func_color;} elif (($4==9)){c=$__tfind_eqdol_color;} elif (($4==10)){c=$__tfind_macro_color;} else {c=$__tfind_arrow_color;}; region_highlight_+=("$(($1+$2-1)) $(($1+$3)) $c"); }
    functions -M coloratt 4 4 color_att
    local -a region_highlight_
    # Also highlight project name
    local h="$(( 30+buflen+__tfind_spe_funct*2 )) $(( 30+$buflen+${#TAG[git-or-project]}+__tfind_spe_funct*2 )) $__tfind_title_color"
    local q="$buflen $offset $__tfind_heading_color"
    region_highlight+=( $q $h )
    : "${preamble//(#b)no. ([^.]##)./$((coloratt(buflen,mbegin[1],mend[1],0)))}"
    : "${preamble//(#b)Found ([0-9]##)/$((coloratt(buflen,mbegin[1],mend[1],1)))}"
    : "${preamble//(#b)» located at: ([^$p]##)/$((coloratt(buflen,mbegin[1],mend[1],1)))}"
    : "${preamble//(#b)(Ctrl-f)/$((coloratt(buflen,mbegin[1],mend[1],0)))}"
    : "${preamble//(#b)(Alt-s)/$((coloratt(buflen,mbegin[1],mend[1],0)))}"
    : "${text//((#s)|$p)(#b)(»)/$((coloratt(offset,mbegin[1],mend[1],3)))}"
    # Basic syntax highlighting - a few keywords like C/Java type names
    : "${text//(#b)((([[:space:]\(\{\[]int|double|enum|short|long|(u|w|g|gu)(int|char|long|short)(8|16|32|64|128|max|)(_t|)|char|(|un)signed|FILE|const|restrict|size_t|va_list|ptrdiff_t|off_t|gboolean|gpointer|gconstpointer|typedef|static|struct|union)[[:space:]])|[a-zA-Z_]##_t|local|integer|float|declare|typeset|readonly)/$((coloratt(offset,mbegin[1],mend[1],4)))}"
    : "${text//(#b)(=)/$((coloratt(offset,mbegin[1],mend[1],9)))}"
    : "${text//(#b)(\#[[:space:]]#(include|define|if|endif))/$((coloratt(offset,mbegin[1],mend[1],10)))}"
    : "${text//(#b)(\$<->#)/$((coloratt(offset,mbegin[1],mend[1],9)))}"
    : "${text//(#b)([[:alnum:]$TAG[fun-xt-chars]]##)[[:space:]]#\([^\)]#\)/$((coloratt(offset,mbegin[1],mend[1],7)))}"
    : "${text//(#b)\#[[:space:]]#(include|define)[[:space:]]##([[:alnum:]_]##)[^[:alnum:]_]/$((coloratt(offset,mbegin[2],mend[2],7)))}"
    if [[ -n $search_pattern ]]; then
        : "${(f)${(S)text//*(#bi)(${~csearch_pattern})/$((coloratt(offset,mbegin[1],mend[1],1)))}}"
    fi

    functions +M color_att
    unfunction color_att
    region_highlight+=( $region_highlight_ )
}


_tfind_functions() {
    __tfind_spe_funct=1-__tfind_spe_funct
    __tfind_spe_restart=1
    _tfind_simulate_widget
}
_tfind_sort() {
    __tfind_spe_sort=1-__tfind_spe_sort
    __tfind_spe_restart=1
    _tfind_simulate_widget
}
_tfind_simulate_widget() {
    (( __tfind_spe_call_count ++ ))
    _tfind_main
}

_tfind_self_insert() {
    [[ $#KEYS ]] && __tfind_spe_restart=1
    LBUFFER+="${KEYS[-1]}"
    _tfind_simulate_widget
}

_tfind_backward_delete_char() {
    [[ $#LBUFFER ]] && __tfind_spe_restart=1
    LBUFFER="${LBUFFER%?}"
    _tfind_simulate_widget
}

_tfind_delete_char() {
    [[ $#RBUFFER ]] && __tfind_spe_restart=1
    RBUFFER="${RBUFFER#?}"
    _tfind_simulate_widget
}

_tfind_cancel_accept() {
    BUFFER=""
    __tfind_spe_index=-1
    zle .accept-line
}

_tfind_main

if [[ $__tfind_spe_call_count -eq 1 ]]; then
    # Make the tfind keymap a copy of the current main
    bindkey -N tfind 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 tfind '^[OA' $up_widget
    bindkey -M tfind '^[OB' $down_widget
    bindkey -M tfind '^[[A' $up_widget
    bindkey -M tfind '^[[B' $down_widget
    [[ -n "$termcap[ku]" ]] && bindkey -M tfind "$termcap[ku]" $up_widget
    [[ -n "$termcap[kd]" ]] && bindkey -M tfind "$termcap[kd]" $down_widget
    [[ -n "$termcap[kD]" ]] && bindkey -M tfind "$termcap[kD]" delete-char
    [[ -n "$terminfo[kcuu1]" ]] && bindkey -M tfind "$terminfo[kcuu1]" $up_widget
    [[ -n "$terminfo[kcud1]" ]] && bindkey -M tfind "$terminfo[kcud1]" $down_widget
    [[ -n "$terminfo[kdch1]" ]] && bindkey -M tfind "$terminfo[kdch1]" delete-char

    # More bindkeys, to remove influence of overloading plugins (sy-h, suggestions)
    # Left/Right cursor keys
    bindkey -M tfind '^[[D' .backward-char
    bindkey -M tfind '^[[C' .forward-char
    [[ -n "$termcap[kl]" ]] && bindkey -M tfind "$termcap[kl]" .backward-char
    [[ -n "$termcap[kr]" ]] && bindkey -M tfind "$termcap[kr]" .forward-char
    [[ -n "$terminfo[kcub1]" ]] && bindkey -M tfind "$terminfo[kcub1]" .backward-char
    [[ -n "$terminfo[kcuf1]" ]] && bindkey -M tfind "$terminfo[kcuf1]" .forward-char
    # Now Home/End keys, first few recorded in my .zshrc during the years sequences
    bindkey -M tfind "\e[1~" .beginning-of-line
    bindkey -M tfind "\e[7~" .beginning-of-line
    bindkey -M tfind "\e[H"  .beginning-of-line
    bindkey -M tfind "\e[4~" .end-of-line
    bindkey -M tfind "\e[F"  .end-of-line
    bindkey -M tfind "\e[8~" .end-of-line
    [[ -n "$termcap[kh]" ]] && bindkey -M tfind "$termcap[kh]" .beginning-of-line
    [[ -n "$termcap[@7]" ]] && bindkey -M tfind "$termcap[@7]" .end-of-line
    [[ -n "$terminfo[khome]" ]] && bindkey -M tfind "$terminfo[khome]" .beginning-of-line
    [[ -n "$terminfo[kend]" ]] && bindkey -M tfind "$terminfo[kend]" .end-of-line
    # The same for Ctrl-E, Ctrl-F
    bindkey -M tfind '^A' .beginning-of-line
    bindkey -M tfind '^E' .end-of-line
    # Additional keys
    bindkey -M tfind '^[b' .backward-word
    bindkey -M tfind '^[B' .backward-word
    bindkey -M tfind '^[f' .forward-word
    bindkey -M tfind '^[F' .forward-word
    bindkey -M tfind '^[w' .forward-word
    bindkey -M tfind '^[W' .forward-word

    # Additional keys
    bindkey -M tfind '^P' $up_widget
    bindkey -M tfind '^N' $down_widget

    # Page Up, Page Down keys
    [[ -n "$termcap[kP]" ]] && bindkey -M tfind "$termcap[kP]" $pup_widget
    [[ -n "$termcap[kN]" ]] && bindkey -M tfind "$termcap[kN]" $pdown_widget
    [[ -n "$terminfo[kpp]" ]] && bindkey -M tfind "$terminfo[kpp]" $pup_widget
    [[ -n "$terminfo[knp]" ]] && bindkey -M tfind "$terminfo[knp]" $pdown_widget

    # Needed for Fedora 23, zsh-5.1.1
    bindkey -M tfind ' ' self-insert

    # Removal of default Ctrl-R binding
    bindkey -M tfind '^R' $down_widget
    # If one would like to re-open
    bindkey -M tfind '^O' $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 _tfind_self_insert
    zle -N backward-delete-char _tfind_backward_delete_char
    zle -N delete-char _tfind_delete_char
    zle -N tfind-functions _tfind_functions
    zle -N tfind-sort _tfind_sort

    # 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 _tfind_simulate_widget
    zle -N $up_widget _tfind_simulate_widget

    zle -A $pdown_widget saved-$pdown_widget
    zle -A $pup_widget saved-$pup_widget
    zle -N $pdown_widget _tfind_simulate_widget
    zle -N $pup_widget _tfind_simulate_widget
    if (( $+widgets[zle-line-pre-redraw] )); then
        zle -A zle-line-pre-redraw saved-pre-redraw
        zle -D zle-line-pre-redraw
    fi
    local selected_editor cd_at_edit tagtext tagline taglinebyte tagfile
    local -a comm
    comm=()

    # Add Ctrl-V, ESC bindings to cancel search
    # A workaround for Zsh versions like 5.0.2
    zle -N _tfind_cancel_accept
    bindkey -M tfind "^[" _tfind_cancel_accept
    bindkey -M tfind "^f" tfind-functions
    bindkey -M tfind "\es" tfind-sort

    local redrawbkp=0
    # Trap INT to manually interrupt Zle to work around a bug
    trap 'zle && zle .send-break' INT
    if zle .recursive-edit -K tfind; then
        if ((__tfind_spe_index<=0)); then
            :
        else
            zstyle -s ":plugin:zinit:symbol-search" editor selected_editor || selected_editor=${VISUAL:-${EDITOR:-mcedit}}
            zstyle -T ":plugin:zinit:symbol-search" cd_at_edit && cd_at_edit=yes || cd_at_edit=no
            (( ! $+commands[$selected_editor] )) && selected_editor=vim
            (( ! $+commands[$selected_editor] )) && selected_editor=nano
            (( ! $+commands[$selected_editor] )) && selected_editor=emacs

            tagtext=$__tfind_spe_found[__tfind_spe_index]
            if [[ $tagtext = (#b)[^$'\177']#$'\177'[^$'\1']#$'\1'([^$'\2']#)$'\2'(*) ]]; then
                taglinebyte=${match[1]}
                tagline=${taglinebyte%%,*}

                # CD vs absolute path
                if [[ $match[2] != /* && -n $TAG[repo-dir] ]]; then
                    tagfile=$TAG[repo-dir]/$match[2]
                else
                    tagfile=$match[2]
                fi
                [[ ! -f $tagfile && -f $match[2] ]] && tagfile=$match[2]
                # Editor command
                case "$selected_editor" in
                    (vim|vi|gvim|mvim|nvim)
                        comm+=( $selected_editor "+$tagline" -- "${(q)tagfile}" )
                        ;;
                    (emacs|emacsclient)
                        comm+=( $selected_editor "+$tagline" -- "${(q)tagfile}" )
                        ;;
                    (gedit)
                        comm+=( $selected_editor "+$tagline" -- "${(q)tagfile}" )
                        ;;
                    (nano)
                        comm+=( $selected_editor "+$tagline" -- "${(q)tagfile}" )
                        ;;
                    (mcedit)
                        comm+=( $selected_editor "+$tagline" -- "${(q)tagfile}" )
                        ;;
                    (*)
                        comm+=( $selected_editor "+$tagline" -- "${(q)tagfile}" )
                        ;;
                esac
            fi
        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

    if (( $+widgets[saved-pre-redraw] )); then
        zle -A saved-pre-redraw zle-line-pre-redraw
        zle -D saved-pre-redraw
    fi

    # Full reinitialisation at next call
    __tfind_spe_call_count=0

    # Free memory
    __tfind_spe_found=()
    __tfind_tag_data=()
    region_highlight=()

    # Is there a command to run?
    if [[ $#comm != 0 ]]; then
        local auto_run
        zstyle -T ":plugin:zinit" auto_run && auto_run=yes || auto_run=no
        BUFFER=$comm[*]
        CURSOR=$buflen
        [[ $auto_run = yes ]] && zle .accept-line
    fi
elif (( __tfind_spe_call_count > 0 )); then
    (( __tfind_spe_call_count -- ))
fi

# Local Variables:
# mode: Shell-Script
# sh-indentation: 2
# indent-tabs-mode: nil
# sh-basic-offset: 2
# End:
# vim: ft=zsh sw=2 ts=2 et
