I use Emacs and Z shell exclusively, and have been frustrated at times about the features in Z shell that are not in Emacs, one being the shortened directory names. These are used for navigating (changing directories and displayed in the prompt), and are especially useful with long/deep directory names.
In Java projects, this is beneficial, because the hierarchy tends to be so deep. For example, with the path:
In Z shell the directory can be given a short name with:
hash -d projectx=/home/me/proj/com/mycompany/projectx/trunk
So the file can be referred as:
And this can be done more extensively than that, such as:
hash -d pxutil=~projectx/src/main/java/com/mycompany/util
And used as:
That also makes for a shorter directory name displayed in the prompt, such as this for DiffJ:
Which without Zsh hashes would be:
So I’ve become used to that in my shell, but have been frustrated with my editor, which shows the full path in the default ibuffer display, running out to over 100 columns:
TokenList.java 1699 /home/jpace/proj/org/incava/diffj/src/main/java/org/incava/diffj/code/TokenList.java
It also seemed redundant that in the above, TokenList.java is displayed twice, so the filename-and-process column could be replaced with only the directory name.
I looked around for examples about changing the columns in ibuffer, but found few examples, mainly the same code repeated on various sites online, variations of this from http://www.emacswiki.org/emacs/IbufferMode:
;; Use human readable Size column instead of original one (define-ibuffer-column size-h (:name "Size" :inline t) (cond ((> (buffer-size) 1000000) (format "%7.3fM" (/ (buffer-size) 1000000.0))) ((> (buffer-size) 1000) (format "%7.3fk" (/ (buffer-size) 1000.0))) (t (format "%8d" (buffer-size)))))
That was a starting point, but I couldn’t find anything more about revising the filename-and-process column, which shows the above long path.
The following code adds a ‘dirname’ format to ibuffer to shorten the filename and show only the directory:
(defvar jep:filename-subs '(("/home/jpace" . "~") (".*/Projects/com/mycompany/is/" . "~is/") ("/home/jpace/proj/org/incava/" . "~incava/") ("/$" . ""))) (define-ibuffer-column dirname (:name "Directory" :inline nil) (if (buffer-file-name buffer) (str-replace-all (file-name-directory (buffer-file-name buffer)) jep:filename-subs) (or dired-directory ""))) (setq ibuffer-formats '((mark modified read-only " " (name 30 30 :left :elide) " " (size 9 -1 :right) " " dirname) (mark modified read-only " " (name 30 30 :left :elide) " " (size 9 -1 :right) " " filename-and-process) (mark " " (name 30 30 :left :elide) " " filename-and-process)))
Now my ibuffer looks like:
[ diffj ] TokenList.java 1699 ~incava/diffj/src/main/java/org/incava/diffj/code build.gradle 892 ~incava/diffj etc....
Coincidentally, I had the same complaint about the modeline, which defaults to the same display as ibuffer, with the full path of the file. So I tweaked the modeline code to do the same:
(defvar jep:modeline-subs '(("/home/jpace/" . "~/") (".*/Projects/com/mycompany/is/" . "~is/") ("/proj/org/incava/" . "~incava/") ("/$" . "") )) (defun jep:modeline-dir-abbrev () (str-replace-all default-directory jep:modeline-subs)) (setq default-mode-line-format (list "" 'mode-line-modified "%25b--" " [" '(:eval (jep:modeline-dir-abbrev)) "] " "%[(" 'mode-name "%n" 'mode-line-process ")%]--" "L%l--" "C%c--" '(-3 . "%P") "-%-"))
Note that the modeline and ibuffer code above uses this function, which I put in ~/.emacs.d/lisp/str.el:
(defun str-replace-all (str pats) (if (null pats) str (let* ((pat (car pats)) (lhs (car pat)) (rhs (cdr pat))) (replace-regexp-in-string lhs rhs (str-replace-all str (cdr pats))))))
So there is my contribution. Here it is in action:
And it’s included with my Emacs configuration on GitHub.