(or emacs irrelevant)

dired and ansi-term: BFF

In the comments to my previous post on ansi-term, I discovered sane-term - a package that cycles though your terminals in Emacs, as well as implements some of the tips that I gave. While it's nice and all, and you should check it out if you're looking for something like that, it's not really for me. I will describe the system that I'm currently using below.

What is the best list length for cycling?

In my opinion, it's one or two. If it's one, you're not really cycling, if it's two, it's fine. Anything more than that causes stress, since you have to check each time if the outcome of the cycle ended up being the one that you wanted.

That's why I usually have only one *ansi-term* active in my Emacs session at all times. Here's how it looks like:

(defun terminal ()
  "Switch to terminal. Launch if nonexistent."
  (interactive)
  (if (get-buffer "*ansi-term*")
      (switch-to-buffer "*ansi-term*")
    (ansi-term "/bin/bash"))
  (get-buffer-process "*ansi-term*"))

(defalias 'tt 'terminal)

At one point, I had terminal bound to C-t, until I found a command even better suited for that binding, which was smex. The actual terminal command isn't bound right now, I just launch it from smex on very rare occasions.

How I launch terminal 95% of the time

From dired of course. The shell's natural way of switching the directory with cd is extremely inefficient compared to dired. So any time I want to have a shell in a specific directory, I first navigate there with dired, sometimes combined with ido-find-file. Then I get my current *ansi-term* and tell it to switch to the current dired buffer's directory with ` binding:

(define-key dired-mode-map (kbd "`") 'dired-open-term)

(defun dired-open-term ()
  "Open an `ansi-term' that corresponds to current directory."
  (interactive)
  (let ((current-dir (dired-current-directory)))
    (term-send-string
     (terminal)
     (if (file-remote-p current-dir)
         (let ((v (tramp-dissect-file-name current-dir t)))
           (format "ssh %s@%s\n"
                   (aref v 1) (aref v 2)))
       (format "cd '%s'\n" current-dir)))))

I also have a similar eshell setup, although I have yet to comprehend why eshell is great and am using *ansi-term* most of the time instead.

(define-key dired-mode-map (kbd "'")
  (lambda ()
    (interactive)
    (eshell-cmd
     (format "cd %s"
             (expand-file-name
              default-directory)))))

How I launch dired 100% of the time

With dired-jump, of course. This command will examine your current buffer's default-directory and open a dired buffer there. All you need is:

(require 'dired-x)

The dired-jump command will be bound automatically to C-x C-j. I have it also bound to C-:, since that's more convenient to press with my keyboard layout.

It's also better in the common situation when I want to jump to a dired buffer from *ansi-term*. In that situation, C-x C-j will not work by default, and will call term-line-mode instead. But it will work once you are in term-line-mode. You can go back to the default term-char-mode with C-x C-k. To avoid this nonsense, just bind dired-jump to some binding that's convenient for you and works from *ansi-term*.

What I do when I need more than one terminal

Then I just name one: since the default one is supposed to be named *ansi-term*, if I create one named e.g. *jekyll*, it will be ignored by dired-open-term. This is exactly what I want, since I just create named terminals for long running processes like jekyll serve. And I can switch to the named terminals with just ido-switch-buffer. Here is the very simple code:

(defun named-term (name)
  (interactive "sName: ")
  (ansi-term "/bin/bash" name))