Files
emacs.d/my-site-start.el
Ralf Zerres dfd4317d2d emacs.d: initial config version
- starting init.el
  just basics (package, use-package, path-handlin)
- include my-site-start.el
  that includes site-start.d directory and imports
  all *.el files in lexical order
- functionality is imported via use-package inside
  the *.el file
  (first run: internet connection is needed to MELPA)
2020-06-03 22:24:55 +02:00

256 lines
9.2 KiB
EmacsLisp

;;; my-site-start.el --- set up personal .emacs.d/site-start.d/
;;
;; Copyright (C) era eriksson <http://www.iki.fi/~era/> 2008-2015
;; License: GPL v2
;; Version: see `my-site-start-version' below
;;
;;; Commentary:
;;
;; The purpose of my-site-start is to simplify maintenance of user libraries.
;; Instead of indefinitely tweaking your .emacs, just create a site-start.d
;; directory and add symlinks to the libraries you want to load into Emacs.
;;
;; See README.md for a more detailed introduction, and the customization
;; variables below for the rest.
;;
;;
;; Github repository / download: <http://github.com/tripleee/my-site-start/>
;;
;;; History:
;;
;; 2015-02-25 Version 0.003 -- moved to Github; update documentation and links
;; 2009-02-09 Version 0.002 -- various tweaks and updated documentation
;; 2009-02-05 Version 0.001 -- first public beta.
;;
;; See changelog and version control history for details.
;;
;;; Code:
(defconst my-site-start-version "0.003"
"Version numer for `my-site-start' library.")
;;;;;;;; FIXME: defcustom
(defvar my-site-start-inhibit-p nil "\
*Set to non-nil to inhibit the running of `my-site-start' when loading.")
(defvar my-site-start-file-name-regex
"\\(\\`\\|/\\)[0-9][0-9][-A-Za-z0-9_+.#$%@]+\.elc?$"
"*Regular expression to select which files to `load' from `my-site-start'.
If you change this setting, you might also need to change other settings.
The assumption that all selected files will have one or more numbers at the
beginning of the file name is present in several other parts of `my-site-start'
and so you will need to change at least `my-site-start-load-order-function'
if this is not true.")
(defvar my-site-start-avoid-dir-regex
(mapconcat
#'regexp-quote
'(
"RCS"
"CVS"
".git"
".svn"
;;;;;;;; TODO: hg, monotone, svk, arch, bzr, others ...?
)
"\\|")
"*Regular expression of directory names to avoid in `my-site-start'
when recursing into a directory tree.
The regular expression is applied in a context where the match is
anchored to the beginning and end of the bare directory name, without
a full path.")
(defvar my-site-start-load-order-function #'my-site-start-sort-load-order
"*Function accepting a list of strings specifying file names to be loaded,
and returning the list in sorted order. Used in `my-site-start' to decide
the order in which to load files.")
(defvar my-site-start-defer-file-p-function #'my-site-start-defer-file-p
"*Function to determine whether loading of a file name should be deferred.
See `my-site-start-do-deferred-loads'.")
(defvar my-site-start--deferred-load-files nil
"List of files to load from `my-site-start-do-deferred-loads'.
\(Internal use only.\)")
(defun my-site-start (dir &optional no-recursion) "\
Add DIR to `load-path' and load files matching `my-site-start-file-name-regex'.
The optional second argument NO-RECURSION says to not traverse any directories.
Those other directories will also be prepended to `load-path'.
Files will be sorted according to the function pointed to by the variable
`my-site-start-load-order-function'.
See also `my-site-start-defer-file-p-function' for controlling deferred
loading of files. The documentation for `my-site-start-do-deferred-loads'
contains further information about this feature. If a file is determined to
belong in the deferred set, it will be loaded only later, from within the
`my-site-start-interactive-setup-hook' hook.
If the value of the variable `my-site-start-inhibit-p' is non-nil,
`my-site-start' will only report which files would have been loaded.
Changes to the `load-path' will also not be made, only reported."
(mapc #'my-site-start-load
(my-site-start-split-deferred
(funcall my-site-start-load-order-function
(my-site-start-files (expand-file-name dir) no-recursion) )
'my-site-start--deferred-load-files) ) )
(defun my-site-start-split-deferred (list variable)
"Move deferred file names from LIST to VARIABLE, and return the rest.
Whether a file is to be deferred or not is determined by the function
pointed to by the variable `my-site-start-defer-file-p-function'."
(let (l f d v)
(while list
(setq f (car list)
list (cdr list) )
(setq v (if (funcall my-site-start-defer-file-p-function f) 'd 'l))
(set v (cons f (symbol-value v))) )
(set variable (append (symbol-value variable) (reverse d)))
(reverse l) ))
(defun my-site-start-load (file)
"Load FILE, unless `my-site-start' loading is inhibited.
If `my-site-start-inhibit-p' is non-nil, just print diagnostics indicating
what would have been done."
(message (if my-site-start-inhibit-p "Would load %s" "Loading %s") file)
(or my-site-start-inhibit-p (load-file file)) )
(defun my-site-start-files (dir no-recursion)
"Return files in DIR which are eligible for loading, obeying NO-RECURSION
i.e. only scanning the current directory if non-nil, otherwise descending
into subdirectories.
DIR is also added to the front of `load-path' unless it is already on the
path \(or `my-site-start-inhibit-p' is non-nil, in which case only log
whether the path would have been added\). If recursing, all traversed
directories will also be added to the path, under the same conditions.
DIR should be an absolute path name.
See `my-site-start-file-name-regex' for determining which files should be
loaded.
If both an `.el' and and `.elc' version of a file exists, only the newer
of the two is returned."
(message (if my-site-start-inhibit-p
(if (member dir load-path) "%s is already on load-path"
"Would add %s to load-path")
"Adding %s to load-path") dir)
(add-to-list 'load-path dir)
(let ((files (directory-files dir 'full-path nil ; no regex to filter on
'dont-sort))
(avoid-re
(concat "\\(\\`\\|/\\)"
"\\("
"\\.\\.?"
"\\|"
my-site-start-avoid-dir-regex
"\\)\\'") )
list file elc)
(save-match-data
(while files
(setq file (car files)
files (cdr files))
(cond
((file-directory-p file)
(or no-recursion
(string-match avoid-re file)
(setq list (append list (my-site-start-files file nil))) ) )
((string-match my-site-start-file-name-regex file)
(if (string-match "\\`\\(.*\\.el\\)c?\\'" file)
(setq file (match-string 1 file)
elc (concat file "c") )
(error "%s is neither .el nor .elc" file) )
(and (file-exists-p file)
(file-exists-p elc)
(file-newer-than-file-p elc file)
(setq file elc) )
(add-to-list 'list file) ) ) ) )
list) )
(defsubst my-site-start-split-filename (filename)
(if (string-match "\\(\\`\\|/\\)\\(\\([0-9][0-9]\\).*\\)\\.elc?\\'" filename)
(cons (string-to-number (match-string 3 filename))
(match-string 2 filename) )
(error "\"%s\" does not look like a valid .el/.elc file name" filename) ) )
(defun my-site-start-sort-load-order (list)
"Return the file names in LIST sorted numerically by basename.
This function assumes file names adhere to the convention of having a leading
numeric prefix to decide the load order, and will fail if this is not the
case."
(sort list
(function
(lambda (aa bb)
(save-match-data
(let ((a (my-site-start-split-filename aa))
(b (my-site-start-split-filename bb)))
(if (= (car a) (car b))
(string-lessp (cdr a) (cdr b))
(< (car a) (car b)) ) ) ))) ) )
(defun my-site-start-do-deferred-loads ()
"Load all files whose loading was deferred from `my-site-start'.
Load all files from the list `my-site-start--deferred-load-files'.
The value of `my-site-stat--deferred-load-files' is then set to nil.
The default `my-site-start-interactive-setup-hook' calls this function.
By convention, features which are only useful for interactive use should
be deferred, which in practice means they will only be loaded when Emacs
is started for interactive use \(and not, for example, from within a script,
say, to batch compile some Lisp files\).
Furthermore, the default `my-site-start-defer-file-p' function encodes the
convention that file names with a numeric prefix larger than 99 will be
deferred. See furthermore `my-site-start-defer-file-p-function' if you
wish to override this behavior."
(mapc #'my-site-start-load my-site-start--deferred-load-files)
(setq my-site-start--deferred-load-files nil) )
(defun my-site-start-defer-file-p (file)
"Return non-nil if FILE has a numeric prefix strictly bigger than 99.
This function is used as `my-site-start-defer-file-p-function' by default,
and implements the simple policy that a file name with a numeric prefix
larger than 99 names a file whose loading should be deferred."
(save-match-data
(string-match "\\`\\(.*/\\)?0*[1-9][0-9][0-9][^/]*\\'" file) ) )
(defvar my-site-start-interactive-setup-hook
(list (function my-site-start-do-deferred-loads))
"Hook run at the end of loading user's startup files, if running on a terminal.
This provides a facility for deferring loading of features which are only
useful in interactive use, but not e.g. when batch-compiling Elisp files.
By default, the hook runs `my-site-start-do-deferred-loads'.
Technically, this hook is run from `term-setup-hook' in turn.")
(add-hook 'term-setup-hook
'(lambda nil (run-hooks 'my-site-start-interactive-setup-hook)) )
;; This isn't really meant to be `require'd, but what the hey
(provide 'my-site-start)
;;; my-site-start.el ends here