aboutsummaryrefslogtreecommitdiff
path: root/linux/home/.config/zsh/user/prompt.zsh
diff options
context:
space:
mode:
authorsrdusr <trevorgray@srdusr.com>2025-09-01 15:40:50 +0200
committersrdusr <trevorgray@srdusr.com>2025-09-01 15:40:50 +0200
commit40fc89461967f0094911e8846117ed3190e42d0b (patch)
treeed22b71d8a3036fb7e0e2a48ec6a09f99f9da365 /linux/home/.config/zsh/user/prompt.zsh
parentecd73a73200a64b5c62614debd9f9ec08748a72d (diff)
downloaddotfiles-40fc89461967f0094911e8846117ed3190e42d0b.tar.gz
dotfiles-40fc89461967f0094911e8846117ed3190e42d0b.zip
Testing
Diffstat (limited to 'linux/home/.config/zsh/user/prompt.zsh')
-rw-r--r--linux/home/.config/zsh/user/prompt.zsh568
1 files changed, 522 insertions, 46 deletions
diff --git a/linux/home/.config/zsh/user/prompt.zsh b/linux/home/.config/zsh/user/prompt.zsh
index d9fc148..b8b1b97 100644
--- a/linux/home/.config/zsh/user/prompt.zsh
+++ b/linux/home/.config/zsh/user/prompt.zsh
@@ -2,19 +2,91 @@
########## Prompt(s) ##########
-terminfo_down_sc=$terminfo[cud1]$terminfo[cuu1]$terminfo[sc]$terminfo[cud1]
-
+# Autoload necessary functions for vcs_info and coloring
autoload -Uz vcs_info
autoload -Uz add-zsh-hook
autoload -U colors && colors
+# Enable prompt substitution
+setopt prompt_subst
+
+# Display git branch status and color
precmd_vcs_info() { vcs_info }
+# Add vcs_info to precmd functions
precmd_functions+=( precmd_vcs_info )
-setopt prompt_subst
+# Manipulates cursor position: moves down by 2 lines, saves position, and restores cursor after an operation.
+terminfo_down_sc=$terminfo[cud1]$terminfo[cuu1]$terminfo[sc]$terminfo[cud1]
+
+# Track last executed command for exit code display
+typeset -g _last_executed_command=""
+typeset -g _cmd_start_time=0
+typeset -g _cmd_end_time=0
+typeset -g _cmd_duration=0
+typeset -g _spinner_idx=0
+typeset -ga _spinner_frames=('⣾' '⣽' '⣻' '⢿' '⡿' '⣟' '⣯' '⣷')
+typeset -g _cmd_is_running=0
+typeset -g _show_spinner=0
+typeset -g _SPINNER_DELAY=5 # Only show spinner after 5 seconds
+typeset -g _FINISHED_DELAY=10 # Only show finished message after 10 seconds
+
+# Register the ZLE widget for spinner updates - do this early
+zle -N update_spinner
+
+# Cache git information to avoid repeated expensive operations
+typeset -g _git_cached_info=""
+typeset -g _git_cache_timestamp=0
+typeset -g _git_cache_lifetime=2 # seconds before cache expires
+
+# Calculate how much space is available for the prompt components
+function available_space() {
+ local width=${COLUMNS:-80}
+ echo $width
+}
+
+# Check if we need to abbreviate git info
+function need_to_abbreviate_git() {
+ local available=$(available_space)
+ local vi_mode_len=13 # Length of "-- INSERT --"
+ local prompt_base_len=20 # Base prompt elements length
+ local path_len=${#${PWD/#$HOME/\~}}
+ local git_full_len=0
+
+ # Try to estimate git info length if available
+ if git rev-parse --is-inside-work-tree &>/dev/null; then
+ local branch=$(git symbolic-ref --short HEAD 2>/dev/null)
+ git_full_len=${#branch}
+
+ # Add length for status indicators
+ if [[ -n "$(git status --porcelain)" ]]; then
+ # Rough estimate for status text
+ git_full_len=$((git_full_len + 20))
+ fi
+ fi
+
+ # Calculate total space needed
+ local total_needed=$((vi_mode_len + prompt_base_len + path_len + git_full_len))
+
+ # Determine if we need to abbreviate
+ if [[ $total_needed -gt $available ]]; then
+ return 0 # Need to abbreviate
+ else
+ return 1 # Don't need to abbreviate
+ fi
+}
+# Custom git branch coloring based on status
git_branch_test_color() {
+ local now=$(date +%s)
+ local cache_age=$((now - _git_cache_timestamp))
+
+ # Use cached value if available and not expired
+ if [[ -n "$_git_cached_info" && $cache_age -lt $_git_cache_lifetime ]]; then
+ echo "$_git_cached_info"
+ return
+ fi
+
local ref=$(git symbolic-ref --short HEAD 2> /dev/null)
if [ -n "${ref}" ]; then
if [ -n "$(git status --porcelain)" ]; then
@@ -22,76 +94,376 @@ git_branch_test_color() {
else
local gitstatuscolor='%F{82}'
fi
- echo "${gitstatuscolor}${ref}"
+ _git_cached_info="${gitstatuscolor}${ref}"
+ _git_cache_timestamp=$now
+ echo "$_git_cached_info"
else
+ _git_cached_info=""
+ _git_cache_timestamp=$now
echo ""
fi
}
+# Git branch with dynamic abbreviation
+git_branch_dynamic() {
+ local now=$(date +%s)
+ local cache_age=$((now - _git_cache_timestamp))
+
+ # Only query git if cache is expired
+ if [[ $cache_age -ge $_git_cache_lifetime ]]; then
+ local ref=$(git symbolic-ref --short HEAD 2> /dev/null)
+ if [ -n "${ref}" ]; then
+ if need_to_abbreviate_git; then
+ # Abbreviated version for small terminals
+ case "${ref}" in
+ "main") _git_cached_info="m" ;;
+ "master") _git_cached_info="m" ;;
+ "development") _git_cached_info="d" ;;
+ "develop") _git_cached_info="d" ;;
+ "feature/"*) _git_cached_info="f/${ref#feature/}" | cut -c 1-4 ;;
+ "release/"*) _git_cached_info="r/${ref#release/}" | cut -c 1-4 ;;
+ "hotfix/"*) _git_cached_info="h/${ref#hotfix/}" | cut -c 1-4 ;;
+ *) _git_cached_info="${ref}" | cut -c 1-5 ;; # Truncate to first 5 chars for other branches
+ esac
+ else
+ # Full branch name when there's room
+ _git_cached_info="${ref}"
+ fi
+ _git_cache_timestamp=$now
+ echo "$_git_cached_info"
+ else
+ _git_cached_info=""
+ _git_cache_timestamp=$now
+ echo ""
+ fi
+ else
+ echo "$_git_cached_info"
+ fi
+}
+
+# VCS info styles (e.g., git)
zstyle ':vcs_info:*' check-for-changes true
-zstyle ':vcs_info:*' stagedstr ' +%F{15}staged%f'
-zstyle ':vcs_info:*' unstagedstr ' -%F{15}unstaged%f'
-zstyle ':vcs_info:*' actionformats '%F{5}%F{2}%b%F{3}|%F{1}%a%F{5}%f '
-zstyle ':vcs_info:*' formats '%F{208} '$'\uE0A0'' %f$(git_branch_test_color)%f%F{76}%c%F{3}%u%f '
-zstyle ':vcs_info:git*+set-message:*' hooks git-untracked
zstyle ':vcs_info:*' enable git
+# Dynamically configure vcs_info formats based on available space
+function configure_vcs_styles() {
+ if need_to_abbreviate_git; then
+ # Abbreviated versions
+ zstyle ':vcs_info:*' stagedstr ' +%F{15}s%f'
+ zstyle ':vcs_info:*' unstagedstr ' -%F{15}u%f'
+ else
+ # Full versions
+ zstyle ':vcs_info:*' stagedstr ' +%F{15}staged%f'
+ zstyle ':vcs_info:*' unstagedstr ' -%F{15}unstaged%f'
+ fi
+
+ zstyle ':vcs_info:*' actionformats '%F{5}%F{2}%b%F{3}|%F{1}%a%F{5}%f '
+ zstyle ':vcs_info:*' formats '%F{208} '$'\uE0A0'' %f$(git_branch_test_color)%f%F{76}%c%F{3}%u%f '
+ zstyle ':vcs_info:git*+set-message:*' hooks git-untracked git-dynamic
+}
+
+# Show "untracked" status in git - with conditional abbreviation
+vi-git-untracked() {
if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \
git status --porcelain | grep '??' &> /dev/null ; then
- hook_com[unstaged]+='%F{196} !%f%F{15}untracked%f'
+
+ if need_to_abbreviate_git; then
+ hook_com[unstaged]+='%F{196} !%f%F{15}u%f'
+ else
+ hook_com[unstaged]+='%F{196} !%f%F{15}untracked%f'
+ fi
fi
}
+# Dynamic git branch hook
++vi-git-dynamic() {
+ hook_com[branch]=$(git_branch_dynamic)
+}
+
+# SSH info with conditional abbreviation
ssh_name() {
if [[ -n $SSH_CONNECTION ]]; then
local ssh_info
- ssh_info="ssh:%F{green}%n$nc%f"
- if [[ -n $SSH_CONNECTION ]]; then
- local ip_address
- ip_address=$(echo $SSH_CONNECTION | awk '{print $3}')
- ssh_info="$ssh_info@%F{green}$ip_address%f"
+
+ if need_to_abbreviate_git; then
+ # Abbreviated SSH info
+ ssh_info="ssh:%F{green}%n$nc%f"
+ else
+ ssh_info="ssh:%F{green}%n$nc%f"
+ if [[ -n $SSH_CONNECTION ]]; then
+ local ip_address
+ ip_address=$(echo $SSH_CONNECTION | awk '{print $3}')
+ ssh_info="$ssh_info@%F{green}$ip_address%f"
+ fi
fi
echo " ${ssh_info}"
fi
}
+# Job names (for job control) with conditional abbreviation
function job_name() {
job_name=""
job_length=0
- if [ "${COLUMNS}" -gt 69 ]; then
- job_length=$((${COLUMNS}-70))
- [ "${job_length}" -lt "0" ] && job_length=0
- fi
+ local available=$(available_space)
- if [ "${job_length}" -gt 0 ]; then
+ # Only show jobs if we have reasonable space
+ if [ "${available}" -gt 60 ]; then
local job_count=$(jobs | wc -l)
if [ "${job_count}" -gt 0 ]; then
- local title_jobs="jobs:"
- job_name="${title_jobs}"
- job_name+="%F{green}$(jobs | grep + | tr -s " " | cut -d " " -f 4- | cut -b 1-${job_length} | sed "s/\(.*\)/\1/")%f"
+ if need_to_abbreviate_git; then
+ job_name+="%F{green}j:${job_count}%f"
+ else
+ local title_jobs="jobs:"
+ job_name="${title_jobs}"
+ job_length=$((${available}-70))
+ [ "${job_length}" -lt "0" ] && job_length=0
+
+ if [ "${job_length}" -gt 0 ]; then
+ job_name+="%F{green}$(jobs | grep + | tr -s " " | cut -d " " -f 4- | cut -b 1-${job_length} | sed "s/\(.*\)/\1/")%f"
+ else
+ job_name+="%F{green}${job_count}%f"
+ fi
+ fi
fi
fi
echo "${job_name}"
}
-function job_count() {
- local job_count
- job_count=$(jobs -s | grep -c "suspended")
- if [ "${job_count}" -gt 0 ]; then
- echo "(${job_count})"
+# Check if we should show the spinner based on elapsed time
+function should_show_spinner() {
+ if [[ $_cmd_is_running -eq 1 ]]; then
+ local current_time=$(date +%s)
+ local elapsed=$((current_time - _cmd_start_time))
+
+ # Show spinner only after delay threshold
+ if [[ $elapsed -ge $_SPINNER_DELAY ]]; then
+ _show_spinner=1
+ return 0 # Yes, show spinner
+ fi
+ fi
+
+ _show_spinner=0
+ return 1 # No, don't show spinner
+}
+
+# Update spinner animation - simplified version
+function update_spinner() {
+ # This function is now just a ZLE widget placeholder
+ # The actual spinner updates happen in the TRAPALRM handler
+ :
+}
+
+# Start spinner timer when command runs longer than threshold
+function start_spinner_timer() {
+ _spinner_idx=0
+ _cmd_is_running=1
+ _show_spinner=0 # Start with spinner hidden until delay passes
+
+ # Set up the TRAPALRM for periodic updates - CRITICAL FIX
+ TMOUT=0.5 # Update spinner every 0.5 seconds
+
+ # Define TRAPALRM function - this is key to the spinner working
+ TRAPALRM() {
+ if [[ $_cmd_is_running -eq 1 ]]; then
+ local current_time=$(date +%s)
+ local elapsed=$((current_time - _cmd_start_time))
+
+ # Show spinner only after delay threshold
+ if [[ $elapsed -ge $_SPINNER_DELAY ]]; then
+ _show_spinner=1
+ _spinner_idx=$(( (_spinner_idx + 1) % ${#_spinner_frames[@]} ))
+
+ # Force prompt refresh - critical for updating the spinner
+ if [[ -o zle ]]; then
+ zle reset-prompt 2>/dev/null || true
+ zle -R
+ fi
+ fi
+ fi
+ }
+}
+
+# Stop spinner when command finishes
+function stop_spinner_timer() {
+ _cmd_is_running=0
+ _show_spinner=0
+
+ # Disable the alarm trap and timer
+ TRAPALRM() { : }
+ TMOUT=0
+
+ # Force prompt refresh to clear spinner
+ if [[ -o zle ]]; then
+ zle reset-prompt 2>/dev/null || true
+ zle -R
fi
}
-current_jobs=' $(job_name)$(job_count)'
+# Format time in a human-readable way
+function format_time() {
+ local seconds=$1
+ local result=""
+
+ # Format time as hours:minutes:seconds for long durations
+ if [[ $seconds -ge 3600 ]]; then
+ local hours=$((seconds / 3600))
+ local minutes=$(( (seconds % 3600) / 60 ))
+ local secs=$((seconds % 60))
+ result="${hours}h${minutes}m${secs}s"
+ elif [[ $seconds -ge 60 ]]; then
+ local minutes=$((seconds / 60))
+ local secs=$((seconds % 60))
+ result="${minutes}m${secs}s"
+ else
+ result="${seconds}s"
+ fi
+
+ echo "$result"
+}
+
+# Error code display for RPROMPT with spinner - fixed version
+function exit_code_info() {
+ local exit_code=$?
+
+ # If a command is running and we should show spinner
+ if [[ $_cmd_is_running -eq 1 && $_show_spinner -eq 1 ]]; then
+ local spinner=${_spinner_frames[$_spinner_idx]}
+ local current_time=$(date +%s)
+ local elapsed=$((current_time - _cmd_start_time))
+ echo "%F{yellow}${spinner} ${elapsed}s%f"
+ return
+ fi
+
+ # Don't show error code when line editor is active (user is typing)
+ if [[ -o zle ]]; then
+ echo ""
+ return
+ fi
+
+ # Show command finished message for completed commands that took longer than threshold
+ if [[ -n "$_last_executed_command" && $_cmd_duration -ge $_FINISHED_DELAY ]]; then
+ local duration_formatted=$(format_time $_cmd_duration)
+
+ # Show error code along with finished message if there was an error
+ if [[ $exit_code -ne 0 ]]; then
+ # Show TSTP (148) as a suspension indicator instead of error
+ if [[ $exit_code -eq 148 ]]; then
+ echo "%F{cyan}finished ${duration_formatted}%f %F{yellow}⏸ TSTP%f"
+ return
+ fi
+
+ local signal_name=""
+ # Check if it's a signal
+ if [[ $exit_code -gt 128 && $exit_code -le 165 ]]; then
+ local signal_num=$((exit_code - 128))
+ signal_name=$(kill -l $signal_num 2>/dev/null)
+ if [[ -n "$signal_name" ]]; then
+ signal_name=" ($signal_name)"
+ fi
+ fi
+
+ # Return formatted error code with finished message
+ echo "%F{cyan}finished ${duration_formatted}%f %F{red}✘ $exit_code$signal_name%f"
+ else
+ echo "%F{cyan}finished ${duration_formatted}%f %F{green}✓%f"
+ fi
+ return
+ fi
+
+ # Don't show anything for exit code 0 (success) if this is first command
+ if [[ -z "$_last_executed_command" && $exit_code -eq 0 ]]; then
+ echo ""
+ return
+ fi
+
+ # Show TSTP (148) as a suspension indicator instead of error
+ if [[ $exit_code -eq 148 ]]; then
+ echo "%F{yellow}⏸ TSTP%f"
+ return
+ fi
+
+ if [[ $exit_code -ne 0 ]]; then
+ local signal_name=""
+
+ # Check if it's a signal
+ if [[ $exit_code -gt 128 && $exit_code -le 165 ]]; then
+ local signal_num=$((exit_code - 128))
+ signal_name=$(kill -l $signal_num 2>/dev/null)
+ if [[ -n "$signal_name" ]]; then
+ signal_name=" ($signal_name)"
+ fi
+ fi
+
+ # Return formatted error code
+ echo "%F{red}✘ $exit_code$signal_name%f"
+ else
+ echo "%F{green}✓%f" # Success indicator
+ fi
+}
+
+abbreviated_path() {
+ local full_path="${PWD/#$HOME/~}" # Replace $HOME with ~
+ local available=$(available_space)
+
+ # If path is root
+ if [[ "$full_path" == "/" ]]; then
+ echo "%F{4}/%f"
+ return
+ fi
+
+ # If path is just ~
+ if [[ "$full_path" == "~" ]]; then
+ echo "%F{4}~%f"
+ return
+ fi
+
+ # If extremely small terminal, show nothing to avoid breaking prompt
+ if (( available < 20 )); then
+ echo ""
+ return
+ fi
+
+ # For very narrow terminals, just show the current dir
+ if (( available < 30 )); then
+ echo "%F{4}%1~%f"
+ return
+ fi
+
+ # For moderately narrow terminals, show last two components
+ if (( available < 40 )); then
+ echo "%F{4}%2~%f"
+ return
+ fi
+
+ # For wide terminals, show full path
+ if (( available > 70 )); then
+ echo "%F{4}${full_path}%f"
+ return
+ fi
+
+ # Otherwise, show abbreviated path (e.g. ~/d/p/n)
+ local parts=("${(s:/:)full_path}")
+ local result=""
+ local last_index=${#parts[@]}
+
+ for i in {1..$((last_index - 1))}; do
+ [[ -n ${parts[i]} ]] && result+="/${parts[i]:0:1}"
+ done
+
+ result+="/${parts[last_index]}"
+ echo "%F{4}${result}%f"
+}
+
+
+# Prompt variables
user="%n"
at="%F{15}at%{$reset_color%}"
machine="%F{4}%m%{$reset_color%}"
relative_home="%F{4}%~%{$reset_color%}"
carriage_return=""$'\n'""
-empty_line_bottom="%r"
-chevron_right=""
+empty_line_bottom=""
+chevron_right=""
color_reset="%{$(tput sgr0)%}"
color_yellow="%{$(tput setaf 226)%}"
color_blink="%{$(tput blink)%}"
@@ -99,16 +471,27 @@ prompt_symbol="$"
dollar_sign="${color_yellow}${color_blink}${prompt_symbol}${color_reset}"
dollar="%(?:%F{2}${dollar_sign}:%F{1}${dollar_sign})"
space=" "
+#thin_space=$'\u2009'
+thin_space=$'\u202F'
cmd_prompt="%(?:%F{2}${chevron_right} :%F{1}${chevron_right} )"
git_info="\$vcs_info_msg_0_"
v1="%{┌─[%}"
v2="%{]%}"
v3="└─["
v4="]"
+newline=$'\n'
-function insert-mode () { echo "-- INSERT --" }
-function normal-mode () { echo "-- NORMAL --" }
+# Indicate INSERT mode for vi - NEVER truncate this
+function insert-mode () {
+ echo "-- INSERT --"
+}
+# Indicate NORMAL mode for vi - NEVER truncate this
+function normal-mode () {
+ echo "-- NORMAL --"
+}
+
+# Vi mode indicator
vi-mode-indicator () {
if [[ ${KEYMAP} == vicmd || ${KEYMAP} == vi-cmd-mode ]]; then
echo -ne '\e[1 q'
@@ -119,32 +502,87 @@ vi-mode-indicator () {
fi
}
-function set-prompt () {
+# Prompt function to ensure the prompt stays on one line, even in narrow terminals
+function set-prompt() {
vi-mode-indicator
- mode="%F{145}%{$terminfo_down_sc$vi_mode$terminfo[rc]%f%}"
- #PS1="${relative_home}${vcs_info_msg_0_}${current_jobs} ${carriage_return}${mode}${dollar}${space}"
- PS1="${v1}${user}${v2}${space}${relative_home}${vcs_info_msg_0_}${current_jobs}$(ssh_name) ${carriage_return}${mode}${v3}${dollar}${v4}${empty_line_bottom}"
- #RPROMPT="$(ssh_name)"
+ configure_vcs_styles # Dynamically set vcs styles based on available space
+ vcs_info # Refresh vcs info with new styles
+
+ local available=$(available_space)
+ if (( available < 14 )); then
+ # Extremely narrow terminal — use minimal prompt
+ PS1="${carriage_return}${dollar}${space}${empty_line_bottom}"
+ #RPROMPT='$(exit_code_info)'
+
+ else
+ # Path display - always show something for path, but adapt based on space
+ local path_display="$(abbreviated_path)"
+
+ # Git info - omit entirely if not enough space
+ local gitinfo=""
+ if [[ $available -gt 40 ]]; then
+ gitinfo="${vcs_info_msg_0_}"
+ fi
+
+ # Jobs info
+ local jobs=" $(job_name)"
+
+ # SSH info
+ local sshinfo="$(ssh_name)"
+
+ # Vi mode is priority 1 - ALWAYS show it
+ mode="%F{145}%{$terminfo_down_sc$vi_mode$terminfo[rc]%f%}"
+
+ # Right prompt for error codes or spinner
+ #RPROMPT='$(exit_code_info)'
+
+ PS1="${newline}${v1}${user}${v2} ${path_display}${gitinfo}${jobs}${sshinfo}${carriage_return}${mode}${v3}${dollar}${v4}${empty_line_bottom}"
+ fi
}
-precmd () {
- print -rP
+# Pre-command hook to set prompt
+my_precmd() {
+ # Calculate command duration if a command was run
+ if [[ -n "$_last_executed_command" && $_cmd_start_time -gt 0 ]]; then
+ _cmd_end_time=$(date +%s)
+ _cmd_duration=$((_cmd_end_time - _cmd_start_time))
+ else
+ _cmd_duration=0
+ fi
+
+ stop_spinner_timer # Make sure spinner is stopped
vcs_info
set-prompt
+ vi-mode-indicator
}
+add-zsh-hook precmd my_precmd
-function update-mode-file() {
+# Update mode file based on current mode
+update-mode-file() {
set-prompt
- local current_mode=$(cat ~/.vi-mode)
+ local current_mode=$(cat ~/.vi-mode 2>/dev/null || echo "")
local new_mode="$vi_mode"
+
if [[ "$new_mode" != "$current_mode" ]]; then
echo "$new_mode" >| ~/.vi-mode
fi
+
+ # Ensure we're in an interactive shell and ZLE is active
+ if [[ -o zle ]] && zle -l &>/dev/null; then
+ zle reset-prompt 2>/dev/null || true
+ else
+ # If ZLE is not active, fallback and print the prompt manually
+ set-prompt
+ print -Pn "$PS1"
+ fi
+
+ # Refresh tmux client if tmux is running
if command -v tmux &>/dev/null && [[ -n "$TMUX" ]]; then
tmux refresh-client -S
fi
}
+# Check if nvim is running and update mode
function check-nvim-running() {
if pgrep -x "nvim" > /dev/null; then
vi_mode=""
@@ -165,8 +603,10 @@ function check-nvim-running() {
fi
}
+# ZLE line initialization hook
function zle-line-init() {
zle reset-prompt
+ vi-mode-indicator
case "${KEYMAP}" in
vicmd)
echo -ne '\e[1 q'
@@ -177,9 +617,12 @@ function zle-line-init() {
esac
}
+# ZLE keymap select hook
function zle-keymap-select() {
update-mode-file
zle reset-prompt
+ zle -R
+ vi-mode-indicator
case "${KEYMAP}" in
vicmd)
echo -ne '\e[1 q'
@@ -190,13 +633,46 @@ function zle-keymap-select() {
esac
}
-preexec () { print -rn -- $terminfo[el]; echo -ne '\e[5 q' ; }
+# Safer version of zle reset-prompt
+function safe_reset_prompt() {
+ # Only reset if ZLE is active
+ if [[ -o zle ]] && zle -l &>/dev/null; then
+ zle reset-prompt 2>/dev/null || true
+ fi
+}
-zle -N zle-line-init
-zle -N zle-keymap-select
+# Preexec hook for command execution - NO BACKGROUND JOBS VERSION
+function preexec() {
+ # Store the command being executed
+ _last_executed_command=$1
+ _cmd_start_time=$(date +%s)
+ _cmd_is_running=1
+ _show_spinner=0 # Reset spinner flag
+
+ # Start the spinner timer immediately
+ start_spinner_timer
+ print -rn -- $terminfo[el]
+ echo -ne '\e[5 q'
+ vi-mode-indicator
+}
+
+# Terminal resizing: resets the prompt if ZLE is active, updates the mode file.
TRAPWINCH() {
- update-mode-file
+ if [[ -o zle ]] && zle -l &>/dev/null; then
+ zle -R
+ zle reset-prompt 2>/dev/null || true
+ fi
+ update-mode-file 2>/dev/null
}
+# Register ZLE hooks
+zle -N zle-line-init
+zle -N zle-keymap-select
+zle -N update_spinner
+
+# Register hooks
+add-zsh-hook preexec preexec
+add-zsh-hook precmd my_precmd
+
set-prompt