Connecting to macOS with Emacs Tramp via ssh

November 13th, 2022

If one tries to connect to a macOS machine with Emacs Tramp via ssh, Emacs always hangs without ever connecting. This was bugging me for quite a while; I had to go out and open a separate Terminal window outside Emacs to do things.

After a (setq tramp-verbose 6) and a re-connection attempt via Tramp, it looked like Tramp was having a hard time finding the shell prompt from the output, because the prompt was littered with control characters.

17:03:07.303779 tramp-process-one-action (5) # Looking for regexp "\(\(?:^\|^M\)[^]#$%>
]*#?[]#$%>] *\(^[\[[[:digit:];]*[[:alpha:]] *\)*\)\'" from remote shell
17:03:07.303812 tramp-process-one-action (5) # Looking for regexp "\(\(Are you sure you want to continue connecting (yes/no\(?:\(?:/\[fingerprint]\)?)\?\)\)\s-*\)\'" from remote shell
17:03:07.303839 tramp-process-one-action (5) # Looking for regexp "\(\(\(?:Store key in cache\? (y/\|Update cached key\? (y/n, Return cancels connectio\)n)\)\s-*\)\'" from remote shell
17:03:07.306464 tramp-process-one-action (5) # Looking for regexp "\(\(TERM = (.*)\|Terminal type\? \[.*\]\)\s-*\)\'" from remote shell
17:03:07.306512 tramp-process-one-action (5) # Looking for regexp "\(Access granted\. Press Return to begin session\. \)\'" from remote shell
17:03:07.306539 tramp-process-one-action (5) # Looking for regexp "\(^^M*Confirm user presence for key .*[^M
]*\)\'" from remote shell
17:03:07.306564 tramp-process-one-action (5) # Looking for regexp "\(\)\'" from remote shell
17:03:07.306588 tramp-process-one-action (5) # Call ‘tramp-action-process-alive’
17:03:07.306653 tramp-accept-process-output (1) # Quit: "Quit", ""
%                                                                              ^M ^M^Msungbin@sungbin-mbp13 ~ % ^[[?2004h
17:03:07.306693 tramp-accept-process-output (1) # Quit: "Quit", ""
%                                                                              ^M ^M^Msungbin@sungbin-mbp13 ~ % ^[[?2004h

I first thought that this was due to my config not respecting the TERM env variable, but I’ve seen that ^[[?2004 escape before and searched for it… and it turns out this is because zsh activates bracketed paste for dumb terminals as well! It’s explained in the article Zsh 5.1 and bracketed paste.

Essentially the fix (also mentioned in the article) is to add this snippet to .zshrc:

if [[ $TERM == "dumb" ]]; then
  unset zle_bracketed_paste
else
  autoload -Uz bracketed-paste-magic
  zle -N bracketed-paste-magic
fi