(or emacs irrelevant)

Even more dired options

I've been posting a lot about dired lately, and with good cause. A lot of people say that org-mode is the killer app of Emacs, but dired should be in that group as well, especially if you count tramp as part of dired. Below, I'll list a few dired options in my config that deviate from the defaults.

dired-listing-switches

This is the essence of what dired presents and how it presents it. A great thing about it is that these are just the ls switches, so you can look them up with info ls.

(setq dired-listing-switches "-laGh1v --group-directories-first")
  • l: Is the only mandatory one.
  • a: Means to list invisible files.
  • G: Don't show group information. These days, when there are more laptops than people, the group info is rarely useful.
  • h: Human readable sizes, such as M for mebibytes.
  • 1v: Affects the sorting of digits, hopefully in a positive way.
  • --group-directories-first: self-explanatory, I like to have the directories on the top, separate from the files.

On recursion

(setq dired-recursive-copies 'always)
(setq dired-recursive-deletes 'always)

These settings make dired skip the confirmation when you copy or delete a directory that contains other directories. What's the worse that could happen, right?

-  rm -rf /usr /lib/nvidia-current/xorg/xorg
+  rm -rf /usr/lib/nvidia-current/xorg/xorg

File sizes in dired

Today, I'll continue with the trend of posting a small piece of my config when I don't have the time to post something more substantial.

Some code

This one looks nice, although it only works on systems with /usr/bin/du, which actually comprise 100% of the systems that I use:

(defun dired-get-size ()
  (interactive)
  (let ((files (dired-get-marked-files)))
    (with-temp-buffer
      (apply 'call-process "/usr/bin/du" nil t nil "-sch" files)
      (message
       "Size of all marked files: %s"
       (progn
         (re-search-backward "\\(^[ 0-9.,]+[A-Za-z]+\\).*total$")
         (match-string 1))))))

On doing a search, turns out that I got this code from the wiki at some point. I can confirm that, unlike some of the other code on the wiki, this one still works as advertised: you can use it on a directory or on a series of marked files and directories.

Standard dired marking

In dired, you can:

  • mark an item with m
  • unmark an item with DEL
  • inverse selection with t
  • unmark everything with U

Compared to this, the selection with the mouse and the control and shift keys that many file browsers use looks like kindergarten.

This new action, getting the size of marked things, I've bound to z:

(define-key dired-mode-map (kbd "z") 'dired-get-size)

Making Elisp regex look nicer

This is just a small improvement to make e.g. \\( show up in regular expressions without the escape chars, but instead fontified with font-lock-keyword-face. It doesn't affect the underlying code at all, just makes it look nicer. For the \\| I chose - the logical or character.

The code

(defun fontify-glyph (item glyph)
  `((,item
     (0 font-lock-keyword-face t)
     (0 (prog1
            (compose-region (match-beginning 0)
                            (match-end 0)
                            ,glyph) nil)))))

(font-lock-add-keywords 'emacs-lisp-mode
                        (fontify-glyph "\\\\\\\\|" "∨"))
(font-lock-add-keywords 'emacs-lisp-mode
                        (fontify-glyph "\\\\\\\\(" "("))
(font-lock-add-keywords 'emacs-lisp-mode
                        (fontify-glyph "\\\\\\\\)" ")"))

How it looks like

At first, I wanted to just inline a picture, but then I thought that htmlize-buffer would be able to handle it. It didn't, so I just edited a small snippet by hand:

(or (string-match "^([^\n%|]*?)|(([^\n]*)?$" str)
    (string-match "^([^\n%|]*?)(%[^\n]*)?$" str))

It's really satisfying to see those escape chars vanish as I type in a capture group in the regex, especially with the help of lispy-mode. Here are some relevant tests for the regex support:

(should (string= (lispy-with "\"a regex \\\\|\"" "(")
                 "\"a regex \\\\(|\\\\)\""))
(should (string= (lispy-with "\"\\\\(|foo\\\\)\"" "\C-?")
                 "\"|foo\""))
(should (string= (lispy-with "\"\\\\(foo\\\\)|\"" "\C-?")
                 "\"foo|\""))
(should (string= (lispy-with "\"|\\\\(foo\\\\)\"" "\C-d")
                 "\"|foo\""))
(should (string= (lispy-with "\"\\\\(foo|\\\\)\"" "\C-d")
                 "\"foo|\""))

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))

tilde in ido-find-file

On seeing this Emacs Stack Exchange question, it occurred to me that if some config code is old for me, it's not old for the new Emacs users. So I'll share one of the old ido-find-file hacks that I've been using for ages.

This song is an oldie ...but, uh ... pause Well, it's an oldie where I come from.

-- Marty

The code

This is the original code that I was using:

(defun oleh-ido-setup-hook ()
  (define-key ido-file-dir-completion-map "~"
    (lambda ()
      (interactive)
      (ido-set-current-directory "~/")
      (setq ido-exit 'refresh)
      (exit-minibuffer))))

(add-hook 'ido-setup-hook 'oleh-ido-setup-hook)

The generalization

It wouldn't be a LISP if I couldn't generalize the code:

(defun ido-find-file-jump (dir)
  "Return a command that sends DIR to `ido-find-file'."
  `(lambda ()
     (interactive)
     (ido-set-current-directory ,dir)
     (setq ido-exit 'refresh)
     (exit-minibuffer)))

And here's how to leverage this generalization:

(defun oleh-ido-setup-hook ()
  (define-key ido-file-dir-completion-map "~"
    (ido-find-file-jump "~/"))
  (define-key ido-file-dir-completion-map "!"
    (ido-find-file-jump "~/Dropbox/source/site-lisp/"))
  (define-key ido-file-dir-completion-map "@"
    (ido-find-file-jump "~/git/lispy/")))

Note that this is pretty ugly, implementation-wise, since ido-find-file-jump would be called three times each time you do an ido related command, like ido-switch-buffer etc. I would have preferred to do it like this instead:

(eval-after-load "ido"
  `(progn
     (define-key ido-file-dir-completion-map "~"
       (ido-find-file-jump "~/"))
     (define-key ido-file-dir-completion-map "!"
       (ido-find-file-jump "~/Dropbox/source/site-lisp/"))
     (define-key ido-file-dir-completion-map "@"
       (ido-find-file-jump "~/git/lispy/"))))

But, for some strange reason, ido keeps overriding ido-file-dir-completion-map and I actually have to re-set my bindings in ido-setup-hook.

The further generalization

Here is the final iteration of the code:

(defvar oleh-ido-shortcuts
  '(("~/" "~")
    ("~/Dropbox/source/site-lisp/" "!")
    ("~/git/lispy/" "@")))

(mapc (lambda (x)
        (setcar x (ido-find-file-jump (car x))))
      oleh-ido-shortcuts)

(defun oleh-ido-setup-hook ()
  (mapc
   (lambda (x)
     (define-key ido-file-dir-completion-map (cadr x) (car x)))
   oleh-ido-shortcuts))

(add-hook 'ido-setup-hook 'oleh-ido-setup-hook)

The customize tricks

"Custom setters?
In my Elisp?"

It's more likely than you think.

Note that the mapc statement needs to be evaluated if I dynamically modify oleh-ido-shortcuts. This isn't a problem for me, but if I wanted to package a code like this, I would define oleh-ido-shortcuts like this:

(defcustom oleh-ido-shortcuts
  '(("~/" "~")
   ("~/Dropbox/source/site-lisp/" "!")
    ("~/git/lispy/" "@"))
  "A list of directory-shortcut pairs for `ido-find-file'."
  :set (lambda (symbol value)
         (set-default
          symbol
          (mapcar
           (lambda (x)
             (if (stringp (car x))
                 (cons (ido-find-file-jump (car x))
                       (cdr x))
               x))
           value))))

Now, this should work:

(csetq oleh-ido-shortcuts
       (progn
         (setcar (rassoc '("@") oleh-ido-shortcuts)
                 "~/git/worf")
         oleh-ido-shortcuts))

(csetq oleh-ido-shortcuts
       (cons '("~/git/" "^")
             oleh-ido-shortcuts))

Here, the appropriate lambda is auto-generated by using the :set property of oleh-ido-shortcuts. And csetq is just a customize-aware version of setq:

(defmacro csetq (variable value)
  `(funcall (or (get ',variable 'custom-set) 'set-default)
            ',variable ,value))