Skip to content

Commit

Permalink
Clear async global variables on successful response
Browse files Browse the repository at this point in the history
If _ZSH_AUTOSUGGEST_ASYNC_FD is not cleared, something else may open the
file descriptor pointed to by it. And then the next call into
_zsh_autosuggest_async_request will close it causing trouble.

It seems like good practice to clean up _ZSH_AUTOSUGGEST_CHILD_PID as
well, though it's not directly causing any known problems at the moment.

I was able to produce errors with ZSH_AUTOSUGGEST_MANUAL_REBIND active
and sourcing a file async-widget-setup.zsh after the first precmd with
the plugin active. If manual rebind is not active or if the widgets are
created before the first precmd, then zsh-autosuggestions wraps the
widgets and for some reason we don't seem to get any fd conflicts.

The .zshrc:

```
ZSH_AUTOSUGGEST_MANUAL_REBIND=true
source zsh-autosuggestions.zsh
```

and async-widget-setup.zsh:

```
function async-widget-fork() {
	exec {fd}< <(echo foo)
	zle -M "opened: $fd, autosuggest fd: $_ZSH_AUTOSUGGEST_ASYNC_FD"
}

function async-widget-read() {
	zle -M "reading from $fd: $(cat <&$fd)"
}

zle -N async-widget-fork
zle -N async-widget-read

bindkey ^A async-widget-fork
bindkey ^B async-widget-read
```

Then run `ZDOTDIR=$PWD zsh` and run `source async-widget-setup.zsh`. At
the next prompt, type one character e.g. "a" to trigger an async
request/response cycle. This leaves _ZSH_AUTOSUGGEST_ASYNC_FD set to the
stale file descriptor number. Then press ^A to activate the fork. This
will set the fd parameter to the same number as
_ZSH_AUTOSUGGEST_ASYNC_FD. Then type another character e.g. "a" to
trigger an async request. This will print a "No handler installed" error
and close the file descriptor pointed to by both
_ZSH_AUTOSUGGEST_ASYNC_FD and fd. Pressing ^B at this point will fail to
read with a "bad file descriptor" error.
  • Loading branch information
ericfreese committed Aug 26, 2023
1 parent 61257de commit 3391962
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/async.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ _zsh_autosuggest_async_request() {
_zsh_autosuggest_async_response() {
emulate -L zsh

typeset -g _ZSH_AUTOSUGGEST_ASYNC_FD _ZSH_AUTOSUGGEST_CHILD_PID
local suggestion

if [[ $# == 1 || "$2" == "hup" ]]; then
Expand All @@ -67,6 +68,8 @@ _zsh_autosuggest_async_response() {

# Close the fd
exec {1}<&-
_ZSH_AUTOSUGGEST_ASYNC_FD=
_ZSH_AUTOSUGGEST_ASYNC_PID=
fi

# Always remove the handler
Expand Down
3 changes: 3 additions & 0 deletions zsh-autosuggestions.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ _zsh_autosuggest_async_request() {
_zsh_autosuggest_async_response() {
emulate -L zsh

typeset -g _ZSH_AUTOSUGGEST_ASYNC_FD _ZSH_AUTOSUGGEST_CHILD_PID
local suggestion

if [[ $# == 1 || "$2" == "hup" ]]; then
Expand All @@ -822,6 +823,8 @@ _zsh_autosuggest_async_response() {

# Close the fd
exec {1}<&-
_ZSH_AUTOSUGGEST_ASYNC_FD=
_ZSH_AUTOSUGGEST_ASYNC_PID=
fi

# Always remove the handler
Expand Down

0 comments on commit 3391962

Please sign in to comment.