Emacs Lisp Scripting Quirk: Relative Paths

Perm url with updates: http://xahlee.org/emacs/elisp_relative_path.html

Emacs Lisp Scripting Quirk: Relative Paths

Xah Lee, 2011-05-28

Here's a useful function, and also a little detail on a quirk of elisp scripting about relative paths.

Suppose you have 2 scripts, B and C. You are coding file B. You know the relative path from B to C. (Suppose C in is in a sub-directory of B.) You do not know the absolute path at run time because these scripts may be installed anywhere. Your B can call C by the fact that you know the relative path. In Perl, Python, and perhaps most other scripting langs, we can rely on this to work.

However, in emacs lisp, when a file A calls your B, emacs doesn't update its notion of current dir, so B's call to C by relative path will be broken, because emacs will assume it's relative to A.

The following function solves this problem.

(defun fullpath-relative-to-current-file (file-relative-path)
  "Returns the full path of FILE-RELATIVE-PATH, relative to file location where this function is called.

Example: If you have this line
 (fullpath-relative-to-current-file \"../xyz.el\")
in the file at
 /home/mary/emacs/emacs_lib.el
then the return value is
 /home/mary/xyz.el
Regardless how or where emacs_lib.el is called.

This function solves 2 problems.

 ① If you have file A, that calls the `load' on a file at B, and
B calls “load” on file C using a relative path, then Emacs will
complain about unable to find C. Because, emacs does not switch
current directory with “load”.

 To solve this problem, when your code only knows the relative
path of another file C, you can use the variable `load-file-name'
to get the current file's full path, then use that with the
relative path to get a full path of the file you are interested.

 ② To know the current file's full path, emacs has 2 ways:
`load-file-name' and `buffer-file-name'.  If the file is loaded
by “load”, then load-file-name works but buffer-file-name
doesn't.  If the file is called by `eval-buffer', then
load-file-name is nil. You want to be able to get the current
file's full path regardless the file is run by “load” or
interactively by “eval-buffer”."
  (concat (file-name-directory (or load-file-name buffer-file-name)) file-relative-path)
)

See also: What's the difference between load-file, load, require, autoload?.

Popular posts from this blog

11 Years of Writing About Emacs

does md5 creates more randomness?

Google Code shutting down, future of ErgoEmacs