Created
June 9, 2026 22:39
-
-
Save Talor-A/2c1a652fa1b2933a7b786e9f39438087 to your computer and use it in GitHub Desktop.
talor.zsh-theme — oh-my-zsh custom theme with async prompts, jj/git integration, and vi-mode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/zsh | |
| setopt prompt_subst | |
| export VIRTUAL_ENV_DISABLE_PROMPT=1 | |
| autoload -Uz colors | |
| colors | |
| # variables | |
| INSERT_COLOR="%{$reset_color%}" | |
| NORMAL_COLOR="%{%F{39}%}" | |
| # https://github.com/clvv/oh-my-zsh/blob/master/modules/git/functions/git-info | |
| autoload -Uz vcs_info | |
| zstyle ':vcs_info:*' enable git | |
| zstyle ':vcs_info:*' check-for-changes true | |
| zstyle ':vcs_info:*' stagedstr "%F{003}" | |
| zstyle ':vcs_info:*' unstagedstr "%F{red}" | |
| zstyle ':vcs_info:*' use-simple true | |
| zstyle ':vcs_info:git+set-message:*' hooks git-untracked | |
| zstyle ':vcs_info:git*:*' formats '%u%c%m%b' # default ' (%s)-[%b]%c%u-' | |
| zstyle ':vcs_info:git*:*' actionformats '%u%c%m%b/%a' # default ' (%s)-[%b|%a]%c%u-' | |
| function _git_pushable() { | |
| setopt localoptions noshwordsplit | |
| if git rev-list --count "origin/$(git rev-parse --abbrev-ref HEAD 2>/dev/null).." > /dev/null 2>&1; then | |
| # git rev-list --left-right --count HEAD...@'{u}' | |
| git rev-list --count "origin/$(git rev-parse --abbrev-ref HEAD 2>/dev/null).." | sed 's/[1-9][0-9]*/ ↯/;s/[0-9]//' | |
| fi | |
| } | |
| _vcs_info_wrapper() { | |
| vcs_info | |
| if jj root --quiet > /dev/null 2>&1; then | |
| local jj_out | |
| jj_out=$(jj log -r @ --no-graph -T 'change_id.shortest(3).prefix() ++ "|" ++ change_id.shortest(3).rest() ++ "|" ++ if(empty, "empty", if(description.first_line() != "", "described", "nodesc")) ++ "|" ++ bookmarks.join(",") ++ "|" ++ parents.map(|c| c.bookmarks().join(",")).join(",")' 2>/dev/null) || return 1 | |
| local parts=("${(@s:|:)jj_out}") | |
| local prefix=${parts[1]} | |
| local rest=${parts[2]} | |
| local state=${parts[3]} | |
| # bookmarks on @ itself, falling back to bookmarks on its parents | |
| local bookmarks=${parts[4]:-${parts[5]}} | |
| while [[ "$bookmarks" == *,,* ]]; do bookmarks=${bookmarks//,,/,}; done | |
| bookmarks=${bookmarks#,} | |
| bookmarks=${bookmarks%,} | |
| [[ -n "$bookmarks" ]] && bookmarks=" %F{005}${bookmarks}" | |
| if [[ "$state" == "empty" ]]; then | |
| echo "%F{002}${prefix}%F{240}${rest}${bookmarks}%f" | |
| elif [[ "$state" == "nodesc" ]]; then | |
| echo "%F{003}${prefix}%F{240}${rest}${bookmarks}%f" | |
| else | |
| echo "%F{white}${prefix}%F{240}${rest}${bookmarks}%f" | |
| fi | |
| else | |
| echo "%F{green}${vcs_info_msg_0_//heads\//}%f" | |
| fi | |
| } | |
| function +vi-git-untracked() { | |
| emulate -L zsh | |
| if [[ -n $(git ls-files --exclude-standard --others 2> /dev/null) ]]; then | |
| hook_com[unstaged]+="%F{blue}" | |
| fi | |
| } | |
| function _current_kubernetes_namespace() { | |
| if [ -d helm ] || [ -d charts ] || [ -f deployment.yaml ] || [ -f .namespace ];then | |
| cluster="$(kubectl config view --minify --output 'jsonpath={..current-context}' 2>/dev/null)" | |
| namespace="$(kubectl config view --minify --output 'jsonpath={..namespace}' 2>/dev/null)" | |
| [ -z "$namespace" ] && [ -n "$cluster" ] && namespace="default" | |
| [ -n "$cluster" ] && printf "%s:%s" "$cluster" "$namespace" || printf "no-cluster" | |
| fi | |
| } | |
| function _git_repo_base(){ | |
| ROOT="$(git remote get-url origin 2>/dev/null | sed 's/\.git$//')" | |
| if [ -n "$ROOT" ];then | |
| echo "$(basename "$ROOT")" | |
| fi | |
| } | |
| _tmux_indicator='›' | |
| if [[ -n "$DISTROBOX_ENTER_PATH" ]] ; then | |
| local _tmux_indicator="@" | |
| elif [[ -n "$IN_NIX_SHELL" ]] ; then | |
| local _tmux_indicator="#" | |
| elif [[ -n "$TMUX" ]] ; then | |
| local _tmux_indicator="=" | |
| fi | |
| local _return_status="%(?..%F{red})" | |
| function virtualenv_info { | |
| [[ -n "$VIRTUAL_ENV" ]] && echo " py:${VIRTUAL_ENV:t}" | |
| } | |
| function _last_two_folders { | |
| DIR=$(pwd) | |
| if [ "$DIR" = "$HOME" ];then | |
| echo "~" | |
| else | |
| DIR=$(pwd | sed "s|$HOME|~|") | |
| D2=$(dirname "$DIR") | |
| if [ -n "$D2" ] && [[ ! "$D2" == "/" ]];then | |
| DIRNAME2=$(basename "$D2")/$(basename "$DIR") | |
| else | |
| DIRNAME2=$(basename "$DIR") | |
| fi | |
| echo "$DIRNAME2" | |
| fi | |
| } | |
| function _cur_folder_with_git_base { | |
| DIR=$(_last_two_folders) | |
| BASE=$(_git_repo_base) | |
| if [ -n "$BASE" ]; then | |
| if [[ "$DIR" == *"$BASE"* ]];then | |
| echo "$DIR" | sed "s/$BASE/%F{240}$BASE%{$reset_color%}/" | |
| else | |
| echo "%F{240}$BASE%{$reset_color%} $DIR" | |
| fi | |
| else | |
| echo "$DIR" | |
| fi | |
| } | |
| PROMPT='${_return_status}${_tmux_indicator}%F{003}%B%(1j.#.)%b%f ' | |
| RPROMPT='%F{white}%2~ ' | |
| function generate_lpropmpt() { | |
| PROMPT_GREPPER=" " # will only add this in tmux | |
| if [[ -n "$TMUX" ]] ; then | |
| PROMPT_GREPPER=" " | |
| fi | |
| echo "${${KEYMAP/vicmd/$NORMAL_COLOR}/(main|viins)/$INSERT_COLOR}${_return_status}${_tmux_indicator}$( _vcs_info_wrapper )%F{yellow}%B%(1j.#.)%b%f$PROMPT_GREPPER" | |
| } | |
| function generate_rpropmpt() { | |
| echo "%F{003}$(virtualenv_info)%F{blue}$(_current_kubernetes_namespace)$FG[240]$(_git_pushable)%f $(_cur_folder_with_git_base)%f" | |
| } | |
| ASYNC_LPROC=0 | |
| ASYNC_RPROC=0 | |
| function precmd() { | |
| function asyncl() { | |
| mkdir -p /tmp/zp | |
| printf "%s" "$(generate_lpropmpt)" > "/tmp/zp/zsh_lprompt_$$" # do not clear, let it persist | |
| kill -s USR1 $$ # signal parent | |
| } | |
| function asyncr() { | |
| mkdir -p /tmp/zp | |
| printf "%s" "$(generate_rpropmpt)" > "/tmp/zp/zsh_rprompt_$$" # save to temp file | |
| kill -s USR2 $$ # signal parent | |
| } | |
| if [[ "${ASYNC_LPROC}" != 0 ]]; then # kill child if necessary | |
| kill -s HUP $ASYNC_LPROC >/dev/null 2>&1 || : | |
| fi | |
| if [[ "${ASYNC_RPROC}" != 0 ]]; then # kill child if necessary | |
| kill -s HUP $ASYNC_RPROC >/dev/null 2>&1 || : | |
| fi | |
| asyncl &! # start background computation | |
| ASYNC_LPROC=$! # save pid | |
| asyncr &! # start background computation | |
| ASYNC_RPROC=$! # save pid | |
| function zle-keymap-select { | |
| asyncl &! # start background computation | |
| ASYNC_LPROC=$! # save pid | |
| asyncr &! # start background computation | |
| ASYNC_RPROC=$! # save pid | |
| } | |
| zle -N zle-keymap-select | |
| # printf '\e[38;5;235m―%.0s' {1..$COLUMNS} # use if you need a seperator | |
| echo "" # newline before prompt | |
| # notify for long running command | |
| if ! [[ -z $CMD_START_DATE ]]; then | |
| CMD_END_DATE=$(date +%s) | |
| CMD_ELAPSED_TIME=$(($CMD_END_DATE - $CMD_START_DATE)) | |
| CMD_NOTIFY_THRESHOLD=60 | |
| CMD_ELAPSED_TIME_MIN="$(($CMD_ELAPSED_TIME/60))" | |
| CMD_ELAPSED_TIME_SEC="$(($CMD_ELAPSED_TIME%60))" | |
| CMD_START_DATE="" | |
| if [[ $CMD_ELAPSED_TIME -gt $CMD_NOTIFY_THRESHOLD ]]; then | |
| notify "$CMD_NAME" "Completed in ${CMD_ELAPSED_TIME_MIN}m${CMD_ELAPSED_TIME_SEC}s" | |
| fi | |
| fi | |
| } | |
| function TRAPUSR1() { | |
| # to insert non breaking space in vim: <c-k> <space> <space> | |
| PS1="$(cat /tmp/zp/zsh_lprompt_$$)" # read from temp file ( uses non breaking space ) | |
| ASYNC_LPROC=0 # reset proc number | |
| zle && zle reset-prompt # redisplay | |
| } | |
| function TRAPUSR2() { | |
| RPS1="$(cat /tmp/zp/zsh_rprompt_$$)" | |
| ASYNC_RPROC=0 # reset proc number | |
| zle && zle reset-prompt # redisplay | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment