1
1
mirror of https://github.com/ellie/atuin.git synced 2024-09-11 13:15:23 +03:00

Add atuin incremental search widget

Add a bash/zsh like reverse history lookup widget that uses `atuin` as
the backend. This widget tries to stay true to default behaviour of
`ctrl-r` found in bash and zsh.

To activate the plugin in zsh, source the file, `source
atuin.isearch.zsh`. Then use `ctrl-r` to activate reverse search. Use
`ctrl-r` again while in search mode to cycle to previous hits, use
`ctrl-f` to cycle filter mode (prefix, fuzzy, full-text, skim). Press
`enter` to select the search hit or `ctrl-c` or `esc` to close.
This commit is contained in:
Tom Cammann 2023-03-28 22:22:04 +01:00
parent 0d16a113c5
commit cf970c6dfd
2 changed files with 168 additions and 0 deletions

View File

@ -16,3 +16,6 @@ jobs:
uses: ludeeus/action-shellcheck@master
env:
SHELLCHECK_OPTS: "-e SC2148"
ignore:
# can't check zsh with shellcheck
- atuin.plugin.zsh

165
atuin.isearch.zsh Normal file
View File

@ -0,0 +1,165 @@
#!/usr/bin/env zsh
typeset -g ATUIN_ISEARCH_N
typeset -g ATUIN_ISEARCH_MATCH
typeset -g ATUIN_ISEARCH_DURATION
typeset -g ATUIN_ISEARCH_DIR
typeset -g ATUIN_ISEARCH_LOCATION
typeset -g ATUIN_ISEARCH_TIME
typeset -g ATUIN_ISEARCH_MATCH_END
typeset -g ATUIN_ISEARCH_LAST_QUERY=""
typeset -g ATUIN_ISEARCH_LAST_N=""
typeset -g ATUIN_ISEARCH_MSG=""
typeset -g ATUIN_ISEARCH_MODES=("prefix" "fuzzy" "full-text" "skim")
typeset -g ATUIN_ISEARCH_MODE_INDEX=1
typeset -g ATUIN_ISEARCH_MODE="prefix"
typeset -g ATUIN_ISEARCH_DISPLAY_FMT='$ATUIN_ISEARCH_MSG\\nDuration: $ATUIN_ISEARCH_DURATION\\n$ATUIN_ISEARCH_TIME\\n$ATUIN_ISEARCH_LOCATION: $ATUIN_ISEARCH_DIR'
_atuin_isearch_atuin_search() {
atuin search --limit 1 --offset "${ATUIN_ISEARCH_N}" --search-mode "$ATUIN_ISEARCH_MODE" \
-f "{duration}:{directory}:{user}@{host}:{time}:{command}" -- "${(b)BUFFER}"
}
_atuin_isearch_query () {
ATUIN_ISEARCH_MSG=""
if [[ -z $BUFFER ]]; then
ATUIN_ISEARCH_MATCH=""
return
fi
local new_query="$BUFFER"
if [[ "$new_query" != "$ATUIN_ISEARCH_LAST_QUERY" ]]; then
ATUIN_ISEARCH_N=0
ATUIN_ISEARCH_LAST_N=0
fi
local result
result=$( _atuin_isearch_atuin_search)
rc=$?
if [[ "$ATUIN_ISEARCH_N" > "$ATUIN_ISEARCH_LAST_N" ]]; then
if [[ $rc -ne 0 ]]; then
ATUIN_ISEARCH_N=$(( ATUIN_ISEARCH_N - 1 ))
ATUIN_ISEARCH_MSG="\nNo more results"
return
fi
fi
if [[ $rc -ne 0 ]]; then
ATUIN_ISEARCH_MSG="\nNo results"
ATUIN_ISEARCH_MATCH=""
return
fi
ATUIN_ISEARCH_LAST_QUERY=$new_query
ATUIN_ISEARCH_LAST_N=$ATUIN_ISEARCH_N
local parts=(${(s/:/)result})
ATUIN_ISEARCH_DURATION=${parts[1]}
ATUIN_ISEARCH_DIR=${parts[2]}
ATUIN_ISEARCH_LOCATION=${parts[3]}
ATUIN_ISEARCH_TIME=${parts[4]}:${parts[5]}:${parts[6]}
ATUIN_ISEARCH_MATCH=${(j.:.)parts:6}
}
_atuin_isearch_display () {
local top_bit="atuin-isearch ($ATUIN_ISEARCH_MODE) ${ATUIN_ISEARCH_N}: "
if [[ -z ${ATUIN_ISEARCH_MATCH} ]]; then
# echo to get the newlines
POSTDISPLAY=$(echo $ATUIN_ISEARCH_MSG)
PREDISPLAY="
$top_bit"
else
local qbuffer="${(b)BUFFER}"
qbuffer="${${qbuffer//\\\*/*}//\\\?/?}"
local match_len="${#ATUIN_ISEARCH_MATCH}"
local prefix="${ATUIN_ISEARCH_MATCH%%${~qbuffer}*}"
local prefix_len="${#prefix}"
local suffix_len="${#${ATUIN_ISEARCH_MATCH:${prefix_len}}##${~qbuffer}}"
local match_end=$(( $match_len - $suffix_len ))
ATUIN_ISEARCH_MATCH_END=${match_end}
region_highlight=("P${prefix_len} ${match_end} underline")
# TODO is there a better way to do this?
POSTDISPLAY=$(eval "echo $ATUIN_ISEARCH_DISPLAY_FMT")
PREDISPLAY="${ATUIN_ISEARCH_MATCH}
$top_bit"
fi
}
_atuin-isearch-mode-rotate() {
# increment and wrap
ATUIN_ISEARCH_MODE_INDEX=$(( ($ATUIN_ISEARCH_MODE_INDEX % ${#ATUIN_ISEARCH_MODES[@]}) + 1))
ATUIN_ISEARCH_MODE=${ATUIN_ISEARCH_MODES[$ATUIN_ISEARCH_MODE_INDEX]}
}
_atuin-isearch-up () {
ATUIN_ISEARCH_N=$(( $ATUIN_ISEARCH_N + 1 ))
}
_atuin-isearch-down () {
if (( $ATUIN_ISEARCH_N > 1 )); then
ATUIN_ISEARCH_N=$(( $ATUIN_ISEARCH_N - 1 ))
fi
}
zle -N self-insert-atuin-isearch
_atuin_line_redraw () {
_atuin_isearch_query
_atuin_isearch_display
}
_atuin_end_of_line () {
# find first new line in $BUFFER and set $CURSOR to the position before it
local new_line_pos=${${BUFFER%%$'\n'*}##$'\n'}
CURSOR=${#new_line_pos}
}
_atuin-isearch () {
local old_buffer=${BUFFER}
local old_cursor=${CURSOR}
ATUIN_ISEARCH_N=0
zle -K atuin-isearch
zle -N zle-line-pre-redraw _atuin_line_redraw
_atuin_isearch_query
_atuin_isearch_display
zle recursive-edit
local stat=$?
zle -D zle-line-pre-redraw
zle -K main
PREDISPLAY=""
POSTDISPLAY=""
region_highlight=()
if (( stat )); then
BUFFER=${old_buffer}
CURSOR=${old_cursor}
else
if [[ -n ${ATUIN_ISEARCH_MATCH} ]]; then
BUFFER="${ATUIN_ISEARCH_MATCH}"
CURSOR="${ATUIN_ISEARCH_MATCH_END}"
fi
fi
return 0
}
zle -N _atuin-isearch-up
zle -N _atuin-isearch-down
zle -N _atuin-isearch
zle -N _atuin-isearch-mode-rotate
zle -N _atuin_end_of_line
bindkey -N atuin-isearch main
bindkey -M atuin-isearch '' _atuin-isearch-mode-rotate
bindkey -M atuin-isearch '' _atuin-isearch-up
bindkey -M atuin-isearch '' _atuin-isearch-down
bindkey -M atuin-isearch '' send-break
bindkey -M atuin-isearch '' _atuin_end_of_line
bindkey '^r' _atuin-isearch