Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

310 lines
12 KiB

  1. ;;; load-relative.el --- Relative file load (within a multi-file Emacs package) -*- lexical-binding: t -*-
  2. ;; Author: Rocky Bernstein <rocky@gnu.org>
  3. ;; Version: 1.3.1
  4. ;; Keywords: internal
  5. ;; URL: http://github.com/rocky/emacs-load-relative
  6. ;; Compatibility: GNU Emacs 23.x
  7. ;; Copyright (C) 2015-2019 Free Software Foundation, Inc
  8. ;; This program is free software: you can redistribute it and/or
  9. ;; modify it under the terms of the GNU General Public License as
  10. ;; published by the Free Software Foundation, either version 3 of the
  11. ;; License, or (at your option) any later version.
  12. ;; This program is distributed in the hope that it will be useful, but
  13. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. ;; General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with this program. If not, see
  18. ;; <http://www.gnu.org/licenses/>.
  19. ;;; Commentary:
  20. ;; Here we provide functions which facilitate writing multi-file Emacs
  21. ;; packages and facilitate running from the source tree without having
  22. ;; to "install" code or fiddle with evil `load-path'. See
  23. ;; https://github.com/rocky/emacs-load-relative/wiki/NYC-Lisp-talk for
  24. ;; the the rationale behind this.
  25. ;;
  26. ;; The functions we add are relative versions of `load', `require' and
  27. ;; `find-file-no-select' and versions which take list arguments. We also add a
  28. ;; `__FILE__' function and a `provide-me' macro.
  29. ;; The latest version of this code is at:
  30. ;; http://github.com/rocky/emacs-load-relative/
  31. ;; `__FILE__' returns the file name that that the calling program is
  32. ;; running. If you are `eval''ing a buffer then the file name of that
  33. ;; buffer is used. The name was selected to be analogous to the name
  34. ;; used in C, Perl, Python, and Ruby.
  35. ;; `load-relative' loads an Emacs Lisp file relative to another
  36. ;; (presumably currently running) Emacs Lisp file. For example suppose
  37. ;; you have Emacs Lisp files "foo.el" and "bar.el" in the same
  38. ;; directory. To load "bar.el" from inside Emacs Lisp file "foo.el":
  39. ;;
  40. ;; (require 'load-relative)
  41. ;; (load-relative "baz")
  42. ;;
  43. ;; The above `load-relative' line could above have also been written as:
  44. ;;
  45. ;; (load-relative "./baz")
  46. ;; or:
  47. ;; (load-relative "baz.el") # if you want to exclude any byte-compiled files
  48. ;;
  49. ;; Use `require-relative' if you want to `require' the file instead of
  50. ;; `load'ing it:
  51. ;;
  52. ;; (require-relative "baz")
  53. ;;
  54. ;; or:
  55. ;;
  56. ;; (require-relative "./baz")
  57. ;;
  58. ;; The above not only does a `require' on 'baz', but makes sure you
  59. ;; get that from the same file as you would have if you had issued
  60. ;; `load_relative'.
  61. ;;
  62. ;; Use `require-relative-list' when you have a list of files you want
  63. ;; to `require'. To `require-relative' them all in one shot:
  64. ;;
  65. ;; (require-relative-list '("dbgr-init" "dbgr-fringe"))
  66. ;;
  67. ;; The macro `provide-me' saves you the trouble of adding a
  68. ;; symbol after `provide' using the file basename (without directory
  69. ;; or file extension) as the name of the thing you want to
  70. ;; provide.
  71. ;;
  72. ;; Using this constrains the `provide' name to be the same as
  73. ;; the filename, but I consider that a good thing.
  74. ;;
  75. ;; The function `find-file-noselect-relative' provides a way of accessing
  76. ;; resources which are located relative to the currently running Emacs Lisp
  77. ;; file. This is probably most useful when running Emacs as a scripting engine
  78. ;; for batch processing or with tests cases. For example, this form will find
  79. ;; the README file for this package.
  80. ;;
  81. ;; (find-file-noselect-relative "README.md")
  82. ;;
  83. ;; `find-file-noselect-relative' also takes wildcards, as does it's
  84. ;; non-relative namesake.
  85. ;;
  86. ;; The macro `with-relative-file' runs in a buffer with the contents of the
  87. ;; given relative file.
  88. ;;
  89. ;; (with-relative-file "README.md"
  90. ;; (buffer-substring))
  91. ;;
  92. ;; This is easier if you care about the contents of the file, rather than
  93. ;; a buffer.
  94. ;;; Code:
  95. ;; Press C-x C-e at the end of the next line configure the program in
  96. ;; for building via "make" to get set up.
  97. ;; (compile (format "EMACSLOADPATH=:%s ./autogen.sh" "."))
  98. ;; After that you can run:
  99. ;; (compile "make check")
  100. ;;;###autoload
  101. (defun __FILE__ (&optional symbol)
  102. "Return the string name of file/buffer that is currently begin executed.
  103. The first approach for getting this information is perhaps the
  104. most pervasive and reliable. But it the most low-level and not
  105. part of a public API, so it might change in future
  106. implementations. This method uses the name that is recorded by
  107. readevalloop of `lread.c' as the car of variable
  108. `current-load-list'.
  109. Failing that, we use `load-file-name' which should work in some
  110. subset of the same places that the first method works. However
  111. `load-file-name' will be nil for code that is eval'd. To cover
  112. those cases, we try function `buffer-file-name' which is initially
  113. correct, for eval'd code, but will change and may be wrong if the
  114. code sets or switches buffers after the initial execution.
  115. As a last resort, you can pass in SYMBOL which should be some
  116. symbol that has been previously defined if none of the above
  117. methods work we will use the file-name value find via
  118. `symbol-file'."
  119. ;; Not used right now:
  120. ;; Failing the above the next approach we try is to use the value of
  121. ;; $# - 'the name of this file as a string'. Although it doesn't
  122. ;; work for eval-like things, it has the advantage that this value
  123. ;; persists after loading or evaluating a file. So it would be
  124. ;; suitable if __FILE__ were called from inside a function.
  125. (cond
  126. ;; lread.c's readevalloop sets (car current-load-list)
  127. ;; via macro LOADHIST_ATTACH of lisp.h. At least in Emacs
  128. ;; 23.0.91 and this code goes back to '93.
  129. ((stringp (car-safe current-load-list)) (car current-load-list))
  130. ;; load-like things. 'relative-file-expand' tests in
  131. ;; test/test-load.el indicates we should put this ahead of
  132. ;; $#.
  133. (load-file-name)
  134. ;; Pick up "name of this file as a string" which is set on
  135. ;; reading and persists. In contrast, load-file-name is set only
  136. ;; inside eval. As such, it won't work when not in the middle of
  137. ;; loading.
  138. ;; (#$)
  139. ;; eval-like things
  140. ((buffer-file-name))
  141. ;; When byte compiling. FIXME: use a more thorough precondition like
  142. ;; byte-compile-file is somehwere in the backtrace or that
  143. ;; bytecomp-filename comes from that routine?
  144. ;; FIXME: `bytecomp-filename' doesn't exist any more (since Emacs-24.1).
  145. ((boundp 'bytecomp-filename) bytecomp-filename)
  146. (t (symbol-file symbol) ;; last resort
  147. )))
  148. (defun autoload-relative (function-or-list
  149. file &optional docstring interactive type
  150. symbol)
  151. ;; FIXME: Docstring talks of FUNCTION but argname is `function-or-list'.
  152. "Autoload an Emacs Lisp file relative to Emacs Lisp code that is in the process
  153. of being loaded or eval'd.
  154. Define FUNCTION to autoload from FILE. FUNCTION is a symbol.
  155. FILE is a string to pass to `load'.
  156. DOCSTRING is documentation for the function.
  157. INTERACTIVE if non-nil says function can be called
  158. interactively.
  159. TYPE indicates the type of the object: nil or omitted says
  160. function is a function, `keymap' says function is really a
  161. keymap, and `macro' or t says function is really a macro. Third
  162. through fifth args give info about the real definition. They
  163. default to nil. If function is already defined other than as an
  164. autoload, this does nothing and returns nil.
  165. SYMBOL is the location of of the file of where that was
  166. defined (as given by `symbol-file' is used if other methods of
  167. finding __FILE__ don't work."
  168. (if (listp function-or-list)
  169. ;; FIXME: This looks broken:
  170. ;; - Shouldn't it iterate on `function-or-list' instead of `file'?
  171. ;; - Shouldn't the `autoload' take `function' rather than
  172. ;; `function-or-list' as argument?
  173. (mapc (lambda(_function)
  174. (autoload function-or-list
  175. (relative-expand-file-name file symbol)
  176. docstring interactive type))
  177. file)
  178. (autoload function-or-list (relative-expand-file-name file symbol)
  179. docstring interactive type))
  180. )
  181. ;;;###autoload
  182. (defun find-file-noselect-relative (filename &optional nowarn rawfile wildcards)
  183. "Read relative FILENAME into a buffer and return the buffer.
  184. If a buffer exists visiting FILENAME, return that one, but
  185. verify that the file has not changed since visited or saved.
  186. The buffer is not selected, just returned to the caller.
  187. Optional second arg NOWARN non-nil means suppress any warning messages.
  188. Optional third arg RAWFILE non-nil means the file is read literally.
  189. Optional fourth arg WILDCARDS non-nil means do wildcard processing
  190. and visit all the matching files. When wildcards are actually
  191. used and expanded, return a list of buffers that are visiting
  192. the various files."
  193. (find-file-noselect (relative-expand-file-name filename)
  194. nowarn rawfile wildcards))
  195. ;;;###autoload
  196. (defmacro with-relative-file (file &rest body)
  197. "Read the relative FILE into a temporary buffer and evaluate BODY
  198. in this buffer."
  199. (declare (indent 1) (debug t))
  200. `(with-temp-buffer
  201. (insert-file-contents
  202. (relative-expand-file-name
  203. ,file))
  204. ,@body))
  205. ;;;###autoload
  206. (defun load-relative (file-or-list &optional symbol)
  207. "Load an Emacs Lisp file relative to Emacs Lisp code that is in
  208. the process of being loaded or eval'd.
  209. FILE-OR-LIST is either a string or a list of strings containing
  210. files that you want to loaded. If SYMBOL is given, the location of
  211. of the file of where that was defined (as given by `symbol-file' is used
  212. if other methods of finding __FILE__ don't work."
  213. (if (listp file-or-list)
  214. (mapcar (lambda(relative-file)
  215. (load (relative-expand-file-name relative-file symbol)))
  216. file-or-list)
  217. (load (relative-expand-file-name file-or-list symbol)))
  218. )
  219. (defun relative-expand-file-name(relative-file &optional opt-file)
  220. "Expand RELATIVE-FILE relative to the Emacs Lisp code that is in
  221. the process of being loaded or eval'd.
  222. WARNING: it is best to run this function before any
  223. buffer-setting or buffer changing operations."
  224. (let ((file (or opt-file (__FILE__) default-directory))
  225. (prefix))
  226. (unless file
  227. ;; FIXME: Since default-directory should basically never be nil, this
  228. ;; should basically never trigger!
  229. (error "Can't expand __FILE__ here and no file name given"))
  230. (setq prefix (file-name-directory file))
  231. (expand-file-name (concat prefix relative-file))))
  232. ;;;###autoload
  233. (defun require-relative (relative-file &optional opt-file opt-prefix)
  234. "Run `require' on an Emacs Lisp file relative to the Emacs Lisp code
  235. that is in the process of being loaded or eval'd. The symbol used in require
  236. is the base file name (without directory or file extension) treated as a
  237. symbol.
  238. WARNING: it is best to to run this function before any
  239. buffer-setting or buffer changing operations."
  240. (let ((require-string-name
  241. (concat opt-prefix (file-name-sans-extension
  242. (file-name-nondirectory relative-file)))))
  243. (require (intern require-string-name)
  244. (relative-expand-file-name relative-file opt-file))))
  245. ;;;###autoload
  246. (defmacro require-relative-list (list &optional opt-prefix)
  247. "Run `require-relative' on each name in LIST which should be a list of
  248. strings, each string being the relative name of file you want to run."
  249. `(eval-and-compile
  250. (dolist (rel-file ,list)
  251. (require-relative rel-file (__FILE__) ,opt-prefix))))
  252. ;;;###autoload
  253. (defmacro provide-me ( &optional prefix )
  254. "Call `provide' with the feature's symbol name made from
  255. source-code's file basename sans extension. For example if you
  256. write (provide-me) inside file ~/lisp/foo.el, this is the same as
  257. writing: (provide \\='foo).
  258. With a prefix, that prefix is prepended to the `provide' So in
  259. the previous example, if you write (provide-me \"bar-\") this is the
  260. same as writing (provide \\='bar-foo)."
  261. `(provide (intern (concat ,prefix (file-name-sans-extension
  262. (file-name-nondirectory (__FILE__)))))))
  263. (provide-me)
  264. ;;; load-relative.el ends here