Making Emacs ansi-term and zsh play nice together

Providing a solution to a common problem encountered when using zsh from inside emacs using *ansi-term*

This is a quick post to document a solution to a problem I have had today and for which no solution was found online. A little background first. I normally use x-term for all my terminal needs but since I am a heavy Emacs user I have also occasionally used emacs as a terminal emulator. In an effort to go even further towards Emacs integration I have been toying with Emacs *ansi-term* which seems to be the most fully functional terminal emulator inside emacs.

Unfortunately since I am using the z-shell, just like some other people ansi-term seemed to be echoing each command back to the buffer in between some numerical characters.

ansi-term and zsh not playing nice

As you can see from the screenshot above, surely enough we do get the exact behavior that people in the above linked pages mention. Their suggestion was to simply give up and change to a simpler shell emulator just like M-x shell

But this is not a proper solution. We have to figure out the root cause of the problem and decipher what the echoing and those strange numbers mean. We are in luck since behavior from a terminal like this possibly means that something is trying to set the title of the terminal window. Since *ansi-term* does not know how to interpret this command it simply echoes it back.

If you are like me and started using zsh in the past by cloning an initial pre-configured setup like prezto or ohmyzsh then this would be the place to look for the root of the problem. I personally use prezto and if you go to prezto/modules/terminal/init.zsh there you will see a zsh function that actually attempts to set the terminal window title after each command.

# Sets the tab and window titles with a given command.
function _terminal-set-titles-with-command {
  emulate -L zsh
  # Get the command name that is under job control.
  if [[ "${2[(w)1]}" == (fg|%*)(\;|) ]]; then
    # Get the job name, and, if missing, set it to the default %+.
    local job_name="${${2[(wr)%*(\;|)]}:-%+}"
    # Make a local copy for use in the subshell.
    local -A jobtexts_from_parent_shell
    jobs "$job_name" 2>/dev/null > >(
      read index discarded
      # The index is already surrounded by brackets: [1].
      _terminal-set-titles-with-command "${(e):-\$jobtexts_from_parent_shell$index}"
    # Set the command name, or in the case of sudo or ssh, the next command.
    local cmd="${${2[(wr)^(*=*|sudo|ssh|-*)]}:t}"
    local truncated_cmd="${cmd/(#m)?(#c15,)/${MATCH[1,12]}...}"
    unset MATCH
    set-window-title "$cmd"
    set-tab-title "$truncated_cmd"

Rings any bell? Yep you are right! Our zsh setup is simply too smart for *ansi-term*. But I don’t know a lot about zsh functions and stuff you say? How do I fix it? Easy enough! At the bottom of the aforementioned file there is a conditional check that allows us a clean and easy way to customize the behavior of the module for our emacs *ansi-term*.

# Set up non-Apple terminals.
if zstyle -t ':prezto:module:terminal' auto-title \
  && ( ! [[ -n "$STY" || -n "$TMUX" ]] )
# Sets the tab and window titles before the prompt is displayed.
add-zsh-hook precmd _terminal-set-titles-with-path
# Sets the tab and window titles before command execution.
add-zsh-hook preexec _terminal-set-titles-with-command

What this means is that with the usage of the zstyle command you can add this to the bottom of your .zshrc, or right after all the prezto setup has finished.

if [[ -n ${EMACS} ]]; then
    zstyle ':prezto:module:terminal' auto-title 'no'

Once that is done, the title of the window will be set before the prompt is displayed and as such *ansi-term* will not be echoing anything back to us.

Hope the above helped other people who have found the same annoying problem as me while using zsh and the emacs terminal emulator. If you are using emacs and ohmyzsh I can’t provide more detailed advice but use ack or grep to search for similar implementation of window title setting as I showed that prezto has above. Then proceed to circumvent it only for *ansi-term* by checking for the $EMACS environment variable.

That’s all. Till next time!

Pass your certification test from the first try!
70-534 questionsAll latest IT exams study materials, exam questions and answers.
pmp bookSave money on your next certification exam by using an exam voucher!
70-346 exam questions|Cisco Cert Saving Pack Sap Cert Saving Pack Novel Cert Saving Pack IBM Cert Saving Pack More
300-206 dumpsOne Year Unlimited Access * Interactive Exam Engines(Testing Software) * Questions & Answers with Explanations
cism dumps|Technology Association certification validates the fundamental knowledge needed to begin building a career in technology.
CQA dumpsA lot of questions (~140 questions currently) for you to review and power up your IT management and operation skills
70-534 questionsSpecializing in IT Certifications Exam Vouchers for CompTIA and Microsoft products.
CQA dumps|STEP 1 – EXAMS. Pass 1 exam to earn an MTA certification. Be sure to explore the exam prep resources.
300-101 practice test|Find the Microsoft Certification exams you need to highlight your skills and further your career. Explore our newest exam list.
810-403 practice
Best IT certifications questions and answers
300-075 pdfReal World IT Labs and Training. Discount 80k+ students, 6000 reviews, 24 courses
200-125 questionsICND1, CCNA, CCNA Sec, Labs, Microsoft MTA… Join now! Browse my courses on Udemy and get 25% off.
400-101 pdfDownload VCE Practice Questions Answers. Latest updated materials, Daily Updates.
200-125 examNo.1 IT certification dumps provider of Cisco, Microsoft, CompTIA, VMware, Oracle certification exams.
300-101 exam
300-135 PdfPass your certification test from the first try!
300-075 exam|
300-115 pdfBest IT certifications questions and answers

2 thoughts on “Making Emacs ansi-term and zsh play nice together”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.