Mercurial > hg > xemacs
comparison generic-mode.el @ 18:2a3055313d1e
*** empty log message ***
author | ht |
---|---|
date | Sat, 19 Apr 2008 19:10:28 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
17:ee87d53174b1 | 18:2a3055313d1e |
---|---|
1 ;;; generic-mode.el --- A meta-mode which makes it easy to create small | |
2 ;; modes with basic comment and font-lock support | |
3 ;; | |
4 ;; Author: Peter Breton | |
5 ;; Created: Fri Sep 27 1996 | |
6 ;; Version: $Header$ | |
7 ;; Keywords: generic, comment, font-lock | |
8 ;; Time-stamp: <97/03/25 10:10:19 pbreton> | |
9 ;; | |
10 ;; Copyright (C) Peter Breton 01Nov96 | |
11 ;; | |
12 ;; This 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, or (at your option) | |
15 ;; any later version. | |
16 ;; | |
17 ;; generic-mode.el 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 GNU | |
20 ;; General Public License for more details. | |
21 ;; | |
22 ;; You should have received a copy of the GNU General Public License | |
23 ;; along with GNU Emacs; see the file COPYING. If not, write to | |
24 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 ;; | |
26 ;; LCD Archive Entry: | |
27 ;; generic-mode|Peter Breton|pbreton@i-kinetics.com| | |
28 ;; Meta-mode to create small modes with basic comment and font-lock support| | |
29 ;; 01-Nov-1996|1.0|~/misc/generic-mode.el.gz| | |
30 ;; | |
31 ;; Purpose: | |
32 ;; | |
33 ;; Meta-mode to create small modes with basic comment and font-lock support | |
34 ;; | |
35 ;;; Commentary: | |
36 ;; | |
37 ;; INTRODUCTION: | |
38 ;; | |
39 ;; Generic-mode is a meta-mode which can be used to define small modes | |
40 ;; which provide basic comment and font-lock support. These modes are | |
41 ;; intended for the many configuration files and such which are too small | |
42 ;; for a "real" mode, but still have a regular syntax, comment characters | |
43 ;; and the like. | |
44 ;; | |
45 ;; Each generic mode can define the following: | |
46 ;; | |
47 ;; * List of comment-characters. The entries in this list should be | |
48 ;; either a character, a one or two character string or a cons pair. | |
49 ;; If the entry is a character or a one-character string | |
50 ;; LIMITATIONS: Emacs does not support comment strings of more than | |
51 ;; two characters in length. | |
52 ;; | |
53 ;; * List of keywords to font-lock. Each keyword should be a string. | |
54 ;; If you have additional keywords which should be highlighted in a face | |
55 ;; different from 'font-lock-keyword-face', you can use the convenience | |
56 ;; function 'generic-make-keywords-list' (which see), and add the | |
57 ;; result to the following list: | |
58 ;; | |
59 ;; * Additional expressions to font-lock. This should be a list of | |
60 ;; expressions, each of which should be of the same form | |
61 ;; as those in 'font-lock-defaults-alist'. | |
62 ;; | |
63 ;; * List of regular expressions to be placed in auto-mode-alist. | |
64 ;; | |
65 ;; * List of functions to call to do some additional setup | |
66 ;; | |
67 ;; This should pretty much cover basic functionality; if you need much | |
68 ;; more than this, or you find yourself writing extensive customizations, | |
69 ;; perhaps you should be writing a major mode instead! | |
70 ;; | |
71 ;; INSTALLATION: | |
72 ;; | |
73 ;; Place the following in your .emacs file: | |
74 ;; | |
75 ;; (require 'generic-mode) | |
76 ;; | |
77 ;; If you want to use some pre-defined generic modes, add: | |
78 ;; | |
79 ;; (require 'generic-extras) | |
80 ;; | |
81 ;; Loading these generic modes will cause some new entries to be placed in | |
82 ;; your auto-mode-alist. See 'generic-extras.el' for details. | |
83 ;; | |
84 ;; LOCAL VARIABLES: | |
85 ;; | |
86 ;; To put a file into generic mode using local variables, use a line | |
87 ;; like this in a Local Variables block: | |
88 ;; | |
89 ;; mode: default-generic | |
90 ;; | |
91 ;; Do NOT use "mode: generic"! | |
92 ;; See also "AUTOMATICALLY ENTERING GENERIC MODE" below. | |
93 ;; | |
94 ;; DEFINING NEW GENERIC MODES: | |
95 ;; | |
96 ;; Use the 'define-generic-mode' function to define new modes. | |
97 ;; For example: | |
98 ;; | |
99 ;; (require 'generic-mode) | |
100 ;; (define-generic-mode 'foo-generic-mode | |
101 ;; (list ?% ) | |
102 ;; (list "keyword") | |
103 ;; nil | |
104 ;; (list "\.FOO") | |
105 ;; (list 'foo-setup-function)) | |
106 ;; | |
107 ;; defines a new generic-mode 'foo-generic-mode', which has '%' as a | |
108 ;; comment character, and "keyword" as a keyword. When files which end in | |
109 ;; '.FOO' are loaded, Emacs will go into foo-generic-mode and call | |
110 ;; foo-setup-function. You can also use the function 'foo-generic-mode' | |
111 ;; (which is interactive) to put a buffer into foo-generic-mode. | |
112 ;; | |
113 ;; ALTERING EXISTING MODES: | |
114 ;; | |
115 ;; To alter an existing generic-mode, use the convenience functions: | |
116 ;; | |
117 ;; (alter-generic-mode-comments MODE COMMENT-LIST HOW-TO-ALTER) | |
118 ;; (alter-generic-mode-keywords MODE KEYWORD-LIST HOW-TO-ALTER) | |
119 ;; (alter-generic-mode-font-lock MODE FONT-LOCK-LIST HOW-TO-ALTER) | |
120 ;; (alter-generic-mode-auto-mode MODE AUTO-MODE-LIST HOW-TO-ALTER) | |
121 ;; (alter-generic-mode-functions MODE FUNCTION-LIST HOW-TO-ALTER) | |
122 ;; | |
123 ;; HOW-TO-ALTER should be one of the following symbols: 'append, 'prepend, | |
124 ;; or 'overwrite. If it is omitted, 'append is assumed. | |
125 ;; | |
126 ;; AUTOMATICALLY ENTERING GENERIC MODE: | |
127 ;; | |
128 ;; Generic-mode provides a hook which automatically puts a | |
129 ;; file into default-generic-mode if the first few lines of a file in | |
130 ;; fundamental mode start with a hash comment character. To disable | |
131 ;; this functionality, set the variable 'generic-use-find-file-hook' | |
132 ;; to nil BEFORE loading generic-mode. See the variables | |
133 ;; 'generic-lines-to-scan' and 'generic-find-file-regexp' for customization | |
134 ;; options. | |
135 ;; | |
136 ;; GOTCHAS: | |
137 ;; | |
138 ;; Be careful that your font-lock definitions are correct. Getting them | |
139 ;; wrong can cause emacs to continually attempt to fontify! This problem | |
140 ;; is not specific to generic-mode. | |
141 ;; | |
142 | |
143 ;; Credit for suggestions, brainstorming, patches and bug-fixes: | |
144 ;; ACorreir@pervasive-sw.com (Alfred Correira) | |
145 | |
146 ;;; Change log: | |
147 ;; $Log$ | |
148 ;; Revision 1.1 2008/04/19 18:10:28 ht | |
149 ;; *** empty log message *** | |
150 ;; | |
151 ; Revision 1.2 1997/04/02 07:02:38 voelker | |
152 ; *** empty log message *** | |
153 ; | |
154 ;; Revision 1.6 1996/11/01 17:27:47 peter | |
155 ;; Changed the function generic-function-name to return a string instead | |
156 ;; of a symbol. Generic-mode now uses this for the mode's name | |
157 ;; | |
158 ;; Revision 1.5 1996/11/01 16:45:20 peter | |
159 ;; Added GPL and LCD information. | |
160 ;; Updated documentation | |
161 ;; Added generic-find-file-regexp variable | |
162 ;; Added generic-make-keywords-list function | |
163 ;; | |
164 ;; Revision 1.4 1996/10/19 12:16:59 peter | |
165 ;; Small bug fixes: fontlock -> font-lock | |
166 ;; New entries are added to the end of auto-mode-alist | |
167 ;; Generic-font-lock-defaults are set to nil, not (list nil) | |
168 ;; Comment-regexp in generic-mode-find-file-hook changed to allow optional | |
169 ;; blank lines | |
170 ;; | |
171 ;; Revision 1.3 1996/10/17 08:24:25 peter | |
172 ;; Added generic-mode-find-file-hook and associated variables | |
173 ;; | |
174 ;; Revision 1.2 1996/10/17 01:00:45 peter | |
175 ;; Moved from a data-centered approach (generic-mode-alist) to | |
176 ;; a function-based one (define-generic-mode) | |
177 ;; | |
178 ;; Revision 1.1 1996/10/10 11:37:36 peter | |
179 ;; Initial revision | |
180 ;; | |
181 | |
182 ;;; Code: | |
183 | |
184 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
185 ;; Variables | |
186 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
187 | |
188 (make-variable-buffer-local | |
189 (defvar generic-font-lock-defaults nil | |
190 "Global defaults for font-lock in a generic mode.")) | |
191 | |
192 (make-variable-buffer-local | |
193 (defvar generic-mode-name 'default-generic-mode | |
194 "The name of the generic mode. | |
195 This is the car of one of the items in `generic-mode-alist'. | |
196 This variable is buffer-local.")) | |
197 | |
198 (make-variable-buffer-local | |
199 (defvar generic-comment-list nil | |
200 "List of comment characters for a generic mode.")) | |
201 | |
202 (make-variable-buffer-local | |
203 (defvar generic-keywords-list nil | |
204 "List of keywords for a generic mode.")) | |
205 | |
206 (make-variable-buffer-local | |
207 (defvar generic-font-lock-expressions nil | |
208 "List of font-lock expressions for a generic mode.")) | |
209 | |
210 (make-variable-buffer-local | |
211 (defvar generic-mode-function-list nil | |
212 "List of customization functions to call for a generic mode.")) | |
213 | |
214 (make-variable-buffer-local | |
215 (defvar generic-mode-syntax-table nil | |
216 "Syntax table for use in a generic mode.")) | |
217 | |
218 (defvar generic-mode-alist nil | |
219 "An association list for generic-mode. | |
220 Each entry in the list looks like this: | |
221 | |
222 NAME COMMENT-LIST KEYWORD-LIST FONT-LOCK-LIST AUTO-MODE-LIST FUNCTION-LIST. | |
223 | |
224 Do not add entries to this list directly; use `define-generic-mode' | |
225 instead (which see). | |
226 | |
227 To alter an already existing generic-mode, use | |
228 one of the `alter-generic-mode-' convenience functions (which see)" | |
229 ) | |
230 | |
231 (defvar generic-use-find-file-hook t | |
232 "*If non-nil, add a hook to enter default-generic-mode automatically | |
233 if the first few lines of a file in fundamental mode start with a hash | |
234 comment character.") | |
235 | |
236 (defvar generic-lines-to-scan 3 | |
237 "*Number of lines that `generic-mode-find-file-hook' looks at | |
238 when deciding whether to enter generic-mode automatically. | |
239 This variable should be set to a small positive number.") | |
240 | |
241 (defvar generic-find-file-regexp "#.*\n\\(.*\n\\)?" | |
242 "*Regular expression used by `generic-mode-find-file-hook' | |
243 to determine if files in fundamental mode should be put into | |
244 `default-generic-mode' instead.") | |
245 | |
246 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
247 ;; Inline functions | |
248 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
249 | |
250 (defsubst generic-read-type () | |
251 (completing-read | |
252 "Generic Type: " | |
253 (mapcar | |
254 '(lambda (elt) (list (symbol-name (car elt)))) | |
255 generic-mode-alist) nil t)) | |
256 | |
257 ;; Basic sanity checks. It does *not* check whether the elements of the lists | |
258 ;; are of the correct type. | |
259 (defsubst generic-mode-sanity-check (name comment-list keyword-list | |
260 font-lock-list auto-mode-list | |
261 function-list &optional description) | |
262 (if (not (symbolp name)) | |
263 (error "%s is not a symbol" (princ name))) | |
264 | |
265 (mapcar '(lambda (elt) | |
266 (if (not (listp elt)) | |
267 (error "%s is not a list" (princ elt)))) | |
268 (list comment-list keyword-list font-lock-list | |
269 auto-mode-list function-list)) | |
270 | |
271 (if (not (or (null description) (stringp description))) | |
272 (error "Description must be a string or nil")) | |
273 ) | |
274 | |
275 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
276 ;; Functions | |
277 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
278 | |
279 ;;;### autoload | |
280 (defun define-generic-mode (name comment-list keyword-list font-lock-list | |
281 auto-mode-list function-list | |
282 &optional description) | |
283 "Create a new generic mode with NAME. | |
284 NAME should be a symbol; its string representation is used as the function | |
285 name. If DESCRIPTION is provided, it is used as the docstring for the new | |
286 function. | |
287 | |
288 COMMENT-LIST is a list, whose entries are either a single character, | |
289 a one or two character string or a cons pair. If the entry is a character | |
290 or a one-character string, it is added to the mode's syntax table with | |
291 comment-start syntax. If the entry is a cons pair, the elements of the | |
292 pair are considered to be comment-start and comment-end respectively. | |
293 Note that Emacs has limitations regarding comment characters. | |
294 | |
295 KEYWORD-LIST is a list of keywords to highlight with `font-lock-keyword-face'. | |
296 Each keyword should be a string. | |
297 | |
298 FONT-LOCK-LIST is a list of additional expressions to highlight. Each entry | |
299 in the list should have the same form as an entry in `font-lock-defaults-alist' | |
300 | |
301 AUTO-MODE-LIST is a list of regular expressions to add to auto-mode-alist. | |
302 These regexps are added to auto-mode-alist as soon as `define-generic-mode' | |
303 is called; any old regexps with the same name are removed. To modify the | |
304 auto-mode-alist expressions, use `alter-generic-mode-auto-mode' (which see). | |
305 | |
306 FUNCTION-LIST is a list of functions to call to do some additional setup. | |
307 | |
308 See the file generic-extras.el for some examples of `define-generic-mode'." | |
309 | |
310 ;; Basic sanity check | |
311 (generic-mode-sanity-check name | |
312 comment-list keyword-list font-lock-list | |
313 auto-mode-list function-list description) | |
314 | |
315 ;; Remove any old entry | |
316 (setq generic-mode-alist | |
317 (delq (assq name generic-mode-alist) | |
318 generic-mode-alist)) | |
319 | |
320 ;; Add a new entry | |
321 (setq generic-mode-alist | |
322 (append | |
323 (list | |
324 (list | |
325 name comment-list keyword-list font-lock-list | |
326 auto-mode-list function-list | |
327 )) | |
328 generic-mode-alist)) | |
329 | |
330 ;; Add it to auto-mode-alist | |
331 (generic-add-to-auto-mode name auto-mode-list t) | |
332 | |
333 ;; Define a function for it | |
334 (generic-create-generic-function name description) | |
335 ) | |
336 | |
337 (defun generic-add-to-auto-mode (mode auto-mode-list | |
338 &optional remove-old prepend) | |
339 "Add the entries for mode to `auto-mode-alist'. | |
340 If remove-old is non-nil, removes old entries first. If prepend is | |
341 non-nil, prepends entries to auto-mode-alist; otherwise, appends them." | |
342 | |
343 (if (not (listp auto-mode-list)) | |
344 (error "%s is not a list" (princ auto-mode-list))) | |
345 | |
346 (let ((new-mode (intern (symbol-name mode)))) | |
347 (if remove-old | |
348 (let ((auto-mode-entry)) | |
349 (while (setq auto-mode-entry (rassq new-mode auto-mode-alist)) | |
350 (setq auto-mode-alist | |
351 (delq auto-mode-entry | |
352 auto-mode-alist))))) | |
353 | |
354 (mapcar '(lambda (entry) | |
355 (generic-add-auto-mode-entry new-mode entry prepend)) | |
356 auto-mode-list))) | |
357 | |
358 (defun generic-add-auto-mode-entry (name entry &optional prepend) | |
359 "Add a new entry to the end of auto-mode-alist. | |
360 If prepend is non-nil, add the entry to the front of the list." | |
361 (let ((new-entry (list (cons entry name)))) | |
362 (setq auto-mode-alist | |
363 (if prepend | |
364 (append new-entry auto-mode-alist) | |
365 (append auto-mode-alist new-entry))))) | |
366 | |
367 (defun generic-create-generic-function (name &optional description) | |
368 "Create a generic mode function with NAME. | |
369 If DESCRIPTION is provided, it is used as the docstring." | |
370 (let ((symname (symbol-name name))) | |
371 (fset (intern symname) | |
372 (list 'lambda nil | |
373 (or description | |
374 (concat "Generic mode for type " symname)) | |
375 (list 'interactive) | |
376 (list 'generic-mode-with-type (list 'quote name)))))) | |
377 | |
378 (defun generic-mode-with-type (&optional mode) | |
379 "Go into the generic-mode MODE." | |
380 (let* ((type (or mode generic-mode-name)) | |
381 (generic-mode-list (assoc type generic-mode-alist)) | |
382 ) | |
383 | |
384 (if (not generic-mode-list) | |
385 (error "Can't find generic-mode information for type %s" | |
386 (princ generic-mode-name))) | |
387 | |
388 ;; Put this after the point where we read generic-mode-name! | |
389 (kill-all-local-variables) | |
390 | |
391 (setq | |
392 generic-mode-name type | |
393 generic-comment-list (nth 1 generic-mode-list) | |
394 generic-keywords-list (nth 2 generic-mode-list) | |
395 generic-font-lock-expressions (nth 3 generic-mode-list) | |
396 generic-mode-function-list (nth 5 generic-mode-list) | |
397 major-mode 'generic-mode | |
398 mode-name (symbol-name type) | |
399 ) | |
400 | |
401 (generic-mode-set-comments generic-comment-list) | |
402 | |
403 ;; Font-lock functionality | |
404 ;; Font-lock-defaults are always set even if there are no keywords | |
405 ;; or font-lock expressions, so comments can be highlighted. | |
406 (setq generic-font-lock-defaults nil) | |
407 (generic-mode-set-font-lock generic-keywords-list | |
408 generic-font-lock-expressions) | |
409 (make-local-variable 'font-lock-defaults) | |
410 (setq font-lock-defaults (list 'generic-font-lock-defaults nil)) | |
411 | |
412 ;; Call a list of functions | |
413 (if generic-mode-function-list | |
414 (mapcar 'funcall generic-mode-function-list)) | |
415 ) | |
416 ) | |
417 | |
418 ;;;###autoload | |
419 (defun generic-mode (type) | |
420 "A mode to do basic comment and font-lock functionality | |
421 for files which are too small to warrant their own mode, but have | |
422 comment characters, keywords, and the like. | |
423 | |
424 To define a generic-mode, use the function `define-generic-mode'. | |
425 To alter an existing generic-mode, use the `alter-generic-mode-' | |
426 convenience functions. | |
427 Some generic modes are defined in generic-extras.el" | |
428 (interactive | |
429 (list (generic-read-type))) | |
430 (generic-mode-with-type (intern type))) | |
431 | |
432 ;;; Comment Functionality | |
433 (defun generic-mode-set-comments (comment-list) | |
434 "Set up comment functionality for generic mode." | |
435 (if (null comment-list) | |
436 nil | |
437 (let ((generic-mode-syntax-table (make-syntax-table))) | |
438 (make-local-variable 'comment-start) | |
439 (make-local-variable 'comment-start-skip) | |
440 (make-local-variable 'comment-end) | |
441 (mapcar 'generic-mode-set-a-comment comment-list) | |
442 (set-syntax-table generic-mode-syntax-table)))) | |
443 | |
444 (defun generic-mode-set-a-comment (comment) | |
445 (and (char-or-string-p comment) | |
446 (if (stringp comment) | |
447 (cond | |
448 ((eq (length comment) 1) | |
449 (generic-mode-set-comment-char | |
450 (string-to-char comment))) | |
451 ((eq (length comment) 2) | |
452 (generic-mode-set-comment-string comment)) | |
453 (t | |
454 (error "Character string %s must be one or two characters long" | |
455 comment)) | |
456 ) | |
457 (generic-mode-set-comment-char comment))) | |
458 (if (consp comment) | |
459 (generic-mode-set-comment-pair comment))) | |
460 | |
461 (defun generic-mode-set-comment-char (comment-char) | |
462 "Set the given character as a comment character for generic mode." | |
463 (if (not comment-char) | |
464 nil | |
465 (setq | |
466 comment-end "" | |
467 comment-start (char-to-string comment-char) | |
468 comment-start-skip (concat comment-start "+ *") | |
469 ) | |
470 | |
471 (modify-syntax-entry comment-char "<" | |
472 generic-mode-syntax-table) | |
473 (modify-syntax-entry ?\n ">" | |
474 generic-mode-syntax-table))) | |
475 | |
476 (defun generic-mode-set-comment-string (comment-string) | |
477 "Set the given string as a comment string for generic mode." | |
478 (if (not comment-string) | |
479 nil | |
480 (setq | |
481 comment-end "" | |
482 comment-start comment-string | |
483 comment-start-skip (concat comment-start " *") | |
484 ) | |
485 | |
486 (let ((first (elt comment-string 0)) | |
487 (second (elt comment-string 1))) | |
488 ;; C++ style comments | |
489 (if (char-equal first second) | |
490 (progn | |
491 (modify-syntax-entry first "<12b" | |
492 generic-mode-syntax-table) | |
493 (modify-syntax-entry ?\n ">b" | |
494 generic-mode-syntax-table))) | |
495 ;; Some other two character string | |
496 (modify-syntax-entry first "<1" | |
497 generic-mode-syntax-table) | |
498 (modify-syntax-entry second "<2" | |
499 generic-mode-syntax-table) | |
500 (modify-syntax-entry ?\n ">" | |
501 generic-mode-syntax-table)))) | |
502 | |
503 (defun generic-mode-set-comment-pair (comment-pair) | |
504 "Set the given comment pair as a comment start and end for generic mode." | |
505 (let ((generic-comment-start (car comment-pair)) | |
506 (generic-comment-end (cdr comment-pair)) | |
507 ) | |
508 (setq | |
509 comment-end generic-comment-end | |
510 comment-start generic-comment-start | |
511 comment-start-skip (concat generic-comment-start " *") | |
512 ) | |
513 | |
514 ;; Sanity checks | |
515 (if (not (and (stringp generic-comment-start) | |
516 (stringp generic-comment-end))) | |
517 (error "Elements of cons pair must be strings")) | |
518 (if (not (and (equal (length generic-comment-start) 2) | |
519 (equal (length generic-comment-end) 2))) | |
520 (error "Start and end must be exactly two characters long")) | |
521 | |
522 (let ((first (elt generic-comment-start 0)) | |
523 (second (elt generic-comment-start 1)) | |
524 (third (elt generic-comment-end 0)) | |
525 (fourth (elt generic-comment-end 1)) | |
526 ) | |
527 | |
528 (modify-syntax-entry first ". 1" generic-mode-syntax-table) | |
529 (modify-syntax-entry second ". 2" generic-mode-syntax-table) | |
530 | |
531 (modify-syntax-entry | |
532 third | |
533 (concat | |
534 "." | |
535 (cond | |
536 ((char-equal first third) " 13") | |
537 ((char-equal second third) " 23") | |
538 (t " 3")) | |
539 ) | |
540 generic-mode-syntax-table) | |
541 | |
542 (modify-syntax-entry | |
543 fourth | |
544 (concat | |
545 "." | |
546 (cond | |
547 ((char-equal first fourth) " 14") | |
548 ((char-equal second fourth) " 24") | |
549 (t " 4")) | |
550 ) | |
551 generic-mode-syntax-table) | |
552 ))) | |
553 | |
554 (defun generic-mode-set-font-lock (keywords font-lock-expressions) | |
555 "Set up font-lock functionality for generic mode." | |
556 (let ((generic-font-lock-expressions)) | |
557 ;; Keywords | |
558 (if keywords | |
559 (setq | |
560 generic-font-lock-expressions | |
561 (append | |
562 (list | |
563 (list | |
564 (concat | |
565 "\\(\\<" | |
566 (mapconcat 'identity keywords "\\>\\|\\<") | |
567 "\\>\\)") | |
568 1 'font-lock-keyword-face)) | |
569 generic-font-lock-expressions))) | |
570 ;; Other font-lock expressions | |
571 (if font-lock-expressions | |
572 (setq generic-font-lock-expressions | |
573 (append | |
574 font-lock-expressions | |
575 generic-font-lock-expressions))) | |
576 (if (not (or font-lock-expressions keywords)) | |
577 nil | |
578 (setq generic-font-lock-defaults generic-font-lock-expressions)) | |
579 )) | |
580 | |
581 (defun alter-generic-mode (mode alter-list &optional how-to-alter) | |
582 "Alter the specified generic mode. | |
583 How-to-alter, if specified, should be one of the following symbols: | |
584 `append', `prepend', `overwrite'. The default is `append'." | |
585 (let ((generic-mode-list (assoc mode generic-mode-alist)) | |
586 (item-number 0) | |
587 (current-elt) | |
588 (current-list) | |
589 (alter-elt) | |
590 (alter-method (or how-to-alter 'append)) | |
591 ) | |
592 (if (not generic-mode-list) | |
593 (error "Can't find generic-mode information for type %s" | |
594 (princ mode))) | |
595 ;; Ignore the name | |
596 (setq generic-mode-list (cdr generic-mode-list)) | |
597 (while (< item-number (length alter-list)) | |
598 (setq current-list (nthcdr item-number generic-mode-list) | |
599 current-elt (nth item-number generic-mode-list) | |
600 alter-elt (nth item-number alter-list)) | |
601 (cond | |
602 ;; Ignore items with value t | |
603 ((eq alter-elt 't) | |
604 nil) | |
605 ((eq alter-method 'overwrite) | |
606 (setcar current-list alter-elt)) | |
607 ((eq alter-method 'prepend) | |
608 (setcar current-list (append alter-elt current-elt))) | |
609 ((eq alter-method 'append) | |
610 (setcar current-list (append current-elt alter-elt))) | |
611 (t | |
612 (error "Optional argument %s not understood" (princ alter-method)))) | |
613 (setq item-number (1+ item-number)) | |
614 ) | |
615 ) | |
616 ) | |
617 | |
618 ;; Convenience functions | |
619 (defun alter-generic-mode-comments (mode comment-list &optional how-to-alter) | |
620 "Alter comments in the specified generic mode. | |
621 How-to-alter, if specified, should be one of the following symbols: | |
622 `append', `prepend', `overwrite'. The default is `append'." | |
623 (alter-generic-mode mode (list comment-list t t t t) how-to-alter)) | |
624 | |
625 (defun alter-generic-mode-keywords (mode keyword-list &optional how-to-alter) | |
626 "Alter keywords in the specified generic mode. | |
627 How-to-alter, if specified, should be one of the following symbols: | |
628 `append', `prepend', `overwrite'. The default is `append'." | |
629 (alter-generic-mode mode (list t keyword-list t t t) how-to-alter)) | |
630 | |
631 (defun alter-generic-mode-font-lock (mode font-lock-list &optional how-to-alter) | |
632 "Alter font-lock expressions in the specified generic mode. | |
633 How-to-alter, if specified, should be one of the following symbols: | |
634 `append', `prepend', `overwrite'. The default is `append'." | |
635 (alter-generic-mode mode (list t t font-lock-list t t) how-to-alter)) | |
636 | |
637 (defun alter-generic-mode-functions (mode function-list &optional how-to-alter) | |
638 "Alter functions in the specified generic mode. | |
639 How-to-alter, if specified, should be one of the following symbols: | |
640 `append', `prepend', `overwrite'. The default is `append'." | |
641 (alter-generic-mode mode (list t t t t function-list) how-to-alter)) | |
642 | |
643 ;; This one is different because it takes effect immediately | |
644 ;; Appending or Prepending to auto-mode-alist is ignored, | |
645 ;; since the effect is the same either way | |
646 (defun alter-generic-mode-auto-mode | |
647 (mode auto-mode-list &optional how-to-alter) | |
648 "Alter auto-mode-alist regular expressions in the specified generic mode. | |
649 How-to-alter, if specified, should be one of the following symbols: | |
650 `append', `prepend', `overwrite'. The default is `append'." | |
651 (alter-generic-mode mode (list t t t auto-mode-list t) how-to-alter) | |
652 (let ((alter-method (or how-to-alter 'append))) | |
653 (cond ((eq alter-method 'overwrite) | |
654 (generic-add-to-auto-mode mode auto-mode-list t)) | |
655 ((eq alter-method 'append) | |
656 (generic-add-to-auto-mode mode auto-mode-list nil)) | |
657 ((eq alter-method 'prepend) | |
658 (generic-add-to-auto-mode mode auto-mode-list nil t)) | |
659 (t | |
660 (error "Optional argument %s not understood" (princ alter-method)))) | |
661 )) | |
662 | |
663 ;; Support for [KEYWORD] constructs found in INF, INI and Samba files | |
664 (defun generic-bracket-support () | |
665 (setq imenu-generic-expression | |
666 '((nil "^\\[\\(.*\\)\\]" 1)))) | |
667 | |
668 ;; This generic mode is always defined | |
669 (define-generic-mode 'default-generic-mode (list ?#) nil nil nil nil) | |
670 | |
671 ;; A more general solution would allow us to enter generic-mode for | |
672 ;; *any* comment character, but would require us to synthesize a new | |
673 ;; generic-mode on the fly. I think this gives us most of what we | |
674 ;; want. | |
675 (defun generic-mode-find-file-hook () | |
676 "Hook to enter default-generic-mode automatically | |
677 if the first few lines of a file in fundamental-mode start with a hash | |
678 comment character. This hook will be installed if the variable | |
679 `generic-use-find-file-hook' is non-nil. The variable `generic-lines-to-scan' | |
680 determines the number of lines to look at." | |
681 (if (not (eq major-mode 'fundamental-mode)) | |
682 nil | |
683 (if (or (> 1 generic-lines-to-scan) | |
684 (< 50 generic-lines-to-scan)) | |
685 (error "Variable `generic-lines-to-scan' should be set to a small" | |
686 " positive number")) | |
687 (let ((comment-regexp "") | |
688 (count 0) | |
689 ) | |
690 (while (< count generic-lines-to-scan) | |
691 (setq comment-regexp (concat comment-regexp | |
692 generic-find-file-regexp)) | |
693 (setq count (1+ count))) | |
694 (save-excursion | |
695 (goto-char (point-min)) | |
696 (if (looking-at comment-regexp) | |
697 (generic-mode-with-type 'default-generic-mode)))))) | |
698 | |
699 (if generic-use-find-file-hook | |
700 (add-hook 'find-file-hooks 'generic-mode-find-file-hook)) | |
701 | |
702 (defun generic-make-keywords-list (keywords-list face &optional prefix suffix) | |
703 "Return a regular expression matching the specified keywords. | |
704 The regexp is highlighted with FACE." | |
705 ;; Sanity checks | |
706 ;; Don't check here; face may not be defined yet | |
707 ;; (if (not (facep face)) | |
708 ;; (error "Face %s is not defined" (princ face))) | |
709 (if (not (listp keywords-list)) | |
710 (error "Keywords argument must be a list of strings")) | |
711 (list | |
712 (concat | |
713 (or prefix "") | |
714 "\\(\\<" | |
715 (mapconcat 'identity keywords-list "\\>\\|\\<") | |
716 "\\>\\)" | |
717 (or suffix "") | |
718 ) 1 face)) | |
719 | |
720 (provide 'generic-mode) | |
721 | |
722 ;;; generic-mode.el ends here | |
723 | |
724 ;; Local Variables: | |
725 ;; autocompile: t | |
726 ;; End: |