-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprompt_asynczle_setup.zsh
executable file
·177 lines (135 loc) · 4.46 KB
/
prompt_asynczle_setup.zsh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# In a file `prompt_asynczle_setup` available on `fpath`
emulate -L zsh
typeset -g ZSH_ASYNC_PROMPT_START_MARK=${ZSH_ASYNC_PROMPT_START_MARK:-}
typeset -g ZSH_ASYNC_PROMPT_TIMEOUT=${ZSH_ASYNC_PROMPT_TIMEOUT:-5s}
typeset -g ZSH_ASYNC_PROMPT_EXEC=${GOPROMPT}
typeset -g ZSH_ASYNC_PROMPT_DATA=""
typeset -g ZSH_ASYNC_PROMPT_LAST=""
typeset -g ZSH_ASYNC_PROMPT_LAST_STATUS=0
typeset -g ZSH_ASYNC_PROMPT_PREEXEC_TS=0
typeset -g ZSH_ASYNC_PROMPT_QUERY_DONE=0
declare -gA __ZLE_ASYNC_FDS=()
typeset -g __ZSH_ASYNC_PROMPT_NEWLINE=$'\n%{\r%}'
#-------------------------------------------------------------------------------
__async_check_exec() {
local exec_name="$1"
if (( $+commands[${exec_name}] )); then
return 0
fi
if [[ -e ${exec_name} ]]; then
return 0
fi
return 1
}
__async_prompt_query() {
if ! __async_check_exec "${ZSH_ASYNC_PROMPT_EXEC}"; then
echo -n ""
return
fi
${ZSH_ASYNC_PROMPT_EXEC} query \
--cmd-status "${ZSH_ASYNC_PROMPT_LAST_STATUS:-0}" \
--preexec-ts "${ZSH_ASYNC_PROMPT_PREEXEC_TS:-0}" \
--pid-parent-skip 1 \
--timeout "${ZSH_ASYNC_PROMPT_TIMEOUT:-5s}"
}
__async_prompt_render() {
if ! __async_check_exec "${ZSH_ASYNC_PROMPT_EXEC}"; then
echo -n "?>"
return
fi
local MODE="normal"
if [[ $KEYMAP == "viins" ]]; then
MODE="edit"
fi
local LOADING=1
if [[ $ZSH_ASYNC_PROMPT_QUERY_DONE -eq 1 ]]; then
LOADING=0
fi
${ZSH_ASYNC_PROMPT_EXEC} render \
--prompt-mode "$MODE" \
--prompt-loading="$LOADING" \
--prompt-mark-start "$ZSH_ASYNC_PROMPT_START_MARK" \
--escape-mode "zsh"
}
#-------------------------------------------------------------------------------
__prompt_rerender() {
PROMPT="$(printf "%s\n" "$ZSH_ASYNC_PROMPT_DATA" | __async_prompt_render) "
if [[ $PROMPT != $ZSH_ASYNC_PROMPT_LAST ]]; then
zle && zle reset-prompt
fi
ZSH_ASYNC_PROMPT_LAST="$PROMPT"
}
#-------------------------------------------------------------------------------
# Command Handlers + Async Comm
#-------------------------------------------------------------------------------
__prompt_preexec() {
typeset -g ZSH_ASYNC_PROMPT_PREEXEC_TS=$EPOCHSECONDS
}
__prompt_precmd() {
# save the status of last command.
ZSH_ASYNC_PROMPT_LAST_STATUS=$?
# reset prompt state
ZSH_ASYNC_PROMPT_DATA=""
# set prompt status to rendering
ZSH_ASYNC_PROMPT_QUERY_DONE=0
__zle_async_dispatch __zle_async_fd_handler __async_prompt_query
__prompt_rerender
}
#-------------------------------------------------------------------------------
# ZLE Async
#-------------------------------------------------------------------------------
__zle_async_fd_handler() {
# NOTES: For my sanity, and for the curious:
# Nothing in this function should block, if you want to have smooth prompt rendering experience.
local ZLE_FD=$1
# read in all data that is available
if ! IFS=$'\n' read -r ASYNC_RESULT <&"$ZLE_FD"; then
# select marks this fd if we reach EOF,
# so handle this specially.
__zle_async_detach "$ZLE_FD"
ZSH_ASYNC_PROMPT_QUERY_DONE=1
ZSH_ASYNC_PROMPT_DATA="${ZSH_ASYNC_PROMPT_DATA}"$'\n'"${ASYNC_RESULT}"
__prompt_rerender
return 1
fi
ZSH_ASYNC_PROMPT_DATA="${ZSH_ASYNC_PROMPT_DATA}"$'\n'"${ASYNC_RESULT}"
if [[ $ASYNC_RESULT == "" ]]; then
__prompt_rerender
fi
}
__zle_async_dispatch() {
local dispatch_handler="$1"; shift 1
local command=( "$@" )
# Close existing file descriptor for this handler.
local OLD_ZLE_FD=${__ZLE_ASYNC_FDS["${dispatch_handler}"]}
if [[ -n $OLD_ZLE_FD ]]; then
__zle_async_detach "$OLD_ZLE_FD" 2>/dev/null
fi
local ZLE_FD
# Create File Descriptor and attach to async command
exec {ZLE_FD}< <( "${command[@]}" )
# Attach file a ZLE handler to file descriptor.
zle -F $ZLE_FD "${dispatch_handler}"
__ZLE_ASYNC_FDS["${dispatch_handler}"]="$ZLE_FD"
}
__zle_async_detach() {
local ZLE_FD=$1
# Close stdout.
exec {ZLE_FD}<&-
# Close the file-descriptor.
zle -F "$ZLE_FD"
}
#-------------------------------------------------------------------------------
prompt_asynczle_setup() {
zmodload zsh/datetime || :
autoload -Uz +X add-zsh-hook 2>/dev/null
autoload -Uz +X add-zle-hook-widget 2>/dev/null
add-zsh-hook precmd __prompt_precmd
add-zsh-hook preexec __prompt_preexec
zle -N __prompt_rerender
if (( $+functions[add-zle-hook-widget] )); then
add-zle-hook-widget zle-line-finish __prompt_rerender
add-zle-hook-widget zle-keymap-select __prompt_rerender
fi
}
prompt_asynczle_setup "$@"