aboutsummaryrefslogtreecommitdiffstats
path: root/crates/client/src/shell/atuin.zsh
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-07-09 21:43:23 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-07-09 21:43:23 +0200
commit3223d93cb3c77ab02aa0a35f2a8314e447cee9a4 (patch)
tree3971a1f37f5fe3cadb747c5229a0d54e868e45e3 /crates/client/src/shell/atuin.zsh
parentfix(client/sync): Pass through precise error on `SyncError::WrongKey` (diff)
downloadatuin-3223d93cb3c77ab02aa0a35f2a8314e447cee9a4.zip
chore: Separate daemon, client, server, and lib into crates
Diffstat (limited to 'crates/client/src/shell/atuin.zsh')
-rw-r--r--crates/client/src/shell/atuin.zsh167
1 files changed, 167 insertions, 0 deletions
diff --git a/crates/client/src/shell/atuin.zsh b/crates/client/src/shell/atuin.zsh
new file mode 100644
index 00000000..7e7fef27
--- /dev/null
+++ b/crates/client/src/shell/atuin.zsh
@@ -0,0 +1,167 @@
+# shellcheck disable=SC2034,SC2153,SC2086,SC2155
+
+# Above line is because shellcheck doesn't support zsh, per
+# https://github.com/koalaman/shellcheck/wiki/SC1071, and the ignore: param in
+# ludeeus/action-shellcheck only supports _directories_, not _files_. So
+# instead, we manually add any error the shellcheck step finds in the file to
+# the above line ...
+
+# Source this in your ~/.zshrc
+autoload -U add-zsh-hook
+
+zmodload zsh/datetime 2>/dev/null
+
+# If zsh-autosuggestions is installed, configure it to use Atuin's search. If
+# you'd like to override this, then add your config after the $(atuin init zsh)
+# in your .zshrc
+_zsh_autosuggest_strategy_atuin() {
+ # silence errors, since we don't want to spam the terminal prompt while typing.
+ suggestion=$(ATUIN_QUERY="$1" atuin search --cmd-only --limit 1 --search-mode prefix 2>/dev/null)
+}
+
+if [ -n "${ZSH_AUTOSUGGEST_STRATEGY:-}" ]; then
+ ZSH_AUTOSUGGEST_STRATEGY=("atuin" "${ZSH_AUTOSUGGEST_STRATEGY[@]}")
+else
+ ZSH_AUTOSUGGEST_STRATEGY=("atuin")
+fi
+
+if [[ -z "${ATUIN_SESSION:-}" || "${ATUIN_SHLVL:-}" != "$SHLVL" ]]; then
+ export ATUIN_SESSION=$(atuin uuid)
+ export ATUIN_SHLVL=$SHLVL
+fi
+ATUIN_HISTORY_ID=""
+
+__atuin_osc133_command_executed() {
+ [[ -n "${ATUIN_PTY_PROXY_ACTIVE:-}" ]] || return
+ [[ -n "${ATUIN_HISTORY_ID:-}" ]] || return
+
+ printf '\033]133;C\a'
+}
+
+__atuin_osc133_command_finished() {
+ [[ -n "${ATUIN_PTY_PROXY_ACTIVE:-}" ]] || return
+ [[ -n "${ATUIN_HISTORY_ID:-}" ]] || return
+
+ printf '\033]133;D;%s;history_id=%s;session_id=%s\a' "$1" "$ATUIN_HISTORY_ID" "${ATUIN_SESSION:-}"
+}
+
+__atuin_osc133_prompt_start=$'%{\033]133;A;cl=line\a%}'
+__atuin_osc133_prompt_end=$'%{\033]133;B\a%}'
+
+__atuin_osc133_wrap_prompt() {
+ local __atuin_prompt="${PROMPT-}"
+ local __atuin_rprompt="${RPROMPT-}"
+
+ __atuin_prompt="${__atuin_prompt//$__atuin_osc133_prompt_start/}"
+ __atuin_prompt="${__atuin_prompt//$__atuin_osc133_prompt_end/}"
+ __atuin_rprompt="${__atuin_rprompt//$__atuin_osc133_prompt_start/}"
+ __atuin_rprompt="${__atuin_rprompt//$__atuin_osc133_prompt_end/}"
+
+ if [[ -n "${ATUIN_PTY_PROXY_ACTIVE:-}" ]]; then
+ PROMPT="${__atuin_osc133_prompt_start}${__atuin_prompt}"
+ RPROMPT="${__atuin_rprompt}${__atuin_osc133_prompt_end}"
+ else
+ PROMPT="$__atuin_prompt"
+ RPROMPT="$__atuin_rprompt"
+ fi
+}
+
+_atuin_preexec() {
+ local id
+ id=$(atuin history start -- "$1" 2>/dev/null)
+ export ATUIN_HISTORY_ID="$id"
+ __atuin_osc133_command_executed
+ __atuin_preexec_time=${EPOCHREALTIME-}
+}
+
+_atuin_precmd() {
+ local EXIT="$?" __atuin_precmd_time=${EPOCHREALTIME-}
+
+ __atuin_osc133_wrap_prompt
+
+ [[ -z "${ATUIN_HISTORY_ID:-}" ]] && return
+
+ local duration=""
+ if [[ -n $__atuin_preexec_time && -n $__atuin_precmd_time ]]; then
+ printf -v duration %.0f $(((__atuin_precmd_time - __atuin_preexec_time) * 1000000000))
+ fi
+
+ __atuin_osc133_command_finished "$EXIT"
+ (ATUIN_LOG=error atuin history end --exit $EXIT ${duration:+--duration=$duration} -- $ATUIN_HISTORY_ID &) >/dev/null 2>&1
+ export ATUIN_HISTORY_ID=""
+}
+
+__atuin_search_cmd() {
+ local -a search_args=("$@")
+
+
+ ATUIN_SHELL=zsh ATUIN_LOG=error ATUIN_QUERY=$BUFFER atuin search "${search_args[@]}" -i 3>&1 1>&2 2>&3 3>&-
+}
+
+_atuin_search() {
+ emulate -L zsh
+ zle -I
+
+ # swap stderr and stdout, so that the tui stuff works
+ # TODO: not this
+ local output __atuin_status
+ # shellcheck disable=SC2048
+ output=$(__atuin_search_cmd $*)
+ __atuin_status=$?
+
+ zle reset-prompt
+ # re-enable bracketed paste
+ # shellcheck disable=SC2154
+ echo -n ${zle_bracketed_paste[1]} >/dev/tty
+
+ if (( __atuin_status != 0 )); then
+ [[ -n $output ]] && print -r -- "$output" >/dev/tty
+ return $__atuin_status
+ fi
+
+ if [[ -n $output ]]; then
+ RBUFFER=""
+ LBUFFER=$output
+
+ if [[ $LBUFFER == __atuin_accept__:* ]]
+ then
+ LBUFFER=${LBUFFER#__atuin_accept__:}
+ zle accept-line
+ fi
+ fi
+}
+_atuin_search_vicmd() {
+ _atuin_search --keymap-mode=vim-normal
+}
+_atuin_search_viins() {
+ _atuin_search --keymap-mode=vim-insert
+}
+
+_atuin_up_search() {
+ # Only trigger if the buffer is a single line
+ if [[ ! $BUFFER == *$'\n'* ]]; then
+ _atuin_search --shell-up-key-binding "$@"
+ else
+ zle up-line
+ fi
+}
+_atuin_up_search_vicmd() {
+ _atuin_up_search --keymap-mode=vim-normal
+}
+_atuin_up_search_viins() {
+ _atuin_up_search --keymap-mode=vim-insert
+}
+
+add-zsh-hook preexec _atuin_preexec
+add-zsh-hook precmd _atuin_precmd
+
+zle -N atuin-search _atuin_search
+zle -N atuin-search-vicmd _atuin_search_vicmd
+zle -N atuin-search-viins _atuin_search_viins
+zle -N atuin-up-search _atuin_up_search
+zle -N atuin-up-search-vicmd _atuin_up_search_vicmd
+zle -N atuin-up-search-viins _atuin_up_search_viins
+
+# These are compatibility widget names for "atuin <= 17.2.1" users.
+zle -N _atuin_search_widget _atuin_search
+zle -N _atuin_up_search_widget _atuin_up_search