--- /dev/null
+;;; load-relative.el --- relative file load (within a multi-file Emacs package)
+
+;; Author: Rocky Bernstein
+;; Version: 1.1
+;; Keywords: internal
+;; URL: http://github.com/rocky/emacs-load-relative
+;; Compatibility: GNU Emacs 23.x
+
+;; Copyright (C) 2015 Free Software Foundation, Inc
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see
+;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Here we provide functions which facilitate writing multi-file Emacs
+;; packages and facilitate running from the source tree without having
+;; to "install" code or fiddle with evil `load-path'. See
+;; https://github.com/rocky/emacs-load-relative/wiki/NYC-Lisp-talk for
+;; the the rationale behind this.
+;;
+;; The functions we add are relative versions of `load', and `require'
+;; and versions which take list arguments. We also add a `__FILE__'
+;; function and a `provide-me' macro.
+
+;; The latest version of this code is at:
+;; http://github.com/rocky/emacs-load-relative/
+
+;; `__FILE__' returns the file name that that the calling program is
+;; running. If you are `eval''ing a buffer then the file name of that
+;; buffer is used. The name was selected to be analogous to the name
+;; used in C, Perl, Python, and Ruby.
+
+;; `load-relative' loads an Emacs Lisp file relative to another
+;; (presumably currently running) Emacs Lisp file. For example suppose
+;; you have Emacs Lisp files "foo.el" and "bar.el" in the same
+;; directory. To load "bar.el" from inside Emacs lisp file "foo.el":
+;;
+;; (require 'load-relative)
+;; (load-relative "baz")
+;;
+;; The above `load-relative' line could above have also been written as:
+;;
+;; (load-relative "./baz")
+;; or:
+;; (load-relative "baz.el") # if you want to exclude any byte-compiled files
+;;
+;; Use `require-relative' if you want to `require' the file instead of
+;; `load'ing it:
+;;
+;; (require-relative "baz")
+;;
+;; or:
+;;
+;; (require-relative "./baz")
+;;
+;; The above not only does a `require' on 'baz', but makes sure you
+;; get that from the same file as you would have if you had issued
+;; `load_relative'.
+;;
+;; Use `require-relative-list' when you have a list of files you want
+;; to `require'. To `require-relative' them all in one shot:
+;;
+;; (require-relative-list '("dbgr-init" "dbgr-fringe"))
+;;
+;; Finally, macro `provide-me' saves you the trouble of adding a
+;; symbol after `provide' using the file basename (without directory
+;; or file extension) as the name of the thing you want to
+;; provide.
+;;
+;; Using this constrains the `provide' name to be the same as
+;; the filename, but I consider that a good thing.
+
+;;; Code:
+
+;;;###autoload
+(defun __FILE__ (&optional symbol)
+ "Return the string name of file/buffer that is currently begin executed.
+
+The first approach for getting this information is perhaps the
+most pervasive and reliable. But it the most low-level and not
+part of a public API, so it might change in future
+implementations. This method uses the name that is recorded by
+readevalloop of `lread.c' as the car of variable
+`current-load-list'.
+
+Failing that, we use `load-file-name' which should work in some
+subset of the same places that the first method works. However
+`load-file-name' will be nil for code that is eval'd. To cover
+those cases, we try `buffer-file-name' which is initially
+correct, for eval'd code, but will change and may be wrong if the
+code sets or switches buffers after the initial execution.
+
+As a last resort, you can pass in SYMBOL which should be some
+symbol that has been previously defined if none of the above
+methods work we will use the file-name value find via
+`symbol-file'."
+ ;; Not used right now:
+ ;; Failing the above the next approach we try is to use the value of
+ ;; $# - 'the name of this file as a string'. Although it doesn't
+ ;; work for eval-like things, it has the advantage that this value
+ ;; persists after loading or evaluating a file. So it would be
+ ;; suitable if __FILE__ were called from inside a function.
+
+
+ (cond
+ ;; lread.c's readevalloop sets (car current-load-list)
+ ;; via macro LOADHIST_ATTACH of lisp.h. At least in Emacs
+ ;; 23.0.91 and this code goes back to '93.
+ ((stringp (car-safe current-load-list)) (car current-load-list))
+
+ ;; load-like things. 'relative-file-expand' tests in
+ ;; test/test-load.el indicates we should put this ahead of
+ ;; $#.
+ (load-file-name)
+
+ ;; Pick up "name of this file as a string" which is set on
+ ;; reading and persists. In contrast, load-file-name is set only
+ ;; inside eval. As such, it won't work when not in the middle of
+ ;; loading.
+ ;; (#$)
+
+ ;; eval-like things
+ ((buffer-file-name))
+
+ ;; When byte compiling. FIXME: use a more thorough precondition like
+ ;; byte-compile-file is somehwere in the backtrace or that
+ ;; bytecomp-filename comes from that routine?
+ ((boundp 'bytecomp-filename) bytecomp-filename)
+
+ (t (symbol-file symbol)) ;; last resort
+ ))
+
+(defun autoload-relative (function-or-list
+ file &optional docstring interactive type
+ symbol)
+ "Autoload an Emacs Lisp file relative to Emacs Lisp code that is in
+the process of being loaded or eval'd.
+
+
+Define FUNCTION to autoload from FILE. FUNCTION is a symbol.
+
+FILE is a string to pass to `load'.
+
+DOCSTRING is documentation for the function.
+
+INTERACATIVE if non-nil says function can be called
+interactively.
+
+TYPE indicates the type of the object: nil or omitted says
+function is a function, `keymap' says function is really a
+keymap, and `macro' or t says function is really a macro. Third
+through fifth args give info about the real definition. They
+default to nil. If function is already defined other than as an
+autoload, this does nothing and returns nil.
+
+SYMBOL is the location of of the file of where that was
+defined (as given by `symbol-file' is used if other methods of
+finding __FILE__ don't work."
+
+ (if (listp function-or-list)
+ (mapcar (lambda(function)
+ (autoload function-or-list
+ (relative-expand-file-name file symbol)
+ docstring interactive type))
+ file)
+ (autoload function-or-list (relative-expand-file-name file symbol)
+ docstring interactive type))
+ )
+
+;;;###autoload
+(defun load-relative (file-or-list &optional symbol)
+ "Load an Emacs Lisp file relative to Emacs Lisp code that is in
+the process of being loaded or eval'd.
+
+FILE-OR-LIST is either a string or a list of strings containing
+files that you want to loaded. If SYMBOL is given, the location of
+of the file of where that was defined (as given by `symbol-file' is used
+if other methods of finding __FILE__ don't work."
+
+ (if (listp file-or-list)
+ (mapcar (lambda(relative-file)
+ (load (relative-expand-file-name relative-file symbol)))
+ file-or-list)
+ (load (relative-expand-file-name file-or-list symbol)))
+ )
+
+(defun relative-expand-file-name(relative-file &optional opt-file)
+ "Expand RELATIVE-FILE relative to the Emacs Lisp code that is in
+the process of being loaded or eval'd.
+
+WARNING: it is best to to run this function before any
+buffer-setting or buffer changing operations."
+ (let ((file (or opt-file (__FILE__) default-directory))
+ (prefix))
+ (unless file
+ (error "Can't expand __FILE__ here and no file name given"))
+ (setq prefix (file-name-directory file))
+ (expand-file-name (concat prefix relative-file))))
+
+;;;###autoload
+(defun require-relative (relative-file &optional opt-file opt-prefix)
+ "Run `require' on an Emacs Lisp file relative to the Emacs Lisp code
+that is in the process of being loaded or eval'd. The symbol used in require
+is the base file name (without directory or file extension) treated as a
+symbol.
+
+WARNING: it is best to to run this function before any
+buffer-setting or buffer changing operations."
+ (let ((require-string-name
+ (concat opt-prefix (file-name-sans-extension
+ (file-name-nondirectory relative-file)))))
+ (require (intern require-string-name)
+ (relative-expand-file-name relative-file opt-file))))
+
+;;;###autoload
+(defmacro require-relative-list (list &optional opt-prefix)
+ "Run `require-relative' on each name in LIST which should be a list of
+strings, each string being the relative name of file you want to run."
+ `(progn
+ (eval-when-compile
+ (require 'cl
+ (dolist (rel-file ,list)
+ (require-relative rel-file (__FILE__) ,opt-prefix))))
+ (dolist (rel-file ,list)
+ (require-relative rel-file (__FILE__) ,opt-prefix))))
+
+;;;###autoload
+(defmacro provide-me ( &optional prefix )
+ "Call `provide' with the feature's symbol name made from
+source-code's file basename sans extension. For example if you
+write (provide-me) inside file ~/lisp/foo.el, this is the same as
+writing: (provide 'foo).
+
+With a prefix, that prefix is prepended to the `provide' So in
+the previous example, if you write (provide-me \"bar-\") this is the
+same as writing (provide 'bar-foo)
+"
+ `(provide (intern (concat ,prefix (file-name-sans-extension
+ (file-name-nondirectory (__FILE__)))))))
+
+(provide-me)
+
+;;; load-relative.el ends here