Tools for grepping in Emacs
Jonathan Lange
jml at mumak.net
Tue Apr 28 09:59:17 BST 2009
On Mon, Apr 13, 2009 at 5:52 AM, Karl Fogel <karl.fogel at canonical.com> wrote:
> Jonathan Lange <jml at mumak.net> 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!
Thanks, although I can't take much credit.
> 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;
Not only that, it defines a global anyway, so I'm not even masking the
inner 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.
>
Obvious to you maybe. To a casual, Python-influenced reader,
(file-name-directory (directory-file-name path)) doesn't scream out
"get the parent directory of path".
It turns out, however, that Emacs 23 has `locate-dominating-file',
which does exactly what I want. Since I use Emacs 23 personally, I've
just deleted my snippets of code.
>> ;; 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)))))
>>
Offlist, someone pointed out that I could just set default-directory
instead of this convoluted macro.
>>
>> ;; 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))
>>
>>
...
> (Why not using 'at-branch-root' in 'bzr-grep', by the way?)
>
Simple mistake.
>> (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 :-).
>
And PHP's too!
"Those who cannot remember the past are condemned to repeat it"
I've attached the updated version. The other significant change is
that I use `shell-quote-argument' to wrap up the regular expression
that the user provides.
Thanks heaps to everyone who sent me feedback. It was very helpful and
very encouraging.
Happy chording!
jml
-------------- next part --------------
A non-text attachment was scrubbed...
Name: bzr-tools.el
Type: text/x-emacs-lisp
Size: 2153 bytes
Desc: not available
Url : https://lists.ubuntu.com/archives/bazaar/attachments/20090428/52884e25/attachment.bin
More information about the bazaar
mailing list