Mercurial > dotfiles
comparison dot_zsh/zsh-history-substring-search.zsh @ 262:44d179225271
Add history substring search plugin
author | zegervdv <zegervdv@me.com> |
---|---|
date | Sun, 24 May 2020 10:24:04 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
261:217fba8117c8 | 262:44d179225271 |
---|---|
1 #!/usr/bin/env zsh | |
2 ############################################################################## | |
3 # | |
4 # Copyright (c) 2009 Peter Stephenson | |
5 # Copyright (c) 2011 Guido van Steen | |
6 # Copyright (c) 2011 Suraj N. Kurapati | |
7 # Copyright (c) 2011 Sorin Ionescu | |
8 # Copyright (c) 2011 Vincent Guerci | |
9 # Copyright (c) 2016 Geza Lore | |
10 # Copyright (c) 2017 Bengt Brodersen | |
11 # All rights reserved. | |
12 # | |
13 # Redistribution and use in source and binary forms, with or without | |
14 # modification, are permitted provided that the following conditions are met: | |
15 # | |
16 # * Redistributions of source code must retain the above copyright | |
17 # notice, this list of conditions and the following disclaimer. | |
18 # | |
19 # * Redistributions in binary form must reproduce the above | |
20 # copyright notice, this list of conditions and the following | |
21 # disclaimer in the documentation and/or other materials provided | |
22 # with the distribution. | |
23 # | |
24 # * Neither the name of the FIZSH nor the names of its contributors | |
25 # may be used to endorse or promote products derived from this | |
26 # software without specific prior written permission. | |
27 # | |
28 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
29 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
30 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
31 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
32 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
33 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
34 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
35 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
36 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
37 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
38 # POSSIBILITY OF SUCH DAMAGE. | |
39 # | |
40 ############################################################################## | |
41 | |
42 #----------------------------------------------------------------------------- | |
43 # declare global configuration variables | |
44 #----------------------------------------------------------------------------- | |
45 | |
46 typeset -g HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='bg=magenta,fg=white,bold' | |
47 typeset -g HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='bg=red,fg=white,bold' | |
48 typeset -g HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS='i' | |
49 typeset -g HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE='' | |
50 typeset -g HISTORY_SUBSTRING_SEARCH_FUZZY='' | |
51 | |
52 #----------------------------------------------------------------------------- | |
53 # declare internal global variables | |
54 #----------------------------------------------------------------------------- | |
55 | |
56 typeset -g BUFFER MATCH MBEGIN MEND CURSOR | |
57 typeset -g _history_substring_search_refresh_display | |
58 typeset -g _history_substring_search_query_highlight | |
59 typeset -g _history_substring_search_result | |
60 typeset -g _history_substring_search_query | |
61 typeset -g -a _history_substring_search_query_parts | |
62 typeset -g -a _history_substring_search_raw_matches | |
63 typeset -g -i _history_substring_search_raw_match_index | |
64 typeset -g -a _history_substring_search_matches | |
65 typeset -g -i _history_substring_search_match_index | |
66 typeset -g -A _history_substring_search_unique_filter | |
67 | |
68 #----------------------------------------------------------------------------- | |
69 # the main ZLE widgets | |
70 #----------------------------------------------------------------------------- | |
71 | |
72 history-substring-search-up() { | |
73 _history-substring-search-begin | |
74 | |
75 _history-substring-search-up-history || | |
76 _history-substring-search-up-buffer || | |
77 _history-substring-search-up-search | |
78 | |
79 _history-substring-search-end | |
80 } | |
81 | |
82 history-substring-search-down() { | |
83 _history-substring-search-begin | |
84 | |
85 _history-substring-search-down-history || | |
86 _history-substring-search-down-buffer || | |
87 _history-substring-search-down-search | |
88 | |
89 _history-substring-search-end | |
90 } | |
91 | |
92 zle -N history-substring-search-up | |
93 zle -N history-substring-search-down | |
94 | |
95 #----------------------------------------------------------------------------- | |
96 # implementation details | |
97 #----------------------------------------------------------------------------- | |
98 | |
99 zmodload -F zsh/parameter | |
100 | |
101 # | |
102 # We have to "override" some keys and widgets if the | |
103 # zsh-syntax-highlighting plugin has not been loaded: | |
104 # | |
105 # https://github.com/nicoulaj/zsh-syntax-highlighting | |
106 # | |
107 if [[ $+functions[_zsh_highlight] -eq 0 ]]; then | |
108 # | |
109 # Dummy implementation of _zsh_highlight() that | |
110 # simply removes any existing highlights when the | |
111 # user inserts printable characters into $BUFFER. | |
112 # | |
113 _zsh_highlight() { | |
114 if [[ $KEYS == [[:print:]] ]]; then | |
115 region_highlight=() | |
116 fi | |
117 } | |
118 | |
119 # | |
120 # The following snippet was taken from the zsh-syntax-highlighting project: | |
121 # | |
122 # https://github.com/zsh-users/zsh-syntax-highlighting/blob/56b134f5d62ae3d4e66c7f52bd0cc2595f9b305b/zsh-syntax-highlighting.zsh#L126-161 | |
123 # | |
124 # Copyright (c) 2010-2011 zsh-syntax-highlighting contributors | |
125 # All rights reserved. | |
126 # | |
127 # Redistribution and use in source and binary forms, with or without | |
128 # modification, are permitted provided that the following conditions are | |
129 # met: | |
130 # | |
131 # * Redistributions of source code must retain the above copyright | |
132 # notice, this list of conditions and the following disclaimer. | |
133 # | |
134 # * Redistributions in binary form must reproduce the above copyright | |
135 # notice, this list of conditions and the following disclaimer in the | |
136 # documentation and/or other materials provided with the distribution. | |
137 # | |
138 # * Neither the name of the zsh-syntax-highlighting contributors nor the | |
139 # names of its contributors may be used to endorse or promote products | |
140 # derived from this software without specific prior written permission. | |
141 # | |
142 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | |
143 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
144 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
145 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR | |
146 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
147 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
148 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
149 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
150 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
151 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
152 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
153 # | |
154 #--------------8<-------------------8<-------------------8<----------------- | |
155 # Rebind all ZLE widgets to make them invoke _zsh_highlights. | |
156 _zsh_highlight_bind_widgets() | |
157 { | |
158 # Load ZSH module zsh/zleparameter, needed to override user defined widgets. | |
159 zmodload zsh/zleparameter 2>/dev/null || { | |
160 echo 'zsh-syntax-highlighting: failed loading zsh/zleparameter.' >&2 | |
161 return 1 | |
162 } | |
163 | |
164 # Override ZLE widgets to make them invoke _zsh_highlight. | |
165 local cur_widget | |
166 for cur_widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|run-help|which-command|beep|yank*)}; do | |
167 case $widgets[$cur_widget] in | |
168 | |
169 # Already rebound event: do nothing. | |
170 user:$cur_widget|user:_zsh_highlight_widget_*);; | |
171 | |
172 # User defined widget: override and rebind old one with prefix "orig-". | |
173 user:*) eval "zle -N orig-$cur_widget ${widgets[$cur_widget]#*:}; \ | |
174 _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ | |
175 zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; | |
176 | |
177 # Completion widget: override and rebind old one with prefix "orig-". | |
178 completion:*) eval "zle -C orig-$cur_widget ${${widgets[$cur_widget]#*:}/:/ }; \ | |
179 _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ | |
180 zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; | |
181 | |
182 # Builtin widget: override and make it call the builtin ".widget". | |
183 builtin) eval "_zsh_highlight_widget_$cur_widget() { builtin zle .$cur_widget -- \"\$@\" && _zsh_highlight }; \ | |
184 zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; | |
185 | |
186 # Default: unhandled case. | |
187 *) echo "zsh-syntax-highlighting: unhandled ZLE widget '$cur_widget'" >&2 ;; | |
188 esac | |
189 done | |
190 } | |
191 #-------------->8------------------->8------------------->8----------------- | |
192 | |
193 _zsh_highlight_bind_widgets | |
194 fi | |
195 | |
196 _history-substring-search-begin() { | |
197 setopt localoptions extendedglob | |
198 | |
199 _history_substring_search_refresh_display= | |
200 _history_substring_search_query_highlight= | |
201 | |
202 # | |
203 # If the buffer is the same as the previously displayed history substring | |
204 # search result, then just keep stepping through the match list. Otherwise | |
205 # start a new search. | |
206 # | |
207 if [[ -n $BUFFER && $BUFFER == ${_history_substring_search_result:-} ]]; then | |
208 return; | |
209 fi | |
210 | |
211 # | |
212 # Clear the previous result. | |
213 # | |
214 _history_substring_search_result='' | |
215 | |
216 if [[ -z $BUFFER ]]; then | |
217 # | |
218 # If the buffer is empty, we will just act like up-history/down-history | |
219 # in ZSH, so we do not need to actually search the history. This should | |
220 # speed things up a little. | |
221 # | |
222 _history_substring_search_query= | |
223 _history_substring_search_query_parts=() | |
224 _history_substring_search_raw_matches=() | |
225 | |
226 else | |
227 # | |
228 # For the purpose of highlighting we keep a copy of the original | |
229 # query string. | |
230 # | |
231 _history_substring_search_query=$BUFFER | |
232 | |
233 # | |
234 # compose search pattern | |
235 # | |
236 if [[ -n $HISTORY_SUBSTRING_SEARCH_FUZZY ]]; then | |
237 # | |
238 # `=` split string in arguments | |
239 # | |
240 _history_substring_search_query_parts=(${=_history_substring_search_query}) | |
241 else | |
242 _history_substring_search_query_parts=(${==_history_substring_search_query}) | |
243 fi | |
244 | |
245 # | |
246 # Escape and join query parts with wildcard character '*' as seperator | |
247 # `(j:CHAR:)` join array to string with CHAR as seperator | |
248 # | |
249 local search_pattern="*${(j:*:)_history_substring_search_query_parts[@]//(#m)[\][()|\\*?#<>~^]/\\$MATCH}*" | |
250 | |
251 # | |
252 # Find all occurrences of the search pattern in the history file. | |
253 # | |
254 # (k) returns the "keys" (history index numbers) instead of the values | |
255 # (R) returns values in reverse older, so the index of the youngest | |
256 # matching history entry is at the head of the list. | |
257 # | |
258 _history_substring_search_raw_matches=(${(k)history[(R)(#$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)${search_pattern}]}) | |
259 fi | |
260 | |
261 # | |
262 # In order to stay as responsive as possible, we will process the raw | |
263 # matches lazily (when the user requests the next match) to choose items | |
264 # that need to be displayed to the user. | |
265 # _history_substring_search_raw_match_index holds the index of the last | |
266 # unprocessed entry in _history_substring_search_raw_matches. Any items | |
267 # that need to be displayed will be added to | |
268 # _history_substring_search_matches. | |
269 # | |
270 # We use an associative array (_history_substring_search_unique_filter) as | |
271 # a 'set' data structure to ensure uniqueness of the results if desired. | |
272 # If an entry (key) is in the set (non-empty value), then we have already | |
273 # added that entry to _history_substring_search_matches. | |
274 # | |
275 _history_substring_search_raw_match_index=0 | |
276 _history_substring_search_matches=() | |
277 _history_substring_search_unique_filter=() | |
278 | |
279 # | |
280 # If $_history_substring_search_match_index is equal to | |
281 # $#_history_substring_search_matches + 1, this indicates that we | |
282 # are beyond the end of $_history_substring_search_matches and that we | |
283 # have also processed all entries in | |
284 # _history_substring_search_raw_matches. | |
285 # | |
286 # If $#_history_substring_search_match_index is equal to 0, this indicates | |
287 # that we are beyond the beginning of $_history_substring_search_matches. | |
288 # | |
289 # If we have initially pressed "up" we have to initialize | |
290 # $_history_substring_search_match_index to 0 so that it will be | |
291 # incremented to 1. | |
292 # | |
293 # If we have initially pressed "down" we have to initialize | |
294 # $_history_substring_search_match_index to 1 so that it will be | |
295 # decremented to 0. | |
296 # | |
297 if [[ $WIDGET == history-substring-search-down ]]; then | |
298 _history_substring_search_match_index=1 | |
299 else | |
300 _history_substring_search_match_index=0 | |
301 fi | |
302 } | |
303 | |
304 _history-substring-search-end() { | |
305 setopt localoptions extendedglob | |
306 | |
307 _history_substring_search_result=$BUFFER | |
308 | |
309 # the search was successful so display the result properly by clearing away | |
310 # existing highlights and moving the cursor to the end of the result buffer | |
311 if [[ $_history_substring_search_refresh_display -eq 1 ]]; then | |
312 region_highlight=() | |
313 CURSOR=${#BUFFER} | |
314 fi | |
315 | |
316 # highlight command line using zsh-syntax-highlighting | |
317 _zsh_highlight | |
318 | |
319 # highlight the search query inside the command line | |
320 if [[ -n $_history_substring_search_query_highlight ]]; then | |
321 # highlight first matching query parts | |
322 local highlight_start_index=0 | |
323 local highlight_end_index=0 | |
324 local query_part | |
325 for query_part in $_history_substring_search_query_parts; do | |
326 local escaped_query_part=${query_part//(#m)[\][()|\\*?#<>~^]/\\$MATCH} | |
327 # (i) get index of pattern | |
328 local query_part_match_index="${${BUFFER:$highlight_start_index}[(i)(#$HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS)${escaped_query_part}]}" | |
329 if [[ $query_part_match_index -le ${#BUFFER:$highlight_start_index} ]]; then | |
330 highlight_start_index=$(( $highlight_start_index + $query_part_match_index )) | |
331 highlight_end_index=$(( $highlight_start_index + ${#query_part} )) | |
332 region_highlight+=("$(($highlight_start_index - 1)) $(($highlight_end_index - 1)) $_history_substring_search_query_highlight") | |
333 fi | |
334 done | |
335 fi | |
336 | |
337 # For debugging purposes: | |
338 # zle -R "mn: "$_history_substring_search_match_index" m#: "${#_history_substring_search_matches} | |
339 # read -k -t 200 && zle -U $REPLY | |
340 | |
341 # Exit successfully from the history-substring-search-* widgets. | |
342 return 0 | |
343 } | |
344 | |
345 _history-substring-search-up-buffer() { | |
346 # | |
347 # Check if the UP arrow was pressed to move the cursor within a multi-line | |
348 # buffer. This amounts to three tests: | |
349 # | |
350 # 1. $#buflines -gt 1. | |
351 # | |
352 # 2. $CURSOR -ne $#BUFFER. | |
353 # | |
354 # 3. Check if we are on the first line of the current multi-line buffer. | |
355 # If so, pressing UP would amount to leaving the multi-line buffer. | |
356 # | |
357 # We check this by adding an extra "x" to $LBUFFER, which makes | |
358 # sure that xlbuflines is always equal to the number of lines | |
359 # until $CURSOR (including the line with the cursor on it). | |
360 # | |
361 local buflines XLBUFFER xlbuflines | |
362 buflines=(${(f)BUFFER}) | |
363 XLBUFFER=$LBUFFER"x" | |
364 xlbuflines=(${(f)XLBUFFER}) | |
365 | |
366 if [[ $#buflines -gt 1 && $CURSOR -ne $#BUFFER && $#xlbuflines -ne 1 ]]; then | |
367 zle up-line-or-history | |
368 return 0 | |
369 fi | |
370 | |
371 return 1 | |
372 } | |
373 | |
374 _history-substring-search-down-buffer() { | |
375 # | |
376 # Check if the DOWN arrow was pressed to move the cursor within a multi-line | |
377 # buffer. This amounts to three tests: | |
378 # | |
379 # 1. $#buflines -gt 1. | |
380 # | |
381 # 2. $CURSOR -ne $#BUFFER. | |
382 # | |
383 # 3. Check if we are on the last line of the current multi-line buffer. | |
384 # If so, pressing DOWN would amount to leaving the multi-line buffer. | |
385 # | |
386 # We check this by adding an extra "x" to $RBUFFER, which makes | |
387 # sure that xrbuflines is always equal to the number of lines | |
388 # from $CURSOR (including the line with the cursor on it). | |
389 # | |
390 local buflines XRBUFFER xrbuflines | |
391 buflines=(${(f)BUFFER}) | |
392 XRBUFFER="x"$RBUFFER | |
393 xrbuflines=(${(f)XRBUFFER}) | |
394 | |
395 if [[ $#buflines -gt 1 && $CURSOR -ne $#BUFFER && $#xrbuflines -ne 1 ]]; then | |
396 zle down-line-or-history | |
397 return 0 | |
398 fi | |
399 | |
400 return 1 | |
401 } | |
402 | |
403 _history-substring-search-up-history() { | |
404 # | |
405 # Behave like up in ZSH, except clear the $BUFFER | |
406 # when beginning of history is reached like in Fish. | |
407 # | |
408 if [[ -z $_history_substring_search_query ]]; then | |
409 | |
410 # we have reached the absolute top of history | |
411 if [[ $HISTNO -eq 1 ]]; then | |
412 BUFFER= | |
413 | |
414 # going up from somewhere below the top of history | |
415 else | |
416 zle up-line-or-history | |
417 fi | |
418 | |
419 return 0 | |
420 fi | |
421 | |
422 return 1 | |
423 } | |
424 | |
425 _history-substring-search-down-history() { | |
426 # | |
427 # Behave like down-history in ZSH, except clear the | |
428 # $BUFFER when end of history is reached like in Fish. | |
429 # | |
430 if [[ -z $_history_substring_search_query ]]; then | |
431 | |
432 # going down from the absolute top of history | |
433 if [[ $HISTNO -eq 1 && -z $BUFFER ]]; then | |
434 BUFFER=${history[1]} | |
435 _history_substring_search_refresh_display=1 | |
436 | |
437 # going down from somewhere above the bottom of history | |
438 else | |
439 zle down-line-or-history | |
440 fi | |
441 | |
442 return 0 | |
443 fi | |
444 | |
445 return 1 | |
446 } | |
447 | |
448 _history_substring_search_process_raw_matches() { | |
449 # | |
450 # Process more outstanding raw matches and append any matches that need to | |
451 # be displayed to the user to _history_substring_search_matches. | |
452 # Return whether there were any more results appended. | |
453 # | |
454 | |
455 # | |
456 # While we have more raw matches. Process them to see if there are any more | |
457 # matches that need to be displayed to the user. | |
458 # | |
459 while [[ $_history_substring_search_raw_match_index -lt $#_history_substring_search_raw_matches ]]; do | |
460 # | |
461 # Move on to the next raw entry and get its history index. | |
462 # | |
463 _history_substring_search_raw_match_index+=1 | |
464 local index=${_history_substring_search_raw_matches[$_history_substring_search_raw_match_index]} | |
465 | |
466 # | |
467 # If HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE is set to a non-empty value, | |
468 # then ensure that only unique matches are presented to the user. | |
469 # When HIST_IGNORE_ALL_DUPS is set, ZSH already ensures a unique history, | |
470 # so in this case we do not need to do anything. | |
471 # | |
472 if [[ ! -o HIST_IGNORE_ALL_DUPS && -n $HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE ]]; then | |
473 # | |
474 # Get the actual history entry at the new index, and check if we have | |
475 # already added it to _history_substring_search_matches. | |
476 # | |
477 local entry=${history[$index]} | |
478 | |
479 if [[ -z ${_history_substring_search_unique_filter[$entry]} ]]; then | |
480 # | |
481 # This is a new unique entry. Add it to the filter and append the | |
482 # index to _history_substring_search_matches. | |
483 # | |
484 _history_substring_search_unique_filter[$entry]=1 | |
485 _history_substring_search_matches+=($index) | |
486 | |
487 # | |
488 # Indicate that we did find a match. | |
489 # | |
490 return 0 | |
491 fi | |
492 | |
493 else | |
494 # | |
495 # Just append the new history index to the processed matches. | |
496 # | |
497 _history_substring_search_matches+=($index) | |
498 | |
499 # | |
500 # Indicate that we did find a match. | |
501 # | |
502 return 0 | |
503 fi | |
504 | |
505 done | |
506 | |
507 # | |
508 # We are beyond the end of the list of raw matches. Indicate that no | |
509 # more matches are available. | |
510 # | |
511 return 1 | |
512 } | |
513 | |
514 _history-substring-search-has-next() { | |
515 # | |
516 # Predicate function that returns whether any more older matches are | |
517 # available. | |
518 # | |
519 | |
520 if [[ $_history_substring_search_match_index -lt $#_history_substring_search_matches ]]; then | |
521 # | |
522 # We did not reach the end of the processed list, so we do have further | |
523 # matches. | |
524 # | |
525 return 0 | |
526 | |
527 else | |
528 # | |
529 # We are at the end of the processed list. Try to process further | |
530 # unprocessed matches. _history_substring_search_process_raw_matches | |
531 # returns whether any more matches were available, so just return | |
532 # that result. | |
533 # | |
534 _history_substring_search_process_raw_matches | |
535 return $? | |
536 fi | |
537 } | |
538 | |
539 _history-substring-search-has-prev() { | |
540 # | |
541 # Predicate function that returns whether any more younger matches are | |
542 # available. | |
543 # | |
544 | |
545 if [[ $_history_substring_search_match_index -gt 1 ]]; then | |
546 # | |
547 # We did not reach the beginning of the processed list, so we do have | |
548 # further matches. | |
549 # | |
550 return 0 | |
551 | |
552 else | |
553 # | |
554 # We are at the beginning of the processed list. We do not have any more | |
555 # matches. | |
556 # | |
557 return 1 | |
558 fi | |
559 } | |
560 | |
561 _history-substring-search-found() { | |
562 # | |
563 # A match is available. The index of the match is held in | |
564 # $_history_substring_search_match_index | |
565 # | |
566 # 1. Make $BUFFER equal to the matching history entry. | |
567 # | |
568 # 2. Use $HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND | |
569 # to highlight the current buffer. | |
570 # | |
571 BUFFER=$history[$_history_substring_search_matches[$_history_substring_search_match_index]] | |
572 _history_substring_search_query_highlight=$HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND | |
573 } | |
574 | |
575 _history-substring-search-not-found() { | |
576 # | |
577 # No more matches are available. | |
578 # | |
579 # 1. Make $BUFFER equal to $_history_substring_search_query so the user can | |
580 # revise it and search again. | |
581 # | |
582 # 2. Use $HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND | |
583 # to highlight the current buffer. | |
584 # | |
585 BUFFER=$_history_substring_search_query | |
586 _history_substring_search_query_highlight=$HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND | |
587 } | |
588 | |
589 _history-substring-search-up-search() { | |
590 _history_substring_search_refresh_display=1 | |
591 | |
592 # | |
593 # Select history entry during history-substring-down-search: | |
594 # | |
595 # The following variables have been initialized in | |
596 # _history-substring-search-up/down-search(): | |
597 # | |
598 # $_history_substring_search_matches is the current list of matches that | |
599 # need to be displayed to the user. | |
600 # $_history_substring_search_match_index is the index of the current match | |
601 # that is being displayed to the user. | |
602 # | |
603 # The range of values that $_history_substring_search_match_index can take | |
604 # is: [0, $#_history_substring_search_matches + 1]. A value of 0 | |
605 # indicates that we are beyond the beginning of | |
606 # $_history_substring_search_matches. A value of | |
607 # $#_history_substring_search_matches + 1 indicates that we are beyond | |
608 # the end of $_history_substring_search_matches and that we have also | |
609 # processed all entries in _history_substring_search_raw_matches. | |
610 # | |
611 # If $_history_substring_search_match_index equals | |
612 # $#_history_substring_search_matches and | |
613 # $_history_substring_search_raw_match_index is not greater than | |
614 # $#_history_substring_search_raw_matches, then we need to further process | |
615 # $_history_substring_search_raw_matches to see if there are any more | |
616 # entries that need to be displayed to the user. | |
617 # | |
618 # In _history-substring-search-up-search() the initial value of | |
619 # $_history_substring_search_match_index is 0. This value is set in | |
620 # _history-substring-search-begin(). _history-substring-search-up-search() | |
621 # will initially increment it to 1. | |
622 # | |
623 | |
624 if [[ $_history_substring_search_match_index -gt $#_history_substring_search_matches ]]; then | |
625 # | |
626 # We are beyond the end of $_history_substring_search_matches. This | |
627 # can only happen if we have also exhausted the unprocessed matches in | |
628 # _history_substring_search_raw_matches. | |
629 # | |
630 # 1. Update display to indicate search not found. | |
631 # | |
632 _history-substring-search-not-found | |
633 return | |
634 fi | |
635 | |
636 if _history-substring-search-has-next; then | |
637 # | |
638 # We do have older matches. | |
639 # | |
640 # 1. Move index to point to the next match. | |
641 # 2. Update display to indicate search found. | |
642 # | |
643 _history_substring_search_match_index+=1 | |
644 _history-substring-search-found | |
645 | |
646 else | |
647 # | |
648 # We do not have older matches. | |
649 # | |
650 # 1. Move the index beyond the end of | |
651 # _history_substring_search_matches. | |
652 # 2. Update display to indicate search not found. | |
653 # | |
654 _history_substring_search_match_index+=1 | |
655 _history-substring-search-not-found | |
656 fi | |
657 | |
658 # | |
659 # When HIST_FIND_NO_DUPS is set, meaning that only unique command lines from | |
660 # history should be matched, make sure the new and old results are different. | |
661 # | |
662 # However, if the HIST_IGNORE_ALL_DUPS shell option, or | |
663 # HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE is set, then we already have a | |
664 # unique history, so in this case we do not need to do anything. | |
665 # | |
666 if [[ -o HIST_IGNORE_ALL_DUPS || -n $HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE ]]; then | |
667 return | |
668 fi | |
669 | |
670 if [[ -o HIST_FIND_NO_DUPS && $BUFFER == $_history_substring_search_result ]]; then | |
671 # | |
672 # Repeat the current search so that a different (unique) match is found. | |
673 # | |
674 _history-substring-search-up-search | |
675 fi | |
676 } | |
677 | |
678 _history-substring-search-down-search() { | |
679 _history_substring_search_refresh_display=1 | |
680 | |
681 # | |
682 # Select history entry during history-substring-down-search: | |
683 # | |
684 # The following variables have been initialized in | |
685 # _history-substring-search-up/down-search(): | |
686 # | |
687 # $_history_substring_search_matches is the current list of matches that | |
688 # need to be displayed to the user. | |
689 # $_history_substring_search_match_index is the index of the current match | |
690 # that is being displayed to the user. | |
691 # | |
692 # The range of values that $_history_substring_search_match_index can take | |
693 # is: [0, $#_history_substring_search_matches + 1]. A value of 0 | |
694 # indicates that we are beyond the beginning of | |
695 # $_history_substring_search_matches. A value of | |
696 # $#_history_substring_search_matches + 1 indicates that we are beyond | |
697 # the end of $_history_substring_search_matches and that we have also | |
698 # processed all entries in _history_substring_search_raw_matches. | |
699 # | |
700 # In _history-substring-search-down-search() the initial value of | |
701 # $_history_substring_search_match_index is 1. This value is set in | |
702 # _history-substring-search-begin(). _history-substring-search-down-search() | |
703 # will initially decrement it to 0. | |
704 # | |
705 | |
706 if [[ $_history_substring_search_match_index -lt 1 ]]; then | |
707 # | |
708 # We are beyond the beginning of $_history_substring_search_matches. | |
709 # | |
710 # 1. Update display to indicate search not found. | |
711 # | |
712 _history-substring-search-not-found | |
713 return | |
714 fi | |
715 | |
716 if _history-substring-search-has-prev; then | |
717 # | |
718 # We do have younger matches. | |
719 # | |
720 # 1. Move index to point to the previous match. | |
721 # 2. Update display to indicate search found. | |
722 # | |
723 _history_substring_search_match_index+=-1 | |
724 _history-substring-search-found | |
725 | |
726 else | |
727 # | |
728 # We do not have younger matches. | |
729 # | |
730 # 1. Move the index beyond the beginning of | |
731 # _history_substring_search_matches. | |
732 # 2. Update display to indicate search not found. | |
733 # | |
734 _history_substring_search_match_index+=-1 | |
735 _history-substring-search-not-found | |
736 fi | |
737 | |
738 # | |
739 # When HIST_FIND_NO_DUPS is set, meaning that only unique command lines from | |
740 # history should be matched, make sure the new and old results are different. | |
741 # | |
742 # However, if the HIST_IGNORE_ALL_DUPS shell option, or | |
743 # HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE is set, then we already have a | |
744 # unique history, so in this case we do not need to do anything. | |
745 # | |
746 if [[ -o HIST_IGNORE_ALL_DUPS || -n $HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE ]]; then | |
747 return | |
748 fi | |
749 | |
750 if [[ -o HIST_FIND_NO_DUPS && $BUFFER == $_history_substring_search_result ]]; then | |
751 # | |
752 # Repeat the current search so that a different (unique) match is found. | |
753 # | |
754 _history-substring-search-down-search | |
755 fi | |
756 } | |
757 | |
758 # -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- | |
759 # vim: ft=zsh sw=2 ts=2 et |