11# Simple, reliable prompt similar to p10k lean style
22# Shows: directory, git info, command execution time, exit status
3+ # Git status is fetched asynchronously to avoid blocking
34
45# Enable colors
56autoload -U colors && colors
67
7- # Enable vcs_info for git status
8- autoload -Uz vcs_info
9- zstyle ' :vcs_info:*' enable git
10- zstyle ' :vcs_info:*' check-for-changes true
11- zstyle ' :vcs_info:*' stagedstr ' %F{green}+'
12- zstyle ' :vcs_info:*' unstagedstr ' %F{yellow}!'
13- zstyle ' :vcs_info:git:*' formats ' %F{cyan}%b%f%c%u'
14- zstyle ' :vcs_info:git:*' actionformats ' %F{cyan}%b%f|%F{red}%a%f%c%u'
8+ # ============================================================================
9+ # Async git status
10+ # ============================================================================
1511
16- # Track command execution time
12+ # State variables
13+ _prompt_git_info=" "
1714_prompt_exec_start=0
1815_prompt_exec_time=0
16+ _prompt_exit_code=0
17+ _prompt_async_fd=" "
18+ _prompt_async_pid=" "
19+
20+ # Get git status synchronously (called in background)
21+ _prompt_git_status () {
22+ cd -q " $1 " 2> /dev/null || return
23+
24+ # Check if we're in a git repo
25+ local branch
26+ branch=$( git symbolic-ref --short HEAD 2> /dev/null) || \
27+ branch=$( git rev-parse --short HEAD 2> /dev/null) || return
28+
29+ local result=" %F{cyan}${branch} %f"
30+
31+ # Check for staged changes
32+ if ! git diff --cached --quiet 2> /dev/null; then
33+ result+=" %F{green}+%f"
34+ fi
35+
36+ # Check for unstaged changes
37+ if ! git diff --quiet 2> /dev/null; then
38+ result+=" %F{yellow}!%f"
39+ fi
40+
41+ # Check for untracked files
42+ if [[ -n $( git ls-files --others --exclude-standard 2> /dev/null | head -1) ]]; then
43+ result+=" %F{blue}?%f"
44+ fi
45+
46+ echo " ${result} "
47+ }
48+
49+ # Callback when async job completes
50+ _prompt_async_callback () {
51+ local fd=" $1 "
52+
53+ # Read result from file descriptor
54+ _prompt_git_info=" "
55+ if [[ -n " $fd " ]] && read -r -u " $fd " _prompt_git_info 2> /dev/null; then
56+ : # Successfully read
57+ fi
58+
59+ # Clean up file descriptor
60+ if [[ -n " $_prompt_async_fd " ]]; then
61+ zle -F " $_prompt_async_fd " 2> /dev/null
62+ exec {_prompt_async_fd}< & - 2> /dev/null
63+ _prompt_async_fd=" "
64+ fi
65+
66+ _prompt_async_pid=" "
67+
68+ # Redraw prompt with new git info
69+ zle && zle reset-prompt
70+ }
71+
72+ # Start async git status fetch
73+ _prompt_async_start () {
74+ # Kill any existing async job
75+ if [[ -n " $_prompt_async_pid " ]]; then
76+ kill " $_prompt_async_pid " 2> /dev/null
77+ _prompt_async_pid=" "
78+ fi
79+
80+ # Clean up old file descriptor
81+ if [[ -n " $_prompt_async_fd " ]]; then
82+ zle -F " $_prompt_async_fd " 2> /dev/null
83+ exec {_prompt_async_fd}< & - 2> /dev/null
84+ _prompt_async_fd=" "
85+ fi
86+
87+ # Clear git info while loading
88+ _prompt_git_info=" "
89+
90+ # Quick check: are we in a git repo at all?
91+ git rev-parse --is-inside-work-tree & > /dev/null || return
92+
93+ # Start background job and capture output via fd
94+ exec {_prompt_async_fd}< <( _prompt_git_status " $PWD " )
95+ _prompt_async_pid=$!
96+
97+ # Register callback for when data is available
98+ zle -F " $_prompt_async_fd " _prompt_async_callback
99+ }
100+
101+ # ============================================================================
102+ # Prompt hooks
103+ # ============================================================================
19104
20105preexec () {
21106 _prompt_exec_start=$EPOCHREALTIME
@@ -35,10 +120,14 @@ precmd() {
35120 # Store exit code for prompt
36121 _prompt_exit_code=$exit_code
37122
38- # Update vcs_info
39- vcs_info
123+ # Start async git status fetch
124+ _prompt_async_start
40125}
41126
127+ # ============================================================================
128+ # Prompt segments
129+ # ============================================================================
130+
42131# Format execution time (only show if > 3 seconds)
43132_prompt_format_time () {
44133 (( _prompt_exec_time < 3 )) && return
@@ -67,29 +156,18 @@ _prompt_char() {
67156 fi
68157}
69158
70- # Git info with untracked files indicator
71- _prompt_git () {
72- [[ -z " ${vcs_info_msg_0_} " ]] && return
73-
74- local git_info=" ${vcs_info_msg_0_} "
75-
76- # Check for untracked files
77- if command git status --porcelain 2> /dev/null | grep -q ' ^??' ; then
78- git_info+=' %F{blue}?%f'
79- fi
80-
81- echo " ${git_info} "
82- }
83-
84159# Right prompt with time
85160_prompt_time () {
86161 echo " %F{8}%T%f"
87162}
88163
164+ # ============================================================================
89165# Set prompts
166+ # ============================================================================
167+
90168setopt PROMPT_SUBST
91169
92- PROMPT=' %F{blue}%~%f$(_prompt_git)
170+ PROMPT=' %F{blue}%~%f${_prompt_git_info}
93171$(_prompt_char) '
94172
95173RPROMPT=' $(_prompt_format_time)$(_prompt_time)'
0 commit comments