(latexenc-find-file-coding-system): Don't inherit the EOL part of the
[emacs.git] / lisp / emacs-lisp / generic.el
blob4d778bf35c6f11b226bf8c398736b027287f08e2
1 ;;; generic.el --- defining simple major modes with comment and font-lock
2 ;;
3 ;; Copyright (C) 1997, 1999, 2004, 2005 Free Software Foundation, Inc.
4 ;;
5 ;; Author: Peter Breton <pbreton@cs.umb.edu>
6 ;; Created: Fri Sep 27 1996
7 ;; Keywords: generic, comment, font-lock
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
26 ;;; Commentary:
28 ;; INTRODUCTION:
30 ;; The macro `define-generic-mode' can be used to define small modes
31 ;; which provide basic comment and font-lock support. These modes are
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.
36 ;; Each generic mode can define the following:
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.
48 ;; * List of keywords to font-lock. Each keyword should be a string.
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:
54 ;; * Additional expressions to font-lock. This should be a list of
55 ;; expressions, each of which should be of the same form as those in
56 ;; `font-lock-keywords'.
58 ;; * List of regular expressions to be placed in auto-mode-alist.
60 ;; * List of functions to call to do some additional setup
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!
66 ;; EXAMPLE:
68 ;; You can use `define-generic-mode' like this:
70 ;; (define-generic-mode 'foo-generic-mode
71 ;; (list ?%)
72 ;; (list "keyword")
73 ;; nil
74 ;; (list "\\.FOO\\'")
75 ;; (list 'foo-setup-function))
77 ;; to define a new generic-mode `foo-generic-mode', which has '%' as a
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.
84 ;; GOTCHAS:
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.
90 ;; Credit for suggestions, brainstorming, help with debugging:
91 ;; ACorreir@pervasive-sw.com (Alfred Correira)
92 ;; Extensive cleanup by:
93 ;; Stefan Monnier (monnier+gnu/emacs@flint.cs.yale.edu)
95 ;;; Code:
97 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
98 ;; Internal Variables
99 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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)
104 (defvaralias 'generic-font-lock-defaults 'generic-font-lock-keywords)
105 (make-obsolete-variable 'generic-font-lock-defaults 'generic-font-lock-keywords "22.1")
107 ;;;###autoload
108 (defvar generic-mode-list nil
109 "A list of mode names for `generic-mode'.
110 Do not add entries to this list directly; use `define-generic-mode'
111 instead (which see).")
113 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
114 ;; Functions
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
117 ;;;###autoload
118 (defmacro define-generic-mode (mode comment-list keyword-list
119 font-lock-list auto-mode-list
120 function-list &optional docstring)
121 "Create a new generic mode MODE.
123 MODE is the name of the command for the generic mode; don't quote it.
124 The optional DOCSTRING is the documentation for the mode command. If
125 you do not supply it, `define-generic-mode' uses a default
126 documentation string instead.
128 COMMENT-LIST is a list in which each element is either a character, a
129 string of one or two characters, or a cons cell. A character or a
130 string is set up in the mode's syntax table as a \"comment starter\".
131 If the entry is a cons cell, the `car' is set up as a \"comment
132 starter\" and the `cdr' as a \"comment ender\". (Use nil for the
133 latter if you want comments to end at the end of the line.) Note that
134 the syntax table has limitations about what comment starters and
135 enders are actually possible.
137 KEYWORD-LIST is a list of keywords to highlight with
138 `font-lock-keyword-face'. Each keyword should be a string.
140 FONT-LOCK-LIST is a list of additional expressions to highlight. Each
141 element of this list should have the same form as an element of
142 `font-lock-keywords'.
144 AUTO-MODE-LIST is a list of regular expressions to add to
145 `auto-mode-alist'. These regular expressions are added when Emacs
146 runs the macro expansion.
148 FUNCTION-LIST is a list of functions to call to do some additional
149 setup. The mode command calls these functions just before it runs the
150 mode hook `MODE-hook'.
152 See the file generic-x.el for some examples of `define-generic-mode'."
153 (declare (debug (sexp def-form def-form def-form form def-form
154 [&optional stringp] &rest [keywordp form]))
155 (indent 1))
157 ;; Backward compatibility.
158 (when (eq (car-safe mode) 'quote)
159 (setq mode (eval mode)))
161 (let* ((name (symbol-name mode))
162 (pretty-name (capitalize (replace-regexp-in-string
163 "-mode\\'" "" name))))
165 `(progn
166 ;; Add a new entry.
167 (add-to-list 'generic-mode-list ,name)
169 ;; Add it to auto-mode-alist
170 (dolist (re ,auto-mode-list)
171 (add-to-list 'auto-mode-alist (cons re ',mode)))
173 (defun ,mode ()
174 ,(or docstring
175 (concat pretty-name " mode.\n"
176 "This a generic mode defined with `define-generic-mode'.\n"
177 "It runs `" name "-hook' as the last thing it does."))
178 (interactive)
179 (generic-mode-internal ',mode ,comment-list ,keyword-list
180 ,font-lock-list ,function-list)))))
182 ;;;###autoload
183 (defun generic-mode-internal (mode comment-list keyword-list
184 font-lock-list function-list)
185 "Go into the generic mode MODE."
186 (let* ((name (symbol-name mode))
187 (pretty-name (capitalize (replace-regexp-in-string
188 "-mode\\'" "" name)))
189 (mode-hook (intern (concat name "-hook"))))
191 (kill-all-local-variables)
193 (setq major-mode mode
194 mode-name pretty-name)
196 (generic-mode-set-comments comment-list)
198 ;; Font-lock functionality.
199 ;; Font-lock-defaults is always set even if there are no keywords
200 ;; or font-lock expressions, so comments can be highlighted.
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))
205 (setq font-lock-defaults '(generic-font-lock-keywords))
207 ;; Call a list of functions
208 (mapcar 'funcall function-list)
210 (run-mode-hooks mode-hook)))
212 ;;;###autoload
213 (defun generic-mode (mode)
214 "Enter generic mode MODE.
216 Generic modes provide basic comment and font-lock functionality
217 for \"generic\" files. (Files which are too small to warrant their
218 own mode, but have comment characters, keywords, and the like.)
220 To define a generic-mode, use the function `define-generic-mode'.
221 Some generic modes are defined in `generic-x.el'."
222 (interactive
223 (list (completing-read "Generic mode: " generic-mode-list nil t)))
224 (funcall (intern mode)))
226 ;;; Comment Functionality
227 (defun generic-mode-set-comments (comment-list)
228 "Set up comment functionality for generic mode."
229 (let ((st (make-syntax-table))
230 (chars nil)
231 (comstyles))
232 (make-local-variable 'comment-start)
233 (make-local-variable 'comment-start-skip)
234 (make-local-variable 'comment-end)
236 ;; Go through all the comments
237 (dolist (start comment-list)
238 (let (end (comstyle ""))
239 ;; Normalize
240 (when (consp start)
241 (setq end (cdr start))
242 (setq start (car start)))
243 (when (char-valid-p start) (setq start (char-to-string start)))
244 (cond
245 ((char-valid-p end) (setq end (char-to-string end)))
246 ((zerop (length end)) (setq end "\n")))
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)
257 (setq comment-end (if (string-equal end "\n") "" end))
258 (setq comment-start-skip (concat (regexp-quote start) "+\\s-*")))
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)
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)))))
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)))
294 (defun generic-bracket-support ()
295 "Imenu support for [KEYWORD] constructs found in INF, INI and Samba files."
296 (setq imenu-generic-expression
297 '((nil "^\\[\\(.*\\)\\]" 1))
298 imenu-case-fold-search t))
300 ;;;###autoload
301 (defun generic-make-keywords-list (keyword-list face &optional prefix suffix)
302 "Return a `font-lock-keywords' construct that highlights KEYWORD-LIST.
303 KEYWORD-LIST is a list of keyword strings that should be
304 highlighted with face FACE. This function calculates a regular
305 expression that matches these keywords and concatenates it with
306 PREFIX and SUFFIX. Then it returns a construct based on this
307 regular expression that can be used as an element of
308 `font-lock-keywords'."
309 (unless (listp keyword-list)
310 (error "Keywords argument must be a list of strings"))
311 (list (concat prefix "\\_<"
312 ;; Use an optimized regexp.
313 (regexp-opt keyword-list t)
314 "\\_>" suffix)
316 face))
318 (provide 'generic)
320 ;; arch-tag: 239c1fc4-1303-48d9-9ac0-657d655669ea
321 ;;; generic.el ends here