Emacs ansi-term tricks

December 26, 2008 at 11:30 AM | categories: emacs | View Comments

Being on vacation is soo nice. With some of my free time I'm planning on revamping my emacs environment, so hopefully that means a few more articles showing up here on that topic.

I read some great tips on ansi-term. Ansi-term is a terminal emulator written in emacs lisp that is as close to a real terminal as possible. That means you can run virtually all command line programs, even the ones that use ncurses like top or screen, all within emacs. You can still switch between line and char modes which means you can still edit the buffer as you could in a regular (emacs) shell too.

F2 Keybinding

In the above mentioned article Joseph wrote a nice little bit of elisp to get to a running ansi-term efficiently, by hitting F2. The nice thing about it is that it does what I mean:

  1. If I'm already in an ansi-term, but it's called "*ansi-term*" rename it.
  2. If I'm already in an ansi-term, but it's called something else, start a new ansi-term called "*ansi-term*"
  3. If I'm in another non-terminal buffer, switch to a buffer called "*ansi-term*" or create a new one if it doesn't exist

There's one more catch though, as Joseph explains, an ansi-term can be considered "stopped" such that it is no longer running but the buffer still exists. In that case I don't want the third rule to switch me to a defunct terminal, so instead I want it to kill the buffer and create a new ansi-term. Here is my enhanced elisp:

(require 'term)
(defun visit-ansi-term ()
  "If the current buffer is:
     1) a running ansi-term named *ansi-term*, rename it.
     2) a stopped ansi-term, kill it and create a new one.
     3) a non ansi-term, go to an already running ansi-term
        or start a new one while killing a defunt one"
  (interactive)
  (let ((is-term (string= "term-mode" major-mode))
        (is-running (term-check-proc (buffer-name)))
        (term-cmd "/bin/bash")
        (anon-term (get-buffer "*ansi-term*")))
    (if is-term
        (if is-running
            (if (string= "*ansi-term*" (buffer-name))
                (call-interactively 'rename-buffer)
              (if anon-term
                  (switch-to-buffer "*ansi-term*")
                (ansi-term term-cmd)))
          (kill-buffer (buffer-name))
          (ansi-term term-cmd))
      (if anon-term
          (if (term-check-proc "*ansi-term*")
              (switch-to-buffer "*ansi-term*")
            (kill-buffer "*ansi-term*")
            (ansi-term term-cmd))
        (ansi-term term-cmd)))))
(global-set-key (kbd "<f2>") 'visit-ansi-term)

TRAMP Integration

This is cool.

Put the following inside of your .bash_profile on any computer that you ssh into frequently:

#Emacs ansi-term directory tracking
# track directory, username, and cwd for remote logons
if [ $TERM = eterm-color ]; then
    function eterm-set-cwd {
        $@
        echo -e "\033AnSiTc" $(pwd)
    }
    
    # set hostname, user, and cwd
    function eterm-reset {
        echo -e "\033AnSiTu" $(whoami)
        echo -e "\033AnSiTc" $(pwd)
        echo -e "\033AnSiTh" $(hostname)
    }
    
    for temp in cd pushd popd; do
        alias $temp="eterm-set-cwd $temp"
    done
    
    # set hostname, user, and cwd now
    eterm-reset
fi

Now when you ssh into a machine from within ansi-term and open a file with C-x C-f you'll be loading a file via TRAMP from the current working directory on the remote machine. Amazingly cool.

blog comments powered by Disqus