Ignore uninteresting files.
[skel] / skel.el.in
CommitLineData
7fb0878b 1;;; -*-emacs-lisp-*-
2;;;
3;;; $Id: skel.el.in,v 1.1 1999/04/05 13:44:59 mdw Exp $
4;;;
5;;; Filling in skeletons
6;;;
7;;; (c) 1998 Mark Wooding
8;;;
9
10;;;----- Licensing notice ---------------------------------------------------
11;;;
12;;; This program is free software; you can redistribute it and/or modify
13;;; it under the terms of the GNU General Public License as published by
14;;; the Free Software Foundation; either version 2 of the License, or
15;;; (at your option) any later version.
16;;;
17;;; This program is distributed in the hope that it will be useful,
18;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;;; GNU General Public License for more details.
21;;;
22;;; You should have received a copy of the GNU General Public License
23;;; along with this program; if not, write to the Free Software Foundation,
24;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26;;;----- Revision history ---------------------------------------------------
27;;;
28;;; $Log: skel.el.in,v $
29;;; Revision 1.1 1999/04/05 13:44:59 mdw
30;;; Initial revision
31;;;
32
33;;;----- Variables (largely tweakable) --------------------------------------
34
35(defvar skel-directory-list '(".skel" "")
36 "*List of directory names which contain skeleton files.")
37
38(defvar skel-skeleton-path '("@skeldir@" "~/skel" "~/src/skel")
39 "*List of directories to search for skeleton data anyway.")
40
41(defvar skel-skelrc '(".skelrc" "skelrc")
42 "*File containing skeleton substitution data, looked up using the standard
43skeleton search mathod.")
44
45(defvar skel-alist '()
46 "Alist of values to substitute into a skeleton. It is filled in by skelrc
47files and user interaction.
48
49The alist's keys are symbols, interned from the placeholder strings in the
50skeleton file. The values are forms to be evaluated. In the simplest case,
51the form is a string added as a result of user interaction; however, it could
52just as easily be a function call or something similarly complicated.")
53
54;;;----- Finding skeleton files ---------------------------------------------
55
56(defun skel-do-join (acc jfun ll s)
57 "Recursive guts of skel-join."
58 (if ll
59 (if (car ll)
60 (skel-do-join (skel-do-join acc jfun (cdr ll)
61 (funcall jfun s (car (car ll))))
62 jfun (cons (cdr (car ll)) (cdr ll)) s)
63 acc)
64 (cons s acc)))
65
66(defun skel-join (jfun base &rest ll)
67 "Return a list built from joining elements from the given lists in order,
68left to right. JFUN is a function of two arguments which can join items
69together. BASE is the initial item."
70 (nreverse (skel-do-join nil jfun ll base)))
71
72(defun skel-do-parents (dir acc)
73 "Tail recursive guts of skel-parents"
74 (setq acc (cons dir acc))
75 (setq dir (substring dir 0 (string-match "/[^/]*/?$" dir)))
76 (if (string= dir "")
77 (cons "/" acc)
78 (skel-do-parents dir acc)))
79
80(defun skel-parents (dir)
81 "Returns a list of DIR, DIR's parent directory, etc., all the way up to the
82root."
83 (setq dir (expand-file-name dir))
84 (nreverse (skel-do-parents dir nil)))
85
86(defun skel-do-find (l all acc)
87 (if l
88 (let ((n (car l)))
89 (if (and (file-readable-p n) (file-regular-p n))
90 (if all
91 (skel-do-find (cdr l) all (cons (abbreviate-file-name n) acc))
92 (abbreviate-file-name n))
93 (skel-do-find (cdr l) all acc)))
94 acc))
95
96(defun skel-find-skeleton (name &optional all acc)
97 "Searches for skeleton files. NAME is the name of the file to find, or
98a list of possible names.
99
100If ALL is nil, or omitted, return only the first matching filename
101encountered. Otherwise, return a list of all matching names, most `global'
102first. ACC is a base list to which the matching filenames are prepended."
103
104 ;; --- Build one big list of all the possible names ---
105
106 (let ((l (skel-join (lambda (x y) (if (string= y "")
107 x
108 (expand-file-name y x)))
109 nil
110 (append (skel-parents default-directory)
111 skel-skeleton-path)
112 skel-directory-list
113 (if (listp name) name (cons name nil)))))
114
115 ;; --- Now filter out any which aren't interesting ---
116
117 (skel-do-find l all acc)))
118
119;;;----- Processing file skeletons ------------------------------------------
120
121(defun skel-include (file)
122 "Includes the skeleton rc FILE."
123 (let ((rc (skel-find-skeleton file t)))
124 (while rc
125 (load (car rc) nil t t)
126 (setq rc (cdr rc)))))
127
128(defun skel-lookup (name)
129
130 "Reads the value of symbol NAME in skel-alist. If there is no currrent
131value, the user is prompted for one."
132
133 ;; --- Resolve NAME into a symbol ---
134
135 (if (stringp name)
136 (setq name (intern name)))
137
138 ;; --- Look up the value ---
139 ;;
140 ;; Add it to the list if we've not seen it before. Protect ourselves
141 ;; against functions which do regexp matching.
142
143 (let ((pair (assq name skel-alist))
144 value)
145 (if pair
146 (save-match-data (setq value (eval (cdr pair))))
147 (setq value (read-string (format "Value for %s: " name)))
148 (setq skel-alist (cons (cons name value) skel-alist)))
149 value))
150
151(defun skel-do-fill-in ()
152 "Does the actual donkey-work of filling in a file. For each fill-in area
153in the current buffer, the function looks to see if the item in question has
154been entered into ALIST: if so, it is replaced automatically; otherwise the
155user is promted to enter a string to substitute into the buffer at this
156point."
157 (if (re-search-forward "\\[\\[\\([^]]*\\)\\]\\]" nil t)
158 (progn
159 (replace-match (skel-lookup (match-string 1)) t t nil)
160 (goto-char (match-beginning 0))
161 (skel-do-fill-in))))
162
163;;;----- Creating new files from skeletons ----------------------------------
164
165(defun skel-do-create-file (name switch &optional skel)
166
167 "Does the main work of creating a file based on a skeleton. The SWITCH
168argument is called to display the buffer."
169
170 ;; --- Some local variables ---
171 ;;
172 ;; This is a little bit of a hack, but do I look like someone who cares?
173
174 (let (ext rc)
175
176 ;; --- Find out if the file's there already ---
177
178 (if (file-exists-p name)
179 (or (yes-or-no-p
180 (format "File %s already exists. Overwrite? " name))
181 (error "Aborted!")))
182
183 ;; --- Fiddle with the filename ---
184
185 (cond ((stringp skel) (let ((extind (string-match "\.[^.]*$" skel)))
186 (setq ext (and extind (substring skel extind)))))
187 (skel (progn
188 (setq ext (read-string "Extension: "))
189 (or (string= ext "") (setq ext (concat "." ext)))))
190 (t (let ((extind (string-match "\.[^.]*$" name)))
191 (setq ext (and extind (substring name extind))))))
192 (setq skel (concat "skeleton" (or ext "")))
193
194 ;; --- Find the skeleton filename ---
195
196 (setq skel (or (skel-find-skeleton skel)
197 (skel-find-skeleton "skeleton")
198 (error "Couldn't find skeleton file %s" skel)))
199
200 ;; --- Visit the file and destroy its contents ---
201
202 (funcall switch (find-file-noselect name))
203 (kill-region (point-min) (point-max))
204 (insert-file skel)
205
206 ;; --- Mangle the skeleton data in the file ---
207
208 (make-local-variable 'skel-alist)
209 (setq skel-alist '())
210
211 ;; --- Read the default values to insert ---
212
213 (let ((rc (append
214 (skel-find-skeleton skel-skelrc t)
215 (and ext
216 (skel-find-skeleton
217 (if (listp skel-skelrc)
218 (mapcar (lambda (x) (concat x ext)) skel-skelrc)
219 (concat skel-skelrc ext))
220 t)))))
221 (while rc
222 (load (car rc) nil t t)
223 (setq rc (cdr rc))))
224
225 ;; --- Now do substitution ---
226
227 (skel-do-fill-in)
228 (not-modified)))
229
230;;;----- User commands ------------------------------------------------------
231
232(defun skel-create-file (name &optional skel)
233 "Creates a new file called NAME and visits it. If SKEL is non-`nil', it is
234the name of a skeleton file to insert and substitute. Otherwise the skeleton
235file's name is derived from NAME by taking NAME's extension and appending it
236to `skel'."
237 (interactive "FSkeleton create file: \nP")
238 (skel-do-create-file name 'switch-to-buffer skel))
239
240(defun skel-create-file-other-window (name &optional skel)
241 "Like skel-create-file, but in another window."
242 (interactive "FSkeleton create file in other window: \nP")
243 (skel-do-create-file name 'switch-to-buffer-other-window skel))
244
245(defun skel-create-file-other-frame (name &optional skel)
246 "Like skel-create-file, but in another frame."
247 (interactive "FSkeleton create file in other frame: \nP")
248 (skel-do-create-file name 'switch-to-buffer-other-frame skel))
249
250;;;----- Is that all there is? ----------------------------------------------
251
252(provide 'skel)