When a completion function takes a long time, I can interrupt it by pressing Ctrl+C (terminal interrupt key, sends SIGINT) or Ctrl+G (bound to send-break
). I am then left with the uncompleted word.
However, if I happen to hit Ctrl+C or Ctrl+G just as the completion function finishes, my key press may cancel the command line and give me a fresh prompt instead of cancelling the completion.
How can I set up zsh so that a certain key will cancel an ongoing completion but do nothing if no completion function is active?
2 Answers 2
Here's a solution that sets up a SIGINT handler that makes Ctrl+C only interrupt when completion is active.
# A completer widget that sets a flag for the duration of
# the completion so the SIGINT handler knows whether completion
# is active. It would be better if we could check some internal
# zsh parameter to determine if completion is running, but as
# far as I'm aware that isn't possible.
function interruptible-expand-or-complete {
COMPLETION_ACTIVE=1
# Bonus feature: automatically interrupt completion
# after a three second timeout.
# ( sleep 3; kill -INT $$ ) &!
zle expand-or-complete
COMPLETION_ACTIVE=0
}
# Bind our completer widget to tab.
zle -N interruptible-expand-or-complete
bindkey '^I' interruptible-expand-or-complete
# Interrupt only if completion is active.
function TRAPINT {
if [[ $COMPLETION_ACTIVE == 1 ]]; then
COMPLETION_ACTIVE=0
zle -M "Completion canceled."
# Returning non-zero tells zsh to handle SIGINT,
# which will interrupt the completion function.
return 1
else
# Returning zero tells zsh that we handled SIGINT;
# don't interrupt whatever is currently running.
return 0
fi
}
I don't know if this is an acceptable solution or not, but sending a SIGSTOP (Ctrl+S) seems to have the desired effect, with the added benefit that you can start up the autocomplete again if you send a SIGSTART (Ctrl+Q) before typing anything else. I'm not an expert on job control though, so this may leave some additional clutter related to the stopped job.
-
1Ctrl+S and Ctrl+Q are flow control commands. They only affect output to the terminal, which is irrelevant here. Predictably, Ctrl+S has no effect during completion (zsh disables the terminal setting anyway, it grabs the key combination). Pressing Ctrl+Z (which sends SIGTOP) has no effect either.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2013年09月25日 19:40:13 +00:00Commented Sep 25, 2013 at 19:40
-
Thanks! I wasn't entirely sure what was going on in the background. All I saw was that I got control of the terminal back.Aaron Okano– Aaron Okano2013年09月26日 02:21:07 +00:00Commented Sep 26, 2013 at 2:21