diff options
Diffstat (limited to 'Functions')
-rw-r--r-- | Functions/Zle/.distfiles | 2 | ||||
-rw-r--r-- | Functions/Zle/history-pattern-search | 81 |
2 files changed, 82 insertions, 1 deletions
diff --git a/Functions/Zle/.distfiles b/Functions/Zle/.distfiles index 4b2da07a1..b00da2f41 100644 --- a/Functions/Zle/.distfiles +++ b/Functions/Zle/.distfiles @@ -13,5 +13,5 @@ down-case-word-match forward-word-match kill-word-match match-words-by-style select-word-style transpose-words-match up-case-word-match delete-whole-word-match quote-and-complete-word url-quote-magic -zed-set-file-name +zed-set-file-name history-pattern-search ' diff --git a/Functions/Zle/history-pattern-search b/Functions/Zle/history-pattern-search new file mode 100644 index 000000000..02f85a2fb --- /dev/null +++ b/Functions/Zle/history-pattern-search @@ -0,0 +1,81 @@ +# Prompt for an search in the history for a pattern. +# Patterns to search are standard zsh patterns, but may include +# ^ at the start or $ at the end to anchor the pattern to the +# start or end of the history entry respectively. +# +# To search backwards, create a widget history-pattern-search-backward: +# zle -N history-pattern-search-backward history-pattern-search +# and to search forwards, create history-pattern-search-forward +# zle -N history-pattern-search-forward history-pattern-search + +# Use extended globbing by default. +emulate -L zsh +setopt extendedglob + +# Load required features. +autoload -U read-from-minibuffer +zmodload -i zsh/parameter + +local REPLY dir new +integer i +local -a found match mbegin mend + +# Decide if we are searching backwards or forwards. +if [[ $WIDGET = *forward* ]]; then + dir="forw" +else + dir="rev" +fi + +# Read pattern. Prompt could be made customisable. +read-from-minibuffer "pat ($dir): " + +# Abort if bad status or nothing entered +[[ $? -ne 0 || -z $REPLY ]] && return 0 + +# Handle start-of-line anchor. +if [[ $REPLY = \^* ]]; then + REPLY=$REPLY[2,-1] +else + REPLY="*$REPLY" +fi + +# Handle end-of-line anchor. +if [[ $REPLY = *\$ ]]; then + REPLY=$REPLY[1,-2] +else + REPLY="$REPLY*" +fi + +# Search history for pattern. +# As $history is an associative array we can get all matches. +found=(${(kon)history[(R)$REPLY]}) + +if [[ $dir = forw ]]; then + # Searching forward. Look back through matches until we + # get back to the current history number. + for (( i = ${#found}; i >= 1; i-- )); do + (( $found[$i] <= HISTNO )) && break + new=$found[$i] + done +else + # Searching backward. Look forward through matches until we + # reach the current history number. + for (( i = 1; i <= ${#found}; i++ )); do + (( $found[$i] >= HISTNO )) && break + new=$found[$i] + done +fi + +if [[ -n $new ]]; then + # Match found. Move to line. + HISTNO=$new + if [[ $REPLY = *\* && $history[$new] = (#b)(${~REPLY[1,-2]})* ]]; then + # If not anchored to the end, move to the end of the pattern + # we were searching for. + CURSOR=$mend[1] + fi + return 0 +else + return 1 +fi |