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