13

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?

5

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
}
0

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.

  • 1
    Ctrl+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 Sep 25 '13 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 Sep 26 '13 at 2:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.