Advertisement
unai-ndz

Untitled

May 7th, 2022
1,751
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 11.74 KB | None | 0 0
  1. ## .zshrc
  2. source "$ZPLUGINS/zsh-autosuggestions/zsh-autosuggestions.zsh"
  3.  
  4. # Atuin (history replacement)
  5. # Keeps the history in a sqlite db (Needs to be after zsh-autosuggestions)
  6. source "$ZDOTDIR/plugins/atuin.zsh"
  7.  
  8. # bind UP and DOWN arrow keys to history search
  9. bindkey "$terminfo[kcuu1]" atuin_fzf_inline_up
  10. bindkey "$terminfo[kcud1]" atuin_fzf_inline_down
  11. bindkey '^[[A' atuin_fzf_inline_up
  12. bindkey '^[[B' atuin_fzf_inline_down
  13.  
  14. bindkey '^r' _atuin_search_widget  # Default
  15. bindkey '^[r' _atuin_fzf  # Using fzf interactively
  16.  
  17. ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=#555'
  18. ZSH_AUTOSUGGEST_STRATEGY=('atuin')
  19. ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE='20'
  20. ZSH_AUTOSUGGEST_USE_ASYNC='true'
  21. ZSH_AUTOSUGGEST_MANUAL_REBIND='true'
  22.  
  23.  
  24. ## plugins/atuin.zsh
  25. # Enable atuin history plugin
  26. # Import atuin history into zsh array
  27. # Support multiline commands
  28. # Support interactive atuin, interactive fzf,
  29. #   inline history navigation with or without fzf filtering by query
  30. # Support zsh-autosuggestions using atuin history
  31. # Support highlighting of query terms
  32.  
  33. ## Source the atuin zsh plugin
  34. # Equivalent to `eval "$(atuin init zsh)"` but a little bit faster (~2ms)
  35. # Yeah, probably not worth it but it's already written so ¯\_(ツ)_/¯
  36. atuin_version="# $(atuin --version)"
  37. current_atuin_version="$(head -1 $ZCACHE/_atuin_init_zsh.zsh)"
  38. if [[ "$atuin_version" != "$current_atuin_version" ]]; then
  39.     # Check for new atuin version and update the cache
  40.     echo "$atuin_version" > "$ZCACHE/_atuin_init_zsh.zsh"
  41.     atuin init zsh >> "$ZCACHE/_atuin_init_zsh.zsh"
  42. fi
  43. export ATUIN_NOBIND='true'
  44. source "$ZCACHE/_atuin_init_zsh.zsh"
  45.  
  46. ## Import atuin history into zsh array
  47. declare -U _history_atuin # -U indicates unique array so duplicates are not inserted
  48. # Get the last 1500 (More than the 'max_lenght' below, to account for duplicates) commands from the atuin history database
  49. # Separate each command with ';;\n;;' instead of '\n', this allows support for multiline commands.
  50. #  Split them using the same separator and insert them into the array: (@pws:;;\n;;:).
  51. # Sort them by timestamp in descending order (Last executed command first), this helps with:
  52. #   Limiting the number of sqlite rows (otherwise it woulds trim the latest rows)
  53. #   As latest commands are inserted first they have preference to earlier ones when checking for duplicates.
  54. #   Bonus points for simplifying 'Limit history array size' below.
  55. _history_atuin=("${(@pws:;;\n;;:)"$(sqlite3 --newline $';;\n;;' ~/.local/share/atuin/history.db 'SELECT command FROM history ORDER BY timestamp DESC LIMIT 2000')"}")
  56.  
  57. # Redeclare as normal array, this allows us to store new duplicate commands for keeping a better session history.
  58. # Ofc those duplicates get removed when opening a new terminal.
  59. declare -a history_atuin
  60.  
  61. ## Limit history array size to 1000
  62. # _history_atuin:0:1000, Get slice from 0 to 1000, effectively trimming it's size
  63. # (@Oa), Reverse the order so last executed commands are first
  64. history_atuin=(${(@Oa)_history_atuin:0:1000})
  65. unset _history_atuin
  66.  
  67. if [[ -z $history_atuin ]]; then
  68.     echo 'Error: Atuin history array is empty'
  69.     echo 'Atuin may not be installed, history not imported, wrong path for the database or something else.'
  70.     exit
  71. fi
  72.  
  73. ## Keep history array updated with new executed commands
  74. _atuin_update_history_preexec(){
  75.     if [[ $history_atuin[-1] != "$1" ]]; then
  76.         # Store the new command in history if it's different than the last one
  77.         # This basically avoids adding duplicate commands one right after the other
  78.         history_atuin+=("$1") # Store the command in our zsh array (cache)
  79.     fi
  80. }
  81. add-zsh-hook preexec _atuin_update_history_preexec
  82.  
  83. ## Set selected command as new buffer and move the cursor to the end
  84. __atuin_set_buffer() {
  85.     BUFFER="$1"
  86.     CURSOR=${#BUFFER}
  87. }
  88.  
  89. ## Invoque fzf with atuin history
  90. _atuin_fzf() {
  91.     # Print history splitting commands with nulls `print -rNC1 -- $var`
  92.     # Get the history inverted `${(@Oa)history_atuin}` for the print command.
  93.     # Get and parse history using nulls as separators
  94.     # Nulls are used as separators instead of newlines to keep support for multiline commands
  95.     output=$(print -rNC1 -- "${(@Oa)history_atuin}" | fzf --read0)
  96.     __atuin_set_buffer "$output"
  97. }
  98. zle -N _atuin_fzf
  99.  
  100. typeset -g _atuin_fzf_inline_query
  101. typeset -g _atuin_fzf_inline_query_matches
  102. typeset -g _atuin_fzf_inline_result
  103. typeset -i _atuin_fzf_inline_result_index=0
  104.  
  105. ## Emulate history-substring-search but with atuin results
  106. __atuin_fzf_inline() {
  107.     typeset -g suggestion=''
  108.     local add_or_substract="$1"
  109.  
  110.     # Move the cursor instead of changing history command
  111.     #  but only if he current command is multiline, and we are not in the first or last line
  112.     #   (depending if we are moving up or downon the history)
  113.     if (( $BUFFERLINES > 1 )); then
  114.         local lines_before_end
  115.         if [[ "$add_or_substract" == '+' ]]; then
  116.             lines_before_end=(${(f)LBUFFER})
  117.         else
  118.             lines_before_end=(${(f)RBUFFER})
  119.         fi
  120.         if (( ${#lines_before_end} > 1 )); then
  121.             if [[ "$add_or_substract" == '+' ]]; then
  122.                 zle up-line    # zsh builtin, move cursor one line up
  123.             else
  124.                 zle down-line  # zsh builtin, move cursor one line down
  125.             fi
  126.             return
  127.         fi
  128.     fi
  129.  
  130.     # Add or substract one from the index, depending if we are going up or down on the history
  131.     _atuin_fzf_inline_result_index=$(( _atuin_fzf_inline_result_index $add_or_substract 1 ))
  132.  
  133.     if (( _atuin_fzf_inline_result_index < 0 )); then
  134.         # Drop the current query, clear the buffer.
  135.         _atuin_fzf_inline_result_index=0
  136.         unset _atuin_fzf_inline_query_matches
  137.         __atuin_set_buffer ''
  138.         return
  139.     elif [[ "$BUFFER" == "$_atuin_fzf_inline_result" ]]; then
  140.         if (( _atuin_fzf_inline_result_index == 0 )); then
  141.             __atuin_set_buffer "$_atuin_fzf_inline_query"
  142.             return
  143.         fi
  144.     else
  145.         _atuin_fzf_inline_result_index=1
  146.         unset _atuin_fzf_inline_query_matches
  147.         _atuin_fzf_inline_query="$BUFFER"
  148.     fi
  149.  
  150.     ## Get the history array we are gonna use
  151.     local query="$_atuin_fzf_inline_query"
  152.     local index="$_atuin_fzf_inline_result_index"
  153.     if [[ -n "$query" ]]; then # Filter commands by query using fzf
  154.         # Create array of matches, filtered by fzf if not already created
  155.         #   Print history splitting commands with nulls `print -rNC1 -- $var`
  156.         #   Filter results with fzf, using nulls as separators for both input and output
  157.         #   Create array using nulls as separators `(@0)`
  158.         # Nulls are used as separators instead of newlines to keep support for multiline commands
  159.         if [[ -z "$_atuin_fzf_inline_query_matches" ]]; then
  160.             _atuin_fzf_inline_query_matches=("${(@0)"$(print -rNC1 -- "$history_atuin[@]" | fzf --read0 --print0 --exact --no-sort --filter="$query")"}")
  161.             shift -p _atuin_fzf_inline_query_matches # Pop the last item, it's an empty string
  162.         fi
  163.         matches='_atuin_fzf_inline_query_matches'
  164.     else # No need to filter with fzf if there is no query, use the entire history array
  165.         matches='history_atuin'
  166.     fi
  167.  
  168.     max_index=${#${(P)matches}} # Get size of array named $matches
  169.     if (( index > max_index )); then
  170.         _atuin_fzf_inline_result_index="$max_index"
  171.         # We already reached the end of the history, do nothing
  172.         return
  173.     fi
  174.  
  175.     ## Get next command from history
  176.     # From array named $matches get element -$index, negative number to start from the last element
  177.     _atuin_fzf_inline_result=${${(P)matches}[-$index]}
  178.  
  179.     ## Set command as current edit buffer
  180.     __atuin_set_buffer "$_atuin_fzf_inline_result"
  181.  
  182.     # Find all matches of $query in $BUFFER and highlight them
  183.     if [[ -n "$query" ]]; then
  184.         _zsh_highlight # This needs to be before region_highlight+= or the added highlight will be ignored, does _zsh_highlight clear the region_highlight array?.
  185.         local last_match_end=0
  186.         while true; do
  187.             # (i) Search $query inside $BUFFER and return the index of the first matching character
  188.             # (e) Match using $query as a literal string (i.e. query=* will match the literal character `*`)
  189.             # (b:last_match_end:) Start matching from index=$last_match_end
  190.             local match_start="${BUFFER[(ieb:last_match_end:)${query}]}"
  191.             if (( $match_start <= ${#BUFFER} )); then
  192.                 local match_end=$(( $match_start + ${#query} ))
  193.                 last_match_end=$match_end
  194.                 # Highlight from index $match_start to $match_end, they need an offset of 1
  195.                 region_highlight+=("$(($match_start - 1)) $(($match_end - 1)) underline") # bold
  196.             else
  197.                 # The query didn't match anything
  198.                 break
  199.             fi
  200.         done
  201.     fi
  202. }
  203.  
  204. atuin_fzf_inline_up() {
  205.     __atuin_fzf_inline '+'
  206. }
  207. atuin_fzf_inline_down() {
  208.     __atuin_fzf_inline '-'
  209. }
  210.  
  211. zle -N atuin_fzf_inline_up
  212. zle -N atuin_fzf_inline_down
  213.  
  214. ## Add compatibility with zsh-autosuggest
  215.  
  216. # Tell  autosuggest to clear suggestions when atuin changes the edit buffer
  217. ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=('atuin_fzf_inline_up')
  218. ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=('atuin_fzf_inline_down')
  219.  
  220. _zsh_autosuggest_strategy_atuin() {
  221.     # Straight copy from: https://github.com/zsh-users/zsh-autosuggestions/blob/master/src/strategies/history.zsh
  222.     # Only changes are the history source and inverting the matching order.
  223.     #
  224.     # Copyright (c) 2013 Thiago de Arruda
  225.     # Copyright (c) 2016-2021 Eric Freese
  226.  
  227.     # Permission is hereby granted, free of charge, to any person
  228.     # obtaining a copy of this software and associated documentation
  229.     # files (the "Software"), to deal in the Software without
  230.     # restriction, including without limitation the rights to use,
  231.     # copy, modify, merge, publish, distribute, sublicense, and/or sell
  232.     # copies of the Software, and to permit persons to whom the
  233.     # Software is furnished to do so, subject to the following
  234.     # conditions:
  235.  
  236.     # The above copyright notice and this permission notice shall be
  237.     # included in all copies or substantial portions of the Software.
  238.  
  239.     # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  240.     # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  241.     # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  242.     # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  243.     # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  244.     # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  245.     # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  246.     # OTHER DEALINGS IN THE SOFTWARE.
  247.     #
  248.  
  249.     # Reset options to defaults and enable LOCAL_OPTIONS
  250.     emulate -L zsh
  251.  
  252.     # Enable globbing flags so that we can use (#m) and (x~y) glob operator
  253.     setopt EXTENDED_GLOB
  254.  
  255.     # Escape backslashes and all of the glob operators so we can use
  256.     # this string as a pattern to search the $history associative array.
  257.     # - (#m) globbing flag enables setting references for match data
  258.     # TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
  259.     local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
  260.  
  261.     # Get the history items that match the prefix, excluding those that match
  262.     # the ignore pattern
  263.     local pattern="$prefix*"
  264.     if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then
  265.         pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)"
  266.     fi
  267.  
  268.     # Give the first history item matching the pattern as the suggestion
  269.     # - (r) subscript flag makes the pattern match on values
  270.     # - (R) same as r, but gives the last match
  271.     typeset -g suggestion="${history_atuin[(R)$pattern]}"
  272. }
  273.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement