Update history substring search plugin
authorJoerg Jaspert <joerg@debian.org>
Wed, 15 Nov 2017 08:40:36 +0000 (09:40 +0100)
committerJoerg Jaspert <joerg@debian.org>
Wed, 15 Nov 2017 08:40:36 +0000 (09:40 +0100)
.zsh/plugins/history-substring-search.zsh

index e29c9b1..0edf85e 100644 (file)
@@ -7,6 +7,7 @@
 # Copyright (c) 2011 Sorin Ionescu
 # Copyright (c) 2011 Vincent Guerci
 # Copyright (c) 2016 Geza Lore
+# Copyright (c) 2017 Bengt Brodersen
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 ##############################################################################
 
 #-----------------------------------------------------------------------------
-# configuration variables
+# declare global configuration variables
 #-----------------------------------------------------------------------------
 
-HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='bg=magenta,fg=white,bold'
-HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='bg=red,fg=white,bold'
-HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS='i'
-HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE=''
+typeset -g HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='bg=magenta,fg=white,bold'
+typeset -g HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='bg=red,fg=white,bold'
+typeset -g HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS='i'
+typeset -g HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE=''
+typeset -g HISTORY_SUBSTRING_SEARCH_FUZZY=''
+
+#-----------------------------------------------------------------------------
+# declare internal global variables
+#-----------------------------------------------------------------------------
+
+typeset -g BUFFER MATCH MBEGIN MEND CURSOR
+typeset -g _history_substring_search_refresh_display
+typeset -g _history_substring_search_query_highlight
+typeset -g _history_substring_search_result
+typeset -g _history_substring_search_query
+typeset -g -a _history_substring_search_query_parts
+typeset -g -a _history_substring_search_raw_matches
+typeset -g -i _history_substring_search_raw_match_index
+typeset -g -a _history_substring_search_matches
+typeset -g -i _history_substring_search_match_index
+typeset -g -A _history_substring_search_unique_filter
 
 #-----------------------------------------------------------------------------
 # the main ZLE widgets
@@ -202,6 +220,7 @@ _history-substring-search-begin() {
     # speed things up a little.
     #
     _history_substring_search_query=
+    _history_substring_search_query_parts=()
     _history_substring_search_raw_matches=()
 
   else
@@ -212,20 +231,31 @@ _history-substring-search-begin() {
     _history_substring_search_query=$BUFFER
 
     #
-    # $BUFFER contains the text that is in the command-line currently.
-    # we put an extra "\\" before meta characters such as "\(" and "\)",
-    # so that they become "\\\(" and "\\\)".
+    # compose search pattern
     #
-    local escaped_query=${BUFFER//(#m)[\][()|\\*?#<>~^]/\\$MATCH}
+    if [[ -n $HISTORY_SUBSTRING_SEARCH_FUZZY ]]; then
+      #
+      # `=` split string in arguments
+      #
+      _history_substring_search_query_parts=(${=_history_substring_search_query})
+    else
+      _history_substring_search_query_parts=(${_history_substring_search_query})
+    fi
 
     #
-    # Find all occurrences of the search query in the history file.
+    # Escape and join query parts with wildcard character '*' as seperator
+    # `(j:CHAR:)` join array to string with CHAR as seperator
+    #
+    local search_pattern="*${(j:*:)_history_substring_search_query_parts[@]//(#m)[\][()|\\*?#<>~^]/\\$MATCH}*"
+
+    #
+    # Find all occurrences of the search pattern in the history file.
     #
     # (k) returns the "keys" (history index numbers) instead of the values
     # (R) returns values in reverse older, so the index of the youngest
     # matching history entry is at the head of the list.
     #
-    _history_substring_search_raw_matches=(${(k)history[(R)(#$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)*${escaped_query}*]})
+    _history_substring_search_raw_matches=(${(k)history[(R)(#$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)${search_pattern}]})
   fi
 
   #
@@ -244,8 +274,7 @@ _history-substring-search-begin() {
   #
   _history_substring_search_raw_match_index=0
   _history_substring_search_matches=()
-  unset _history_substring_search_unique_filter
-  typeset -A -g _history_substring_search_unique_filter
+  _history_substring_search_unique_filter=()
 
   #
   # If $_history_substring_search_match_index is equal to
@@ -288,16 +317,20 @@ _history-substring-search-end() {
   _zsh_highlight
 
   # highlight the search query inside the command line
-  if [[ -n $_history_substring_search_query_highlight && -n $_history_substring_search_query ]]; then
-    #
-    # The following expression yields a variable $MBEGIN, which
-    # indicates the begin position + 1 of the first occurrence
-    # of _history_substring_search_query in $BUFFER.
-    #
-    : ${(S)BUFFER##(#m$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)($_history_substring_search_query##)}
-    local begin=$(( MBEGIN - 1 ))
-    local end=$(( begin + $#_history_substring_search_query ))
-    region_highlight+=("$begin $end $_history_substring_search_query_highlight")
+  if [[ -n $_history_substring_search_query_highlight ]]; then
+    # highlight first matching query parts
+    local highlight_start_index=0
+    local highlight_end_index=0
+    for query_part in $_history_substring_search_query_parts; do
+      local escaped_query_part=${query_part//(#m)[\][()|\\*?#<>~^]/\\$MATCH}
+      # (i) get index of pattern
+      local query_part_match_index=${${BUFFER:$highlight_start_index}[(i)(#$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)${escaped_query_part}]}
+      if [[ $query_part_match_index -le ${#BUFFER:$highlight_start_index} ]]; then
+        highlight_start_index=$(( $highlight_start_index + $query_part_match_index ))
+        highlight_end_index=$(( $highlight_start_index + ${#query_part} ))
+        region_highlight+=("$(($highlight_start_index - 1)) $(($highlight_end_index - 1)) $_history_substring_search_query_highlight")
+      fi
+    done
   fi
 
   # For debugging purposes:
@@ -426,7 +459,7 @@ _history_substring_search_process_raw_matches() {
     #
     # Move on to the next raw entry and get its history index.
     #
-    (( _history_substring_search_raw_match_index++ ))
+    _history_substring_search_raw_match_index+=1
     local index=${_history_substring_search_raw_matches[$_history_substring_search_raw_match_index]}
 
     #
@@ -606,7 +639,7 @@ _history-substring-search-up-search() {
     # 1. Move index to point to the next match.
     # 2. Update display to indicate search found.
     #
-    (( _history_substring_search_match_index++ ))
+    _history_substring_search_match_index+=1
     _history-substring-search-found
 
   else
@@ -617,7 +650,7 @@ _history-substring-search-up-search() {
     #    _history_substring_search_matches.
     # 2. Update display to indicate search not found.
     #
-    (( _history_substring_search_match_index++ ))
+    _history_substring_search_match_index+=1
     _history-substring-search-not-found
   fi
 
@@ -686,7 +719,7 @@ _history-substring-search-down-search() {
     # 1. Move index to point to the previous match.
     # 2. Update display to indicate search found.
     #
-    (( _history_substring_search_match_index-- ))
+    _history_substring_search_match_index+=-1
     _history-substring-search-found
 
   else
@@ -697,7 +730,7 @@ _history-substring-search-down-search() {
     #    _history_substring_search_matches.
     # 2. Update display to indicate search not found.
     #
-    (( _history_substring_search_match_index-- ))
+    _history_substring_search_match_index+=-1
     _history-substring-search-not-found
   fi