Noah Wilder
Noah Wilder

Reputation: 1574

ZSH Hangs on Open Application Tab Autocompletion

I frequently open applications on my Mac by using the command open -a <application-name>. I also have been using tab autocompletion more recently to complete my commands. I tried to do this after writing, for example, open -a or open -a Safa, but when I hit tab, zsh hangs and I cannot type anything else in the window. This also does not provide the autocomplete options as it should. I tried this in both Terminal and iTerm2 and the problem persists.

I am using zsh 5.7.1. I also have Oh My Zsh installed on my computer.

Just in case it helps, here is my .zshrc file:

# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH

# Path to your oh-my-zsh installation.
export ZSH="/Users/noahwilder/.oh-my-zsh"

# Set name of the theme to load --- if set to "random", it will
# load a random theme each time oh-my-zsh is loaded, in which case,
# to know which specific one was loaded, run: echo $RANDOM_THEME
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
ZSH_THEME="spaceship"
#"robbyrussell"
#"agnoster"

# Set list of themes to pick from when loading at random
# Setting this variable when ZSH_THEME=random will cause zsh to load
# a theme from this variable instead of looking in ~/.oh-my-zsh/themes/
# If set to an empty array, this variable will have no effect.
# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )

# Uncomment the following line to use case-sensitive completion.
# CASE_SENSITIVE="true"

# Uncomment the following line to use hyphen-insensitive completion.
# Case-sensitive completion must be off. _ and - will be interchangeable.
# HYPHEN_INSENSITIVE="true"

# Uncomment the following line to disable bi-weekly auto-update checks.
# DISABLE_AUTO_UPDATE="true"

# Uncomment the following line to automatically update without prompting.
# DISABLE_UPDATE_PROMPT="true"

# Uncomment the following line to change how often to auto-update (in days).
# export UPDATE_ZSH_DAYS=13

# Uncomment the following line if pasting URLs and other text is messed up.
# DISABLE_MAGIC_FUNCTIONS=true

# Uncomment the following line to disable colors in ls.
# DISABLE_LS_COLORS="true"

# Uncomment the following line to disable auto-setting terminal title.
# DISABLE_AUTO_TITLE="true"

# Uncomment the following line to enable command auto-correction.
# ENABLE_CORRECTION="true"

# Uncomment the following line to display red dots whilst waiting for completion.
# COMPLETION_WAITING_DOTS="true"

# Uncomment the following line if you want to disable marking untracked files
# under VCS as dirty. This makes repository status check for large repositories
# much, much faster.
# DISABLE_UNTRACKED_FILES_DIRTY="true"

# Uncomment the following line if you want to change the command execution time
# stamp shown in the history command output.
# You can set one of the optional three formats:
# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
# or set a custom format using the strftime function format specifications,
# see 'man strftime' for details.
# HIST_STAMPS="mm/dd/yyyy"

# Would you like to use another custom folder than $ZSH/custom?
# ZSH_CUSTOM=/path/to/new-custom-folder

# Which plugins would you like to load?
# Standard plugins can be found in ~/.oh-my-zsh/plugins/*
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(
  git
  zsh-autosuggestions
  zsh-syntax-highlighting
  Z
)

source $ZSH/oh-my-zsh.sh

# User configuration

# export MANPATH="/usr/local/man:$MANPATH"

# You may need to manually set your language environment
# export LANG=en_US.UTF-8

# Preferred editor for local and remote sessions
# if [[ -n $SSH_CONNECTION ]]; then
#   export EDITOR='vim'
# else
#   export EDITOR='mvim'
# fi

# Compilation flags
# export ARCHFLAGS="-arch x86_64"

# Set personal aliases, overriding those provided by oh-my-zsh libs,
# plugins, and themes. Aliases can be placed here, though oh-my-zsh
# users are encouraged to define aliases within the ZSH_CUSTOM folder.
# For a full list of active aliases, run `alias`.
#
# Example aliases
# alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh"

# Other setup
autoload -U compinit && compinit
zmodload -i zsh/complist
eval $(thefuck --alias)
. /usr/local/etc/profile.d/z.sh

#prompt_context(){}

# Spaceship theme:
# 
ZSH_THEME="spaceship"
autoload -U promptinit; promptinit;
prompt spaceship
SPACESHIP_BATTERY_SHOW=false


# Use Pure theme:
#
# autoload -U promptinit; promptinit
# prompt pure

# This speeds up pasting w/ autosuggest
# https://github.com/zsh-users/zsh-autosuggestions/issues/238
pasteinit() {
  OLD_SELF_INSERT=${${(s.:.)widgets[self-insert]}[2,3]}
  zle -N self-insert url-quote-magic # I wonder if you'd need `.url-quote-magic`?
}

pastefinish() {
  zle -N self-insert $OLD_SELF_INSERT
}
zstyle :bracketed-paste-magic paste-init pasteinit
zstyle :bracketed-paste-magic paste-finish pastefinish

How do I fix this and enable autocompletion for opening applications with zsh, as is available everywhere else in zsh?

Upvotes: 7

Views: 3800

Answers (1)

Chris
Chris

Reputation: 3344

This is actually a macOS bug! The problem is in Apple's own open compdef completion script.

In the past open -a completion was fast because the autocomplete script used the Spotlight index for super fast application fetching. You can find the relevant script here: /usr/share/zsh/5.7.1/functions/_retrieve_mac_apps (referenced from the _open script in the same directory)

However, to check if a Spotlight search index exists, it looks to see if the file /.Spotlight-V100 exists. In some macOS update the Spotlight index for user files was moved here: /System/Volumes/Data/.Spotlight-V100 but the autocomplete script wasn't updated! When it thinks no Spotlight index exists it falls back to a very slow manual application listing.

Specifically the bug is this check:

...
      if [[ -d /.Spotlight-V100 ]]; then
        # / is indexed to use Spotlight
         retrieve=_mac_apps_spotlight_retrieve
       else
         # Fall back to the old way
         retrieve=_mac_apps_old_retrieve
       fi
       zstyle ":completion:*:*:${service}:commands" search-method $retrieve

The slow implementation then does this arcane shell-fu. When experimenting it seems to hang forever for me.

 _mac_apps_old_retrieve () {
   # Get directories which may contain applications
   typeset -aU app_dir
   if [[ -z "$app_dir" ]] && \
     ! zstyle -a ":completion:${curcontext}:commands" application-dir app_dir
   then
     typeset -a app_dir_stop_pattern
     app_dir_stop_pattern=( "*.app" "contents#" "*data" "*plugins#" "*plug?ins#" "fonts#" "document[[:alpha:]]#" "*help" "resources#" "images#" "*configurations#" )
     typeset app_dir_pattern
     app_dir_pattern="(^(#i)(${(j/|/)app_dir_stop_pattern}))"
     app_dir=( ${^app_dir_root}/(${~app_dir_pattern}/)#(N) )
   fi
...

Sadly, since this bug is part of macOS itself, the file is protected by System Integrity Protection so it's very annoying to fix. You can copy it though, fix the bug, and replace open's compdef with your fixed version. Here's hoping Apple finally fixes this in Big Sur!

EDIT: Here's a gist that fixes the issue and has some instructions for how to install it: https://gist.github.com/varenc/d2c09c3ad5939774001c32fe5f7df41f

Also for reference Apple did not fix this issue in Big Sur or Monterey. 😑

Upvotes: 7

Related Questions