22

The file tree is as follwing:

- foo
  - lorem
    - ipsum <-
  - baz <-
- bar
- baz

The currently visited file is ipsum. Now I want to find the first baz and the directory it is in. How do I walk up the tree from ipsum in elisp?

Reactormonk
  • 21,472
  • 14
  • 74
  • 123
  • "First" is ambigous, not in this example, but generally. If there are multiple, should we prefer a child, a parent, or one of the sibling nodes? – tripleee Dec 30 '12 at 22:18

2 Answers2

32

You want locate-dominating-file.

Stefan
  • 27,908
  • 4
  • 53
  • 82
  • Looks nice, except it does not seem to accept wildcards. I'm looking for a file with a given extension. – Reactormonk Jan 07 '13 at 18:07
  • 2
    Actually, in recent versions of Emacs, it accepts a function as argument, so it can definititely do the widlcard thing (via `directory-files`). – Stefan Jun 19 '13 at 02:41
  • 4
    `(locate-dominating-file DIR (lambda (parent) (directory-files parent nil "\\(GNU\\)?[Mm]akefile")))` – Stefan Jun 19 '13 at 18:59
18
(defun parent-directory (dir)
  (unless (equal "/" dir)
    (file-name-directory (directory-file-name dir))))

(defun find-file-in-heirarchy (current-dir fname)
  "Search for a file named FNAME upwards through the directory hierarchy, starting from CURRENT-DIR" 
  (let ((file (concat current-dir fname))
        (parent (parent-directory (expand-file-name current-dir))))
    (if (file-exists-p file)
        file
      (when parent
        (find-file-in-heirarchy parent fname)))))

If the result is not nil, you can extract the file's directory using file-name-directory, like so:

(let ((file (find-file-in-heirarchy (buffer-file-name) "baz")))
  (when file
    (file-name-directory file)))
Chris Barrett
  • 3,383
  • 17
  • 21