|
3 | 3 | # Async #
|
4 | 4 | #--------------------------------------------------------------------#
|
5 | 5 |
|
6 |
| -# Zpty process is spawned running this function |
7 |
| -_zsh_autosuggest_async_server() { |
8 |
| - emulate -R zsh |
| 6 | +zmodload zsh/system |
9 | 7 |
|
10 |
| - # There is a bug in zpty module (fixed in zsh/master) by which a |
11 |
| - # zpty that exits will kill all zpty processes that were forked |
12 |
| - # before it. Here we set up a zsh exit hook to SIGKILL the zpty |
13 |
| - # process immediately, before it has a chance to kill any other |
14 |
| - # zpty processes. |
15 |
| - zshexit() { |
16 |
| - kill -KILL $$ |
17 |
| - sleep 1 # Block for long enough for the signal to come through |
18 |
| - } |
19 |
| - |
20 |
| - # Don't add any extra carriage returns |
21 |
| - stty -onlcr |
22 |
| - |
23 |
| - # Don't translate carriage returns to newlines |
24 |
| - stty -icrnl |
25 |
| - |
26 |
| - # Silence any error messages |
27 |
| - exec 2>/dev/null |
| 8 | +_zsh_autosuggest_async_request() { |
| 9 | + typeset -g _ZSH_AUTOSUGGEST_ASYNC_FD _ZSH_AUTOSUGGEST_CHILD_PID |
| 10 | + |
| 11 | + # If we've got a pending request, cancel it |
| 12 | + if [[ -n "$_ZSH_AUTOSUGGEST_ASYNC_FD" ]] && { true <&$_ZSH_AUTOSUGGEST_ASYNC_FD } 2>/dev/null; then |
| 13 | + # Close the file descriptor and remove the handler |
| 14 | + exec {_ZSH_AUTOSUGGEST_ASYNC_FD}<&- |
| 15 | + zle -F $_ZSH_AUTOSUGGEST_ASYNC_FD |
| 16 | + |
| 17 | + # Zsh will make a new process group for the child process only if job |
| 18 | + # control is enabled (MONITOR option) |
| 19 | + if [[ -o MONITOR ]]; then |
| 20 | + # Send the signal to the process group to kill any processes that may |
| 21 | + # have been forked by the suggestion strategy |
| 22 | + kill -TERM -$_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null |
| 23 | + else |
| 24 | + # Kill just the child process since it wasn't placed in a new process |
| 25 | + # group. If the suggestion strategy forked any child processes they may |
| 26 | + # be orphaned and left behind. |
| 27 | + kill -TERM $_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null |
| 28 | + fi |
| 29 | + fi |
28 | 30 |
|
29 |
| - local last_pid |
| 31 | + # Fork a process to fetch a suggestion and open a pipe to read from it |
| 32 | + exec {_ZSH_AUTOSUGGEST_ASYNC_FD}< <( |
| 33 | + # Tell parent process our pid |
| 34 | + echo $sysparams[pid] |
30 | 35 |
|
31 |
| - while IFS='' read -r -d $'\0' query; do |
32 |
| - # Kill last bg process |
33 |
| - kill -KILL $last_pid &>/dev/null |
| 36 | + # Fetch and print the suggestion |
| 37 | + local suggestion |
| 38 | + _zsh_autosuggest_fetch_suggestion "$1" |
| 39 | + echo -nE "$suggestion" |
| 40 | + ) |
34 | 41 |
|
35 |
| - # Run suggestion search in the background |
36 |
| - ( |
37 |
| - local suggestion |
38 |
| - _zsh_autosuggest_fetch_suggestion "$query" |
39 |
| - echo -n -E "$suggestion"$'\0' |
40 |
| - ) & |
| 42 | + # There's a weird bug here where ^C stops working unless we force a fork |
| 43 | + # See https://github.com/zsh-users/zsh-autosuggestions/issues/364 |
| 44 | + command true |
41 | 45 |
|
42 |
| - last_pid=$! |
43 |
| - done |
44 |
| -} |
| 46 | + # Read the pid from the child process |
| 47 | + read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD |
45 | 48 |
|
46 |
| -_zsh_autosuggest_async_request() { |
47 |
| - # Write the query to the zpty process to fetch a suggestion |
48 |
| - zpty -w -n $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME "${1}"$'\0' |
| 49 | + # When the fd is readable, call the response handler |
| 50 | + zle -F "$_ZSH_AUTOSUGGEST_ASYNC_FD" _zsh_autosuggest_async_response |
49 | 51 | }
|
50 | 52 |
|
51 |
| -# Called when new data is ready to be read from the pty |
| 53 | +# Called when new data is ready to be read from the pipe |
52 | 54 | # First arg will be fd ready for reading
|
53 | 55 | # Second arg will be passed in case of error
|
54 | 56 | _zsh_autosuggest_async_response() {
|
55 |
| - setopt LOCAL_OPTIONS EXTENDED_GLOB |
56 |
| - |
57 |
| - local suggestion |
58 |
| - |
59 |
| - zpty -rt $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME suggestion '*'$'\0' 2>/dev/null |
60 |
| - zle autosuggest-suggest -- "${suggestion%%$'\0'##}" |
61 |
| -} |
62 |
| - |
63 |
| -_zsh_autosuggest_async_pty_create() { |
64 |
| - # With newer versions of zsh, REPLY stores the fd to read from |
65 |
| - typeset -h REPLY |
| 57 | + if [[ -z "$2" || "$2" == "hup" ]]; then |
| 58 | + # Read everything from the fd and give it as a suggestion |
| 59 | + zle autosuggest-suggest -- "$(cat <&$1)" |
66 | 60 |
|
67 |
| - # If we won't get a fd back from zpty, try to guess it |
68 |
| - if (( ! $_ZSH_AUTOSUGGEST_ZPTY_RETURNS_FD )); then |
69 |
| - integer -l zptyfd |
70 |
| - exec {zptyfd}>&1 # Open a new file descriptor (above 10). |
71 |
| - exec {zptyfd}>&- # Close it so it's free to be used by zpty. |
| 61 | + # Close the fd |
| 62 | + exec {1}<&- |
72 | 63 | fi
|
73 | 64 |
|
74 |
| - # Fork a zpty process running the server function |
75 |
| - zpty -b $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME _zsh_autosuggest_async_server |
76 |
| - |
77 |
| - # Store the fd so we can remove the handler later |
78 |
| - if (( REPLY )); then |
79 |
| - _ZSH_AUTOSUGGEST_PTY_FD=$REPLY |
80 |
| - else |
81 |
| - _ZSH_AUTOSUGGEST_PTY_FD=$zptyfd |
82 |
| - fi |
83 |
| - |
84 |
| - # Set up input handler from the zpty |
85 |
| - zle -F $_ZSH_AUTOSUGGEST_PTY_FD _zsh_autosuggest_async_response |
86 |
| -} |
87 |
| - |
88 |
| -_zsh_autosuggest_async_pty_destroy() { |
89 |
| - # Remove the input handler |
90 |
| - zle -F $_ZSH_AUTOSUGGEST_PTY_FD &>/dev/null |
91 |
| - |
92 |
| - # Destroy the zpty |
93 |
| - zpty -d $ZSH_AUTOSUGGEST_ASYNC_PTY_NAME &>/dev/null |
94 |
| -} |
95 |
| - |
96 |
| -_zsh_autosuggest_async_pty_recreate() { |
97 |
| - _zsh_autosuggest_async_pty_destroy |
98 |
| - _zsh_autosuggest_async_pty_create |
99 |
| -} |
100 |
| - |
101 |
| -_zsh_autosuggest_async_start() { |
102 |
| - typeset -g _ZSH_AUTOSUGGEST_PTY_FD |
103 |
| - |
104 |
| - _zsh_autosuggest_feature_detect_zpty_returns_fd |
105 |
| - _zsh_autosuggest_async_pty_recreate |
106 |
| - |
107 |
| - # We recreate the pty to get a fresh list of history events |
108 |
| - add-zsh-hook precmd _zsh_autosuggest_async_pty_recreate |
| 65 | + # Always remove the handler |
| 66 | + zle -F "$1" |
109 | 67 | }
|
0 commit comments