feat: zsh+atuin prefix search

This commit is contained in:
Patrick Großmann 2023-02-18 21:56:34 +01:00
parent a027558058
commit 05873b37d6
Signed by: patrick
GPG key ID: 451F95EFB8BECD0F
2 changed files with 176 additions and 188 deletions

View file

@ -1,134 +1,50 @@
# Use emacs-like key bindings by default:
bindkey -e
# Autoloading
autoload colors && colors
autoload add-zsh-hook
autoload zmv
autoload zed
if autoload history-search-end; then
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
fi
function bind2maps() {
local i sequence widget
local -a maps
while [[ "$1" != "--" ]]; do
maps+=( "$1" )
shift
done
shift
if [[ "$1" == "-s" ]]; then
shift
sequence="$1"
else
sequence="${key[$1]}"
fi
widget="$2"
[[ -z "$sequence" ]] && return 1
for i in "${maps[@]}"; do
bindkey -M "$i" "$sequence" "$widget"
function str_to_hex() {
local str="$1"
for (( i=0; i<${#str}; i++ )); do
printf "%02x" "'${str:$i:1}"
done
}
typeset -A key
key=(
Home "${terminfo[khome]}"
End "${terminfo[kend]}"
Insert "${terminfo[kich1]}"
Delete "${terminfo[kdch1]}"
Up "${terminfo[kcuu1]}"
Down "${terminfo[kcud1]}"
Left "${terminfo[kcub1]}"
Right "${terminfo[kcuf1]}"
PageUp "${terminfo[kpp]}"
PageDown "${terminfo[knp]}"
BackTab "${terminfo[kcbt]}"
)
bind2maps emacs -- Home beginning-of-line
bind2maps emacs -- End end-of-line
bind2maps viins vicmd -- Home vi-beginning-of-line
bind2maps viins vicmd -- End vi-end-of-line
bind2maps emacs viins -- Insert overwrite-mode
bind2maps vicmd -- Insert vi-insert
bind2maps emacs -- Delete delete-char
bind2maps viins vicmd -- Delete vi-delete-char
bind2maps emacs -- Left backward-char
bind2maps viins vicmd -- Left vi-backward-char
bind2maps emacs -- Right forward-char
bind2maps viins vicmd -- Right vi-forward-char
bind2maps emacs viins -- -s '^xp' history-beginning-search-backward-end
bind2maps emacs viins -- -s '^xP' history-beginning-search-forward-end
bind2maps emacs viins -- PageUp history-beginning-search-backward-end
bind2maps emacs viins -- PageDown history-beginning-search-forward-end
bind2maps emacs viins -- -s ' ' magic-space
function atuin-prefix-search-any-end() {
# Use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on
# the command line.
# kitty: Shift-Left/Right
bind2maps emacs viins vicmd -- -s '\e[1;2C' forward-word
bind2maps emacs viins vicmd -- -s '\e[1;2D' backward-word
# kitty: Alt-Left/Right
bind2maps emacs viins vicmd -- -s '\e[1;3C' forward-word
bind2maps emacs viins vicmd -- -s '\e[1;3D' backward-word
# kitty: Ctrl-Del
bind2maps emacs viins vicmd -- -s '\e[3;5~' kill-line
# Key bindings
bind2maps emacs viins vicmd -- -s '^H' backward-kill-line
bind2maps emacs viins vicmd -- -s '^P' expand-or-complete-prefix
if [[ -v _atuin_search_prev_buffer ]] && [[ $_atuin_search_prev_buffer == $BUFFER ]]; then
_atuin_search_offset=$((_atuin_search_offset + $direction))
else
[[ "$direction" == -1 ]] && return 1
_atuin_search_offset=0
_atuin_search_prefix=$LBUFFER
_atuin_search_orig_buffer=$BUFFER
_atuin_search_orig_cursor=$CURSOR
fi
if [[ "$_atuin_search_offset" -ge 0 ]] && zle atuin-prefix-search; then
zle .end-of-line
_atuin_search_prev_buffer=$BUFFER
else
if [[ $_atuin_search_offset -lt 0 ]];then
_atuin_search_offset=0
BUFFER=$_atuin_search_orig_buffer
CURSOR=$_atuin_search_orig_cursor
else
_atuin_search_offset=$((_atuin_search_offset - 1))
fi
return 1
fi
zle reset-prompt
# Enable partial search using up and down keys for completion
bind2maps emacs viins vicmd -- -s '^[[A' history-beginning-search-backward-end
bind2maps emacs viins vicmd -- -s '^[[B' history-beginning-search-forward-end
bind2maps emacs viins vicmd -- -s '\eOA' history-beginning-search-backward-end
bind2maps emacs viins vicmd -- -s '\eOB' history-beginning-search-forward-end
}; zle -N atuin-prefix-search-any-end
# Completion
autoload -Uz compinit
compinit
function atuin-prefix-search-backward-end() {
direction=1 atuin-prefix-search-any-end
}; zle -N atuin-prefix-search-backward-end
# Make sure the completion system is initialised
(( ${+_comps} )) || return 1
function atuin-prefix-search-forward-end() {
direction=-1 atuin-prefix-search-any-end
}; zle -N atuin-prefix-search-forward-end
# Don't insert tabs when there is no completion (e.g. beginning of line)
zstyle ':completion:*' insert-tab false
# allow one error for every three characters typed in approximate completer
zstyle ':completion:*:approximate:' max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
# don't complete backup files as executables
zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
# start menu completion only if it could find no unambiguous initial string
zstyle ':completion:*:correct:*' insert-unambiguous true
zstyle ':completion:*:corrections' format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
zstyle ':completion:*:correct:*' original true
# activate color-completion
zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
# format on completion
zstyle ':completion:*:descriptions' format $'\e[0;31mcompleting \e[1m%d\e[0m'
# insert all expansions for expand completer
zstyle ':completion:*:expand:*' tag-order all-expansions
zstyle ':completion:*:history-words' list false
# activate menu
zstyle ':completion:*:history-words' menu yes
# ignore duplicate entries
zstyle ':completion:*:history-words' remove-all-dups yes
zstyle ':completion:*:history-words' stop yes
# match uppercase from lowercase
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
@ -136,14 +52,6 @@ zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
zstyle ':completion:*:matches' group 'yes'
zstyle ':completion:*' group-name ''
if [[ "$NOMENU" -eq 0 ]] ; then
# if there are more than 5 options allow selecting from a menu
zstyle ':completion:*' menu select=5
else
# don't use any menus at all
setopt no_auto_menu
fi
zstyle ':completion:*:messages' format '%d'
zstyle ':completion:*:options' auto-description '%d'
@ -153,24 +61,9 @@ zstyle ':completion:*:options' description 'yes'
# on processes completion complete all user processes
zstyle ':completion:*:processes' command 'ps -au$USER'
# offer indexes before parameters in subscripts
zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
# provide verbose completion information
zstyle ':completion:*' verbose true
# recent (as of Dec 2007) zsh versions are able to provide descriptions
# for commands (read: 1st word in the line) that it will list for the user
# to choose from. The following disables that, because it's not exactly fast.
zstyle ':completion:*:-command-:*:' verbose false
# set format for warnings
zstyle ':completion:*:warnings' format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
# define files to ignore for zcompile
zstyle ':completion:*:*:zcompile:*' ignored-patterns '(*~|*.zwc)'
zstyle ':completion:correct:' prompt 'correct to: %e'
# Ignore completion functions for commands you don't have:
zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
@ -182,57 +75,28 @@ zstyle ':completion:*:manuals' separate-sections true
zstyle ':completion:*:manuals.*' insert-sections true
zstyle ':completion:*:man:*' menu yes select
# Search path for sudo completion
zstyle ':completion:*:sudo:*' command-path \
/usr/local/sbin \
/usr/local/bin \
/usr/sbin \
/usr/bin \
/sbin \
/bin
# provide .. as a completion
zstyle ':completion:*' special-dirs ..
# run rehash on completion so new installed program are found automatically:
function _force_rehash() {
(( CURRENT == 1 )) && rehash
return 1
}
# No correction
zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
zstyle ':completion:*' completer _oldlist _expand _complete _files _ignored
# use generic completion system for programs not yet defined; (_gnu_generic works
# with commands that provide a --help option with "standard" gnu-like output.)
for compcom in cp deborphan df feh fetchipac gpasswd head hnb ipacsum mv pal stow uname ; do
[[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
done; unset compcom
# treat multiple slash as one
zstyle ':completion:*' squeeze-slashes true
# see upgrade function in this file
compdef _hosts upgrade
# disable sort when completing `git checkout`
zstyle ':completion:*:git-checkout:*' sort false
# set descriptions format to enable group support
zstyle ':completion:*:descriptions' format '[%d]'
# set list-colors to enable filename colorizing
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
# preview directory's content with ls when completing cd
zstyle ':fzf-tab:complete:cd:*' fzf-preview 'ls -lhF --group-directories-first --show-control-chars --quoting-style=escape --color=auto $realpath';
# preview windown min size
zstyle ':fzf-tab:complete:cd:*' popup_pad 20 0
# History settings
unset HISTFILE=~/.zsh_history
HISTSIZE=1000000
SAVEHIST=1005000
# Append history when zsh exits
setopt append_history
# Also save timestamp and duration
setopt extended_history
# Ignore commands beginning with a space
setopt hist_ignore_space
# Remove repeated duplicates
setopt hist_ignore_dups
# Remove trailing whitespace from history
setopt hist_reduce_blanks
# Save history after each command
setopt inc_append_history
# If history is full, delete oldest duplicate commands first
setopt hist_expire_dups_first
# When a history line is selected from expansion, don't execute but fill line buffer
setopt hist_verify
unset HISTFILE
# Emit an error when a glob has no match
setopt nomatch
@ -263,8 +127,6 @@ setopt nobeep
# Don't try to correct inputs
setopt nocorrect
# Allow in-word completion
setopt completeinword
# Don't autocorrect commands
setopt no_correct_all
# Allow completion from within a word/phrase
@ -283,6 +145,118 @@ function zshaddhistory() {
[[ ! $1 =~ "$HISTORY_IGNORE_REGEX" ]]
}
# Delete all keybinds and use emacs-like key bindings by default:
bindkey -d
bindkey -e
function nop() {
true
}; zle -N nop
function bindkeys() {
[[ $# -eq 2 ]] || return
local keys="$1";
for key in ${(P)keys}; do
bindkey "$key" "$2"
done
}
function setup_keybinds() {
local keys_Home=( "${terminfo[khome]}" "\eOH" "\e[H" )
local keys_End=( "${terminfo[kend]}" "\eOF" "\e[F" )
local keys_Insert=( "${terminfo[kich1]}" )
local keys_Tab=( "${terminfo[ht]}" )
local keys_ShiftTab=( "${terminfo[kcbt]}" )
local keys_Backspace=( "${terminfo[kbs]}" )
local keys_CtrlBackspace=( "${terminfo[cub1]}" )
local keys_Delete=( "${terminfo[kdch1]}" )
local keys_ShiftDelete=( "${terminfo[kDC]}" )
local keys_CtrlDelete=( '\e[3;5~' )
local keys_AltDelete=( '\e[3;3~' )
local keys_Up=( "${terminfo[kcuu1]}" "\eOA" "\e[A")
local keys_ShiftUp=( "${terminfo[kri]}" )
local keys_CtrlUp=( '\e[1;5A' )
local keys_AltUp=( '\e[1;3A' )
local keys_Down=( "${terminfo[kcud1]}" "\eOB" "\e[B")
local keys_ShiftDown=( "${terminfo[kind]}" )
local keys_CtrlDown=( '\e[1;5B' )
local keys_AltDown=( '\e[1;3B' )
local keys_Right=( "${terminfo[kcuf1]}" )
local keys_ShiftRight=( "${terminfo[kRIT]}" )
local keys_CtrlRight=( '\e[1;5C' )
local keys_AltRight=( '\e[1;3C' )
local keys_Left=( "${terminfo[kcub1]}" )
local keys_ShiftLeft=( "${terminfo[kLFT]}" )
local keys_CtrlLeft=( '\e[1;5D' )
local keys_AltLeft=( '\e[1;3D' )
local keys_PageUp=( "${terminfo[kpp]}" )
local keys_ShiftPageUp=( "${terminfo[kPRV]}" )
local keys_PageDown=( "${terminfo[knp]}" )
local keys_ShiftPageDown=( "${terminfo[kNXT]}" )
bindkeys keys_Home beginning-of-line
bindkeys keys_End end-of-line
bindkeys keys_Insert nop
bindkeys keys_Tab fzf-tab-complete
bindkeys keys_ShiftTab nop
bindkeys keys_ShiftBackspace backward-kill-word
bindkeys keys_CtrlBackspace backward-kill-line
bindkeys keys_Delete delete-char
bindkeys keys_ShiftDelete delete-word
bindkeys keys_CtrlDelete kill-line
bindkeys keys_AltDelete delete-word
bindkeys keys_Up atuin-prefix-search-backward-end
bindkeys keys_ShiftUp up-line
bindkeys keys_CtrlUp nop
bindkeys keys_AltUp nop
bindkeys keys_Down atuin-prefix-search-forward-end
bindkeys keys_ShiftDown down-line
bindkeys keys_CtrlDown nop
bindkeys keys_AltDown nop
bindkeys keys_Right forward-char
bindkeys keys_ShiftRight forward-word
bindkeys keys_CtrlRight nop
bindkeys keys_AltRight nop
bindkeys keys_Left backward-char
bindkeys keys_ShiftLeft backward-word
bindkeys keys_CtrlLeft nop
bindkeys keys_AltLeft nop
bindkeys keys_PageUp nop
bindkeys keys_ShiftPageUp nop
bindkeys keys_PageDown nop
bindkeys keys_ShiftPageDown nop
# atuin
bindkey '^r' _atuin_search_widget
# fzf file and directory related expansions and functions
bindkey '\ef' fzf-select-file-or-dir
bindkey '\eF' fzf-select-file-or-dir-hidden
bindkey '\ed' fzf-select-dir
bindkey '\eD' fzf-select-dir-hidden
bindkey '\ec' fzf-cd
}
setup_keybinds
unfunction bindkeys
unfunction setup_keybinds
# Set umask
umask 077

View file

@ -1,6 +1,7 @@
{
config,
pkgs,
lib,
...
}: {
imports = [
@ -12,7 +13,20 @@
};
programs.zsh = {
enable = true;
#initExtra = builtins.readFile ../../../data/zsh/zshrc;
dotDir = ".config/zsh";
initExtra = lib.mkAfter (''
function atuin-prefix-search() {
if out=$(${pkgs.sqlite}/bin/sqlite3 -readonly ~/.local/share/atuin/history.db \
'SELECT command FROM history WHERE command LIKE cast('"x'$(str_to_hex "$_atuin_search_prefix")'"' as text) || "%" ORDER BY timestamp DESC LIMIT 1 OFFSET '"$_atuin_search_offset"); then
[[ -z "$out" ]] && return 1
BUFFER=$out
else
return 1
fi
}; zle -N atuin-prefix-search
''
+ (builtins.readFile ../../../data/zsh/zshrc));
plugins = [
{
name = "fzf-tab";