Add "Package:" file headers to denote built-in packages.
[bpt/emacs.git] / lisp / emacs-lisp / generic.el
CommitLineData
e8af40ee 1;;; generic.el --- defining simple major modes with comment and font-lock
89ada4dd 2;;
d59c3137 3;; Copyright (C) 1997, 1999, 2001, 2002, 2003, 2004,
114f9c96 4;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
89ada4dd 5;;
6fe8a37a 6;; Author: Peter Breton <pbreton@cs.umb.edu>
89ada4dd
RS
7;; Created: Fri Sep 27 1996
8;; Keywords: generic, comment, font-lock
bd78fa1d 9;; Package: emacs
89ada4dd
RS
10
11;; This file is part of GNU Emacs.
12
d6cba7ae 13;; GNU Emacs is free software: you can redistribute it and/or modify
89ada4dd 14;; it under the terms of the GNU General Public License as published by
d6cba7ae
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
89ada4dd
RS
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
d6cba7ae 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
89ada4dd 25
89ada4dd
RS
26;;; Commentary:
27
28;; INTRODUCTION:
9aade6c6
LK
29;;
30;; The macro `define-generic-mode' can be used to define small modes
02f853b5 31;; which provide basic comment and font-lock support. These modes are
ea67f0ce
LK
32;; intended for the many configuration files and such which are too
33;; small for a "real" mode, but still have a regular syntax, comment
34;; characters and the like.
89ada4dd
RS
35;;
36;; Each generic mode can define the following:
37;;
74919c6f
LK
38;; * List of comment-characters. The elements of this list should be
39;; either a character, a one or two character string, or a cons
40;; cell. If the entry is a character or a string, it is added to
41;; the mode's syntax table with "comment starter" syntax. If the
42;; entry is a cons cell, the `car' and `cdr' of the pair are
43;; considered the "comment starter" and "comment ender"
44;; respectively. (The latter should be nil if you want comments to
45;; end at the end of the line.) Emacs does not support comment
46;; strings of more than two characters in length.
89ada4dd 47;;
02f853b5 48;; * List of keywords to font-lock. Each keyword should be a string.
ea67f0ce
LK
49;; If you have additional keywords which should be highlighted in a
50;; face different from `font-lock-keyword-face', you can use the
51;; convenience function `generic-make-keywords-list' (which see),
52;; and add the result to the following list:
9a7f629d 53;;
02f853b5 54;; * Additional expressions to font-lock. This should be a list of
ea67f0ce
LK
55;; expressions, each of which should be of the same form as those in
56;; `font-lock-keywords'.
9a7f629d 57;;
89ada4dd
RS
58;; * List of regular expressions to be placed in auto-mode-alist.
59;;
60;; * List of functions to call to do some additional setup
61;;
62;; This should pretty much cover basic functionality; if you need much
63;; more than this, or you find yourself writing extensive customizations,
64;; perhaps you should be writing a major mode instead!
65;;
9aade6c6 66;; EXAMPLE:
89ada4dd 67;;
9aade6c6 68;; You can use `define-generic-mode' like this:
89ada4dd 69;;
89ada4dd 70;; (define-generic-mode 'foo-generic-mode
ea67f0ce
LK
71;; (list ?%)
72;; (list "keyword")
73;; nil
74;; (list "\\.FOO\\'")
75;; (list 'foo-setup-function))
89ada4dd 76;;
9aade6c6 77;; to define a new generic-mode `foo-generic-mode', which has '%' as a
ea67f0ce
LK
78;; comment character, and "keyword" as a keyword. When files which
79;; end in '.FOO' are loaded, Emacs will go into foo-generic-mode and
80;; call foo-setup-function. You can also use the function
81;; `foo-generic-mode' (which is interactive) to put a buffer into
82;; foo-generic-mode.
89ada4dd 83;;
89ada4dd
RS
84;; GOTCHAS:
85;;
ea67f0ce
LK
86;; Be careful that your font-lock definitions are correct. Getting
87;; them wrong can cause Emacs to continually attempt to fontify! This
88;; problem is not specific to generic-mode.
89ada4dd 89
5027054f 90;; Credit for suggestions, brainstorming, help with debugging:
89ada4dd 91;; ACorreir@pervasive-sw.com (Alfred Correira)
9a7f629d
PB
92;; Extensive cleanup by:
93;; Stefan Monnier (monnier+gnu/emacs@flint.cs.yale.edu)
9aade6c6 94
89ada4dd
RS
95;;; Code:
96
97;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
728f84dc 98;; Internal Variables
89ada4dd
RS
99;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100
fbc5e359
LK
101(defvar generic-font-lock-keywords nil
102 "Keywords for `font-lock-defaults' in a generic mode.")
103(make-variable-buffer-local 'generic-font-lock-keywords)
bda2c1ff 104(define-obsolete-variable-alias 'generic-font-lock-defaults 'generic-font-lock-keywords "22.1")
89ada4dd 105
ea67f0ce 106;;;###autoload
9a7f629d
PB
107(defvar generic-mode-list nil
108 "A list of mode names for `generic-mode'.
25e928b0 109Do not add entries to this list directly; use `define-generic-mode'
89ada4dd
RS
110instead (which see).")
111
89ada4dd
RS
112;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
113;; Functions
114;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
115
1d96c2ff 116;;;###autoload
ea67f0ce
LK
117(defmacro define-generic-mode (mode comment-list keyword-list
118 font-lock-list auto-mode-list
7e803501 119 function-list &optional docstring)
ea67f0ce
LK
120 "Create a new generic mode MODE.
121
7e803501
LK
122MODE is the name of the command for the generic mode; don't quote it.
123The optional DOCSTRING is the documentation for the mode command. If
124you do not supply it, `define-generic-mode' uses a default
125documentation string instead.
ea67f0ce 126
7e803501
LK
127COMMENT-LIST is a list in which each element is either a character, a
128string of one or two characters, or a cons cell. A character or a
129string is set up in the mode's syntax table as a \"comment starter\".
130If the entry is a cons cell, the `car' is set up as a \"comment
131starter\" and the `cdr' as a \"comment ender\". (Use nil for the
132latter if you want comments to end at the end of the line.) Note that
133the syntax table has limitations about what comment starters and
134enders are actually possible.
ea67f0ce
LK
135
136KEYWORD-LIST is a list of keywords to highlight with
137`font-lock-keyword-face'. Each keyword should be a string.
138
7e803501
LK
139FONT-LOCK-LIST is a list of additional expressions to highlight. Each
140element of this list should have the same form as an element of
141`font-lock-keywords'.
ea67f0ce
LK
142
143AUTO-MODE-LIST is a list of regular expressions to add to
7e803501
LK
144`auto-mode-alist'. These regular expressions are added when Emacs
145runs the macro expansion.
ea67f0ce 146
7e803501
LK
147FUNCTION-LIST is a list of functions to call to do some additional
148setup. The mode command calls these functions just before it runs the
149mode hook `MODE-hook'.
c85465f9 150
02f853b5 151See the file generic-x.el for some examples of `define-generic-mode'."
7cbf93e0 152 (declare (debug (sexp def-form def-form def-form form def-form
5eee025d 153 [&optional stringp] &rest [keywordp form]))
7cbf93e0 154 (indent 1))
66e181ad
LK
155
156 ;; Backward compatibility.
157 (when (eq (car-safe mode) 'quote)
158 (setq mode (eval mode)))
c85465f9 159
5eee025d 160 (let* ((name (symbol-name mode))
ea67f0ce 161 (pretty-name (capitalize (replace-regexp-in-string
7e803501 162 "-mode\\'" "" name))))
ea67f0ce
LK
163
164 `(progn
165 ;; Add a new entry.
5eee025d 166 (add-to-list 'generic-mode-list ,name)
ea67f0ce
LK
167
168 ;; Add it to auto-mode-alist
169 (dolist (re ,auto-mode-list)
66e181ad 170 (add-to-list 'auto-mode-alist (cons re ',mode)))
ea67f0ce 171
66e181ad 172 (defun ,mode ()
ea67f0ce
LK
173 ,(or docstring
174 (concat pretty-name " mode.\n"
7e803501
LK
175 "This a generic mode defined with `define-generic-mode'.\n"
176 "It runs `" name "-hook' as the last thing it does."))
ea67f0ce 177 (interactive)
66e181ad 178 (generic-mode-internal ',mode ,comment-list ,keyword-list
ea67f0ce 179 ,font-lock-list ,function-list)))))
89ada4dd 180
ea67f0ce 181;;;###autoload
66e181ad
LK
182(defun generic-mode-internal (mode comment-list keyword-list
183 font-lock-list function-list)
ea67f0ce 184 "Go into the generic mode MODE."
5eee025d 185 (let* ((name (symbol-name mode))
ea67f0ce 186 (pretty-name (capitalize (replace-regexp-in-string
5eee025d
LK
187 "-mode\\'" "" name)))
188 (mode-hook (intern (concat name "-hook"))))
ea67f0ce 189
89ada4dd
RS
190 (kill-all-local-variables)
191
ea67f0ce
LK
192 (setq major-mode mode
193 mode-name pretty-name)
89ada4dd 194
66e181ad 195 (generic-mode-set-comments comment-list)
89ada4dd 196
fbc5e359
LK
197 ;; Font-lock functionality.
198 ;; Font-lock-defaults is always set even if there are no keywords
89ada4dd 199 ;; or font-lock expressions, so comments can be highlighted.
9aade6c6
LK
200 (setq generic-font-lock-keywords font-lock-list)
201 (when keyword-list
202 (push (concat "\\_<" (regexp-opt keyword-list t) "\\_>")
203 generic-font-lock-keywords))
8af0371d 204 (setq font-lock-defaults '(generic-font-lock-keywords))
89ada4dd
RS
205
206 ;; Call a list of functions
ba215373 207 (mapc 'funcall function-list)
9b544de1 208
66e181ad 209 (run-mode-hooks mode-hook)))
89ada4dd
RS
210
211;;;###autoload
ea67f0ce
LK
212(defun generic-mode (mode)
213 "Enter generic mode MODE.
214
215Generic modes provide basic comment and font-lock functionality
216for \"generic\" files. (Files which are too small to warrant their
217own mode, but have comment characters, keywords, and the like.)
89ada4dd
RS
218
219To define a generic-mode, use the function `define-generic-mode'.
25e928b0 220Some generic modes are defined in `generic-x.el'."
89ada4dd 221 (interactive
ea67f0ce
LK
222 (list (completing-read "Generic mode: " generic-mode-list nil t)))
223 (funcall (intern mode)))
89ada4dd
RS
224
225;;; Comment Functionality
226(defun generic-mode-set-comments (comment-list)
227 "Set up comment functionality for generic mode."
9a7f629d
PB
228 (let ((st (make-syntax-table))
229 (chars nil)
230 (comstyles))
ea67f0ce
LK
231 (make-local-variable 'comment-start)
232 (make-local-variable 'comment-start-skip)
233 (make-local-variable 'comment-end)
9a7f629d
PB
234
235 ;; Go through all the comments
236 (dolist (start comment-list)
ea67f0ce 237 (let (end (comstyle ""))
9a7f629d
PB
238 ;; Normalize
239 (when (consp start)
ea67f0ce 240 (setq end (cdr start))
9a7f629d 241 (setq start (car start)))
93fd8eeb 242 (when (characterp start) (setq start (char-to-string start)))
0e7acedf 243 (cond
000fc2b1 244 ((characterp end) (setq end (char-to-string end)))
0e7acedf 245 ((zerop (length end)) (setq end "\n")))
9a7f629d
PB
246
247 ;; Setup the vars for `comment-region'
248 (if comment-start
249 ;; We have already setup a comment-style, so use style b
250 (progn
251 (setq comstyle "b")
252 (setq comment-start-skip
253 (concat comment-start-skip "\\|" (regexp-quote start) "+\\s-*")))
254 ;; First comment-style
255 (setq comment-start start)
1ac1fa96 256 (setq comment-end (if (string-equal end "\n") "" end))
9a7f629d
PB
257 (setq comment-start-skip (concat (regexp-quote start) "+\\s-*")))
258
259 ;; Reuse comstyles if necessary
260 (setq comstyle
261 (or (cdr (assoc start comstyles))
262 (cdr (assoc end comstyles))
263 comstyle))
264 (push (cons start comstyle) comstyles)
265 (push (cons end comstyle) comstyles)
266
267 ;; Setup the syntax table
268 (if (= (length start) 1)
269 (modify-syntax-entry (string-to-char start)
270 (concat "< " comstyle) st)
271 (let ((c0 (elt start 0)) (c1 (elt start 1)))
272 ;; Store the relevant info but don't update yet
273 (push (cons c0 (concat (cdr (assoc c0 chars)) "1")) chars)
274 (push (cons c1 (concat (cdr (assoc c1 chars))
275 (concat "2" comstyle))) chars)))
276 (if (= (length end) 1)
277 (modify-syntax-entry (string-to-char end)
278 (concat ">" comstyle) st)
279 (let ((c0 (elt end 0)) (c1 (elt end 1)))
280 ;; Store the relevant info but don't update yet
281 (push (cons c0 (concat (cdr (assoc c0 chars))
282 (concat "3" comstyle))) chars)
283 (push (cons c1 (concat (cdr (assoc c1 chars)) "4")) chars)))))
284
285 ;; Process the chars that were part of a 2-char comment marker
286 (dolist (cs (nreverse chars))
287 (modify-syntax-entry (car cs)
288 (concat (char-to-string (char-syntax (car cs)))
289 " " (cdr cs))
290 st))
291 (set-syntax-table st)))
89ada4dd 292
89ada4dd 293(defun generic-bracket-support ()
fbc5e359 294 "Imenu support for [KEYWORD] constructs found in INF, INI and Samba files."
25e928b0 295 (setq imenu-generic-expression
c0b08eb0
DL
296 '((nil "^\\[\\(.*\\)\\]" 1))
297 imenu-case-fold-search t))
89ada4dd 298
ef300cff 299;;;###autoload
9aade6c6
LK
300(defun generic-make-keywords-list (keyword-list face &optional prefix suffix)
301 "Return a `font-lock-keywords' construct that highlights KEYWORD-LIST.
302KEYWORD-LIST is a list of keyword strings that should be
303highlighted with face FACE. This function calculates a regular
304expression that matches these keywords and concatenates it with
305PREFIX and SUFFIX. Then it returns a construct based on this
306regular expression that can be used as an element of
307`font-lock-keywords'."
308 (unless (listp keyword-list)
9a7f629d 309 (error "Keywords argument must be a list of strings"))
5c2137b8 310 (list (concat prefix "\\_<"
4eea26a9 311 ;; Use an optimized regexp.
9aade6c6 312 (regexp-opt keyword-list t)
5c2137b8 313 "\\_>" suffix)
4eea26a9 314 1
5204a3a0 315 face))
89ada4dd 316
8e9caa8f 317(provide 'generic)
89ada4dd 318
0e7acedf 319;; arch-tag: 239c1fc4-1303-48d9-9ac0-657d655669ea
25e928b0 320;;; generic.el ends here