Find the relative path of a file in a project

elisp, emacs

Solution

Try `locate-dominating-file` and `file-relative-name`.

(let ((fname (buffer-file-name)))
  (file-relative-name fname (locate-dominating-file fname "Makefile")))

N.B. `locate-dominiating-file` returns `nil` if it can't find anything.

Problem

I have my project files set in this format: ``` /home/user/proj/source /home/user/proj/source/src1 /home/user/proj/source/src1 /home/user/proj/header ...etc ``` I have a way to find the project path when viewing any source file ``` "/home/user/proj" ``` Also, (buffer-file-name) gives the full absolute path of a given source file. How to write a lisp function that extract the relative path of a source file? Meaning, if I am viewing ``` /home/user/proj/source/src1/file.c ``` I would like to have the path ``` "source/src1/file.c" ``` The following function gives me the project path: ``` (defun upward-find-file (filename &optional startdir) (let ((dirname (expand-file-name (if startdir startdir "."))) (found nil) ; found is set as a flag to leave loop if we find it (top nil)) ; top is set when we get ; to / so that we only check it once ; While we've neither been at the top last time nor have we found ; the file. (while (not (or found top)) ; If we're at / set top flag. (if (string= (expand-file-name dirname) "/") (setq top t)) ; Check for the file (if (file-exists-p (expand-file-name filename dirname)) (setq found t) ; If not, move up a directory (setq dirname (expand-file-name ".." dirname)))) ; return statement (if found (concat dirname "/") nil))) ``` I always have "Makefile" in the main project folder, so ``` (setq dirname (upward-find-file "Makefile" startdir)) ``` Takes care of that.

Original source