Tools for grepping in Emacs

Karl Fogel karl.fogel at
Sun Apr 12 20:52:17 BST 2009

Jonathan Lange <jml at> writes:
> My elisp-fu is very weak, and I needed a lot of help even to get this
> much done. I'd love some feedback on how the code could be nicer, or
> suggestions on how this should best be maintained / shared with the
> rest of the Bazaar / Emacs community.

Your elisp is excellent, for someone who says his elisp-fu is weak!
A few comments below.

> (provide 'bzr-tools)
> (defun search-upwards (filename starting-path)
>   "Search for `filename' in every directory from `starting-path' up."
>   (defun parent-dir (path)
>     (file-name-directory (directory-file-name path)))
>   (let ((path (file-name-as-directory starting-path)))
>     (if (file-exists-p (concat path filename))
>         path
>       (let ((parent (parent-dir path)))
>         (if (string= parent path)
>             nil
>           (search-upwards filename parent))))))

It's unusual to have a defun within a defun; more common, I think, is to
use 'lambda' and 'funcall', e.g.:

   (let ((parent-dir (lambda (path)
                       (file-name-directory (directory-file-name path)))))
     (funcall parent-dir "/foo/bar/"))

However, I'm not sure the extra readability of a named function is even
worth it.  You could just do

  (let ((parent (file-name-directory (directory-file-name path))))

and the meaning would be obvious anyway.
> ;; Run 'code' in directory 'dirname'.
> ;; Copied from twisted-dev.el
> (defmacro with-cd (dirname &rest code)
>   `(let ((old-dirname default-directory)
> 	 (start-buffer (current-buffer)))
>      (cd ,dirname)
>      (unwind-protect (progn , at code)
>        (let ((end-buffer (current-buffer)))
>          (set-buffer start-buffer)
>          (cd old-dirname)
>          (set-buffer end-buffer)))))
> ;; Run 'code' at the root of the branch which dirname is in.
> (defmacro at-branch-root (dirname &rest code)
>   `(with-cd (search-upwards ".bzr" (expand-file-name ,dirname)) , at code))
> (defun bzr-grep (expression dirname)
>   (interactive "MSearch for: \nDSearch for %s in: ")
>   (with-cd
>    (search-upwards ".bzr" (expand-file-name dirname))
>    (grep-find (format "bzr ls -V --null | xargs -0 grep -In %s" expression))))

Alexander's point about using 'bzr root' means you could avoid the whole
searching-upwards thing anyway, I guess.

(Why not using 'at-branch-root' in 'bzr-grep', by the way?)

> (defun grep-branch (expression)
>   (interactive "MSearch for: ")
>   (at-branch-root "."
>    (grep-find (format "bzr ls -V --null | xargs -0 grep -In %s" expression))))
> (defun branch-todo ()
>   (interactive)
>   (with-cd (search-upwards ".bzr" (expand-file-name "."))
>    (compile "bzr todo" t)))

The only other thing I'd suggest is giving a common prefix to all the
symbols, something beginning with 'bzr-...', if you want to distribute
the code.  Prefixes are Emacs's module system, believe it or not :-).


More information about the bazaar mailing list