Friday, July 17, 2009

Dired mode and too many buffers.

Emacs has a very nice file browser/directory editor builtin called Dired. It's convenient when you're searching for files or or just need a general directory browser. You open it with:
C-x d

Supply to the directory that you want, and the directory listing appears in a buffer which you can navigate like any Emacs buffer. You can open files and directories by moving the cursor sand selecting them, as well as delete, rename, move and apply other opperations to the files and directories. All in all, it's pretty slick.

Dired's one major inconvenience for me is that every time I open something, it opens in a separate buffer. This includes new directories. So, if I use it to browse directories I end up with a large backlog of buffers that I have to delete and it gets very annoying.

Fortunatly, this being Emacs, things are eay to fix. A Google search found me this code:

(defun dired-follow-file ()
"In dired, visit the file or directory on this line.
If a directory is on the current line, replace the current
dired buffer with one containing the contents of the directory.
Otherwise, invoke `dired-find-file' on the file."
(interactive)
(let ((filename (dired-get-filename)))
;; if the file is a directory, replace the buffer with the
;; directory's contents
(if (file-directory-p filename)
(find-alternate-file filename)
;; otherwise simply perform a normal `dired-find-file'
(dired-find-file))))

(add-hook
'dired-mode-hook
(lambda ()
(local-set-key "\C-m" 'dired-follow-file)
(local-set-key "e" 'dired-follow-file)
(local-set-key "f" 'dired-follow-file)))


Which causes Dired to do exactly what I want, with one caveat: for some reason it bombs on . and .. directories. A little bit probing showed that it was dired-get-filename that was was failing for some reasons on these entries. I couldn't find either the definition or a description of dired-get-filename, but did find usage examples through a simple web search and these examples showed the usage:
(dired-get-filename nil t)

Instead of:
(dired-get-filename)

Which seemed to be worth a shor and, in fact, solved the problem.

I also added:

(defun dired-follow-up ()
"In dired, visit the directory up in the
hierarchy from this one"
(interactive)
(find-alternate-file ".."))


So that ^ would also behave as I wanted. The final code in my .emacs is as follows:

;; dired stuff

(defun dired-follow-file ()
"In dired, visit the file or directory on this line.
If a directory is on the current line, replace the current
dired buffer with one containing the contents of the directory.
Otherwise, invoke `dired-find-file' on the file."
(interactive)
(let ((filename (dired-get-filename nil t)))
;; if the file is a directory, replace the buffer with the
;; directory's contents
(if (file-directory-p filename)
(find-alternate-file filename)
;; otherwise simply perform a normal `dired-find-file'
(dired-find-file))))

(defun dired-follow-up ()
"In dired, visit the directory up in the
hierarchy from this one"
(interactive)
(find-alternate-file ".."))

(add-hook
'dired-mode-hook
(lambda ()
(local-set-key "\C-m" 'dired-follow-file)
(local-set-key "e" 'dired-follow-file)
(local-set-key "f" 'dired-follow-file)
(local-set-key "^" 'dired-follow-up)))

No comments:

Post a Comment