-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmy-site-start.el
259 lines (206 loc) · 9.27 KB
/
my-site-start.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
;;; 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:
;(require 'subr) ; Not necessary, and doesn't (provide 'subr)
(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"
"_darcs"
;;;;;;;; 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