annotate .zfun/async @ 425:d0a5109cdfe2

custom: disable magit-auto-revert-mode This seems to interact poorly with global-auto-revert mode and tramp, so just drop it for now.
author Augie Fackler <raf@durin42.com>
date Tue, 29 Nov 2016 13:35:42 -0500
parents e84b6da69ea0
children d3d52766cfcd
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
381
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
1 #!/usr/bin/env zsh
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
2
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
3 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
4 # zsh-async
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
5 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
6 # version: 1.1.0
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
7 # author: Mathias Fredriksson
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
8 # url: https://github.com/mafredri/zsh-async
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
9 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
10
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
11 # Wrapper for jobs executed by the async worker, gives output in parseable format with execution time
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
12 _async_job() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
13 # Store start time as double precision (+E disables scientific notation)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
14 float -F duration=$EPOCHREALTIME
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
15
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
16 # Run the command
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
17 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
18 # What is happening here is that we are assigning stdout, stderr and ret to
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
19 # variables, and then we are printing out the variable assignment through
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
20 # typeset -p. This way when we run eval we get something along the lines of:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
21 # eval "
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
22 # typeset stdout=' M async.test.sh\n M async.zsh'
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
23 # typeset ret=0
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
24 # typeset stderr=''
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
25 # "
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
26 unset stdout stderr ret
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
27 eval "$(
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
28 {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
29 stdout=$(eval "$@")
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
30 ret=$?
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
31 typeset -p stdout ret
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
32 } 2> >(stderr=$(cat); typeset -p stderr)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
33 )"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
34
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
35 # Calculate duration
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
36 duration=$(( EPOCHREALTIME - duration ))
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
37
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
38 # stip all null-characters from stdout and stderr
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
39 stdout=${stdout//$'\0'/}
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
40 stderr=${stderr//$'\0'/}
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
41
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
42 # if ret is missing for some unknown reason, set it to -1 to indicate we
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
43 # have run into a bug
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
44 ret=${ret:--1}
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
45
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
46 # Grab mutex lock
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
47 read -ep >/dev/null
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
48
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
49 # return output (<job_name> <return_code> <stdout> <duration> <stderr>)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
50 print -r -N -n -- "$1" "$ret" "$stdout" "$duration" "$stderr"$'\0'
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
51
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
52 # Unlock mutex
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
53 print -p "t"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
54 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
55
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
56 # The background worker manages all tasks and runs them without interfering with other processes
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
57 _async_worker() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
58 local -A storage
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
59 local unique=0
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
60
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
61 # Process option parameters passed to worker
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
62 while getopts "np:u" opt; do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
63 case $opt in
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
64 # Use SIGWINCH since many others seem to cause zsh to freeze, e.g. ALRM, INFO, etc.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
65 n) trap 'kill -WINCH $ASYNC_WORKER_PARENT_PID' CHLD;;
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
66 p) ASYNC_WORKER_PARENT_PID=$OPTARG;;
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
67 u) unique=1;;
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
68 esac
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
69 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
70
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
71 # Create a mutex for writing to the terminal through coproc
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
72 coproc cat
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
73 # Insert token into coproc
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
74 print -p "t"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
75
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
76 while read -r cmd; do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
77 # Separate on spaces into an array
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
78 cmd=(${=cmd})
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
79 local job=$cmd[1]
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
80
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
81 # Check for non-job commands sent to worker
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
82 case $job in
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
83 _unset_trap)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
84 trap - CHLD; continue;;
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
85 _killjobs)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
86 # Do nothing in the worker when receiving the TERM signal
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
87 trap '' TERM
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
88 # Send TERM to the entire process group (PID and all children)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
89 kill -TERM -$$ &>/dev/null
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
90 # Reset trap
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
91 trap - TERM
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
92 continue
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
93 ;;
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
94 esac
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
95
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
96 # If worker should perform unique jobs
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
97 if (( unique )); then
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
98 # Check if a previous job is still running, if yes, let it finnish
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
99 for pid in ${${(v)jobstates##*:*:}%\=*}; do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
100 if [[ ${storage[$job]} == $pid ]]; then
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
101 continue 2
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
102 fi
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
103 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
104 fi
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
105
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
106 # Run task in background
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
107 _async_job $cmd &
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
108 # Store pid because zsh job manager is extremely unflexible (show jobname as non-unique '$job')...
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
109 storage[$job]=$!
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
110 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
111 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
112
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
113 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
114 # Get results from finnished jobs and pass it to the to callback function. This is the only way to reliably return the
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
115 # job name, return code, output and execution time and with minimal effort.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
116 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
117 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
118 # async_process_results <worker_name> <callback_function>
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
119 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
120 # callback_function is called with the following parameters:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
121 # $1 = job name, e.g. the function passed to async_job
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
122 # $2 = return code
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
123 # $3 = resulting stdout from execution
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
124 # $4 = execution time, floating point e.g. 2.05 seconds
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
125 # $5 = resulting stderr from execution
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
126 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
127 async_process_results() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
128 setopt localoptions noshwordsplit
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
129
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
130 integer count=0
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
131 local worker=$1
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
132 local callback=$2
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
133 local -a items
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
134 local IFS=$'\0'
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
135
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
136 typeset -gA ASYNC_PROCESS_BUFFER
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
137 # Read output from zpty and parse it if available
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
138 while zpty -rt $worker line 2>/dev/null; do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
139 # Remove unwanted \r from output
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
140 ASYNC_PROCESS_BUFFER[$worker]+=${line//$'\r'$'\n'/$'\n'}
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
141 # Split buffer on null characters, preserve empty elements
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
142 items=("${(@)=ASYNC_PROCESS_BUFFER[$worker]}")
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
143 # Remove last element since it's due to the return string separator structure
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
144 items=("${(@)items[1,${#items}-1]}")
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
145
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
146 # Continue until we receive all information
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
147 (( ${#items} % 5 )) && continue
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
148
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
149 # Work through all results
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
150 while (( ${#items} > 0 )); do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
151 $callback "${(@)=items[1,5]}"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
152 shift 5 items
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
153 count+=1
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
154 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
155
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
156 # Empty the buffer
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
157 unset "ASYNC_PROCESS_BUFFER[$worker]"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
158 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
159
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
160 # If we processed any results, return success
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
161 (( count )) && return 0
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
162
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
163 # No results were processed
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
164 return 1
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
165 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
166
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
167 # Watch worker for output
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
168 _async_zle_watcher() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
169 setopt localoptions noshwordsplit
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
170 typeset -gA ASYNC_PTYS ASYNC_CALLBACKS
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
171 local worker=$ASYNC_PTYS[$1]
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
172 local callback=$ASYNC_CALLBACKS[$worker]
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
173
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
174 if [[ -n $callback ]]; then
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
175 async_process_results $worker $callback
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
176 fi
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
177 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
178
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
179 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
180 # Start a new asynchronous job on specified worker, assumes the worker is running.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
181 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
182 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
183 # async_job <worker_name> <my_function> [<function_params>]
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
184 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
185 async_job() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
186 setopt localoptions noshwordsplit
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
187
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
188 local worker=$1; shift
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
189 zpty -w $worker $@
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
190 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
191
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
192 # This function traps notification signals and calls all registered callbacks
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
193 _async_notify_trap() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
194 setopt localoptions noshwordsplit
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
195
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
196 for k in ${(k)ASYNC_CALLBACKS}; do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
197 async_process_results $k ${ASYNC_CALLBACKS[$k]}
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
198 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
199 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
200
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
201 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
202 # Register a callback for completed jobs. As soon as a job is finnished, async_process_results will be called with the
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
203 # specified callback function. This requires that a worker is initialized with the -n (notify) option.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
204 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
205 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
206 # async_register_callback <worker_name> <callback_function>
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
207 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
208 async_register_callback() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
209 setopt localoptions noshwordsplit nolocaltraps
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
210
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
211 typeset -gA ASYNC_CALLBACKS
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
212 local worker=$1; shift
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
213
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
214 ASYNC_CALLBACKS[$worker]="$*"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
215
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
216 if (( ! ASYNC_USE_ZLE_HANDLER )); then
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
217 trap '_async_notify_trap' WINCH
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
218 fi
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
219 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
220
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
221 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
222 # Unregister the callback for a specific worker.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
223 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
224 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
225 # async_unregister_callback <worker_name>
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
226 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
227 async_unregister_callback() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
228 typeset -gA ASYNC_CALLBACKS
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
229
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
230 unset "ASYNC_CALLBACKS[$1]"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
231 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
232
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
233 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
234 # Flush all current jobs running on a worker. This will terminate any and all running processes under the worker, use
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
235 # with caution.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
236 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
237 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
238 # async_flush_jobs <worker_name>
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
239 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
240 async_flush_jobs() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
241 setopt localoptions noshwordsplit
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
242
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
243 local worker=$1; shift
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
244
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
245 # Check if the worker exists
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
246 zpty -t $worker &>/dev/null || return 1
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
247
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
248 # Send kill command to worker
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
249 zpty -w $worker "_killjobs"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
250
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
251 # Clear all output buffers
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
252 while zpty -r $worker line; do true; done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
253
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
254 # Clear any partial buffers
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
255 typeset -gA ASYNC_PROCESS_BUFFER
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
256 unset "ASYNC_PROCESS_BUFFER[$worker]"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
257 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
258
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
259 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
260 # Start a new async worker with optional parameters, a worker can be told to only run unique tasks and to notify a
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
261 # process when tasks are complete.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
262 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
263 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
264 # async_start_worker <worker_name> [-u] [-n] [-p <pid>]
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
265 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
266 # opts:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
267 # -u unique (only unique job names can run)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
268 # -n notify through SIGWINCH signal
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
269 # -p pid to notify (defaults to current pid)
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
270 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
271 async_start_worker() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
272 setopt localoptions noshwordsplit
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
273
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
274 local worker=$1; shift
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
275 zpty -t $worker &>/dev/null && return
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
276
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
277 typeset -gA ASYNC_PTYS
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
278 typeset -h REPLY
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
279 zpty -b $worker _async_worker -p $$ $@ || {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
280 async_stop_worker $worker
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
281 return 1
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
282 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
283
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
284 if (( ASYNC_USE_ZLE_HANDLER )); then
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
285 ASYNC_PTYS[$REPLY]=$worker
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
286 zle -F $REPLY _async_zle_watcher
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
287
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
288 # If worker was called with -n, disable trap in favor of zle handler
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
289 async_job $worker _unset_trap
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
290 fi
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
291 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
292
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
293 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
294 # Stop one or multiple workers that are running, all unfetched and incomplete work will be lost.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
295 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
296 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
297 # async_stop_worker <worker_name_1> [<worker_name_2>]
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
298 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
299 async_stop_worker() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
300 setopt localoptions noshwordsplit
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
301
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
302 local ret=0
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
303 for worker in $@; do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
304 # Find and unregister the zle handler for the worker
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
305 for k v in ${(@kv)ASYNC_PTYS}; do
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
306 if [[ $v == $worker ]]; then
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
307 zle -F $k
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
308 unset "ASYNC_PTYS[$k]"
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
309 fi
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
310 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
311 async_unregister_callback $worker
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
312 zpty -d $worker 2>/dev/null || ret=$?
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
313 done
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
314
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
315 return $ret
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
316 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
317
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
318 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
319 # Initialize the required modules for zsh-async. To be called before using the zsh-async library.
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
320 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
321 # usage:
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
322 # async_init
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
323 #
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
324 async_init() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
325 (( ASYNC_INIT_DONE )) && return
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
326 ASYNC_INIT_DONE=1
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
327
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
328 zmodload zsh/zpty
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
329 zmodload zsh/datetime
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
330
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
331 # Check if zsh/zpty returns a file descriptor or not, shell must also be interactive
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
332 ASYNC_USE_ZLE_HANDLER=0
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
333 [[ -o interactive ]] && {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
334 typeset -h REPLY
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
335 zpty _async_test cat
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
336 (( REPLY )) && ASYNC_USE_ZLE_HANDLER=1
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
337 zpty -d _async_test
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
338 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
339 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
340
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
341 async() {
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
342 async_init
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
343 }
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
344
e84b6da69ea0 async.zsh: import
Augie Fackler <raf@durin42.com>
parents:
diff changeset
345 async "$@"