comparison lisp/generic.el @ 60773:1771db839aa6

Fix commentary section. Don't require cl for compilation. (generic-mode-list): Add autoload cookie. (generic-use-find-file-hook, generic-lines-to-scan) (generic-find-file-regexp, generic-ignore-files-regexp) (generic-mode, generic-mode-find-file-hook) (generic-mode-ini-file-find-file-hook): Fix docstrings. (define-generic-mode): Make it a defmacro. Fix docstring. (generic-mode-internal): Code cleanup. Add autoload cookie. (generic-mode-set-comments): Code cleanup.
author Lute Kamstra <lute@gnu.org>
date Mon, 21 Mar 2005 17:10:06 +0000
parents b392b963c10b
children cb4033032773
comparison
equal deleted inserted replaced
60772:e6c6bee5ad7f 60773:1771db839aa6
32 32
33 ;; INTRODUCTION: 33 ;; INTRODUCTION:
34 34
35 ;; Generic-mode is a meta-mode which can be used to define small modes 35 ;; Generic-mode is a meta-mode which can be used to define small modes
36 ;; which provide basic comment and font-lock support. These modes are 36 ;; which provide basic comment and font-lock support. These modes are
37 ;; intended for the many configuration files and such which are too small 37 ;; intended for the many configuration files and such which are too
38 ;; for a "real" mode, but still have a regular syntax, comment characters 38 ;; small for a "real" mode, but still have a regular syntax, comment
39 ;; and the like. 39 ;; characters and the like.
40 ;; 40 ;;
41 ;; Each generic mode can define the following: 41 ;; Each generic mode can define the following:
42 ;; 42 ;;
43 ;; * List of comment-characters. The entries in this list should be 43 ;; * List of comment-characters. The entries in this list should be
44 ;; either a character, a one or two character string or a cons pair. 44 ;; either a character, a one or two character string or a cons pair.
45 ;; If the entry is a character or a one-character string 45 ;; If the entry is a character or a string, it is added to the
46 ;; LIMITATIONS: Emacs does not support comment strings of more than 46 ;; mode's syntax table with `comment-start' syntax. If the entry is
47 ;; a cons pair, the elements of the pair are considered to be
48 ;; `comment-start' and `comment-end' respectively. (The latter
49 ;; should be nil if you want comments to end at end of line.)
50 ;; LIMITATIONS: Emacs does not support comment strings of more than
47 ;; two characters in length. 51 ;; two characters in length.
48 ;; 52 ;;
49 ;; * List of keywords to font-lock. Each keyword should be a string. 53 ;; * List of keywords to font-lock. Each keyword should be a string.
50 ;; If you have additional keywords which should be highlighted in a face 54 ;; If you have additional keywords which should be highlighted in a
51 ;; different from `font-lock-keyword-face', you can use the convenience 55 ;; face different from `font-lock-keyword-face', you can use the
52 ;; function `generic-make-keywords-list' (which see), and add the 56 ;; convenience function `generic-make-keywords-list' (which see),
53 ;; result to the following list: 57 ;; and add the result to the following list:
54 ;; 58 ;;
55 ;; * Additional expressions to font-lock. This should be a list of 59 ;; * Additional expressions to font-lock. This should be a list of
56 ;; expressions, each of which should be of the same form 60 ;; expressions, each of which should be of the same form as those in
57 ;; as those in `font-lock-keywords'. 61 ;; `font-lock-keywords'.
58 ;; 62 ;;
59 ;; * List of regular expressions to be placed in auto-mode-alist. 63 ;; * List of regular expressions to be placed in auto-mode-alist.
60 ;; 64 ;;
61 ;; * List of functions to call to do some additional setup 65 ;; * List of functions to call to do some additional setup
62 ;; 66 ;;
77 ;; DEFINING NEW GENERIC MODES: 81 ;; DEFINING NEW GENERIC MODES:
78 ;; 82 ;;
79 ;; Use the `define-generic-mode' function to define new modes. 83 ;; Use the `define-generic-mode' function to define new modes.
80 ;; For example: 84 ;; For example:
81 ;; 85 ;;
82 ;; (require 'generic)
83 ;; (define-generic-mode 'foo-generic-mode 86 ;; (define-generic-mode 'foo-generic-mode
84 ;; (list ?% ) 87 ;; (list ?%)
85 ;; (list "keyword") 88 ;; (list "keyword")
86 ;; nil 89 ;; nil
87 ;; (list "\\.FOO\\'") 90 ;; (list "\\.FOO\\'")
88 ;; (list 'foo-setup-function)) 91 ;; (list 'foo-setup-function))
89 ;; 92 ;;
90 ;; defines a new generic-mode `foo-generic-mode', which has '%' as a 93 ;; defines a new generic-mode `foo-generic-mode', which has '%' as a
91 ;; comment character, and "keyword" as a keyword. When files which end in 94 ;; comment character, and "keyword" as a keyword. When files which
92 ;; '.FOO' are loaded, Emacs will go into foo-generic-mode and call 95 ;; end in '.FOO' are loaded, Emacs will go into foo-generic-mode and
93 ;; foo-setup-function. You can also use the function `foo-generic-mode' 96 ;; call foo-setup-function. You can also use the function
94 ;; (which is interactive) to put a buffer into foo-generic-mode. 97 ;; `foo-generic-mode' (which is interactive) to put a buffer into
98 ;; foo-generic-mode.
95 ;; 99 ;;
96 ;; AUTOMATICALLY ENTERING GENERIC MODE: 100 ;; AUTOMATICALLY ENTERING GENERIC MODE:
97 ;; 101 ;;
98 ;; Generic-mode provides a hook which automatically puts a 102 ;; Generic-mode provides a hook which automatically puts a file into
99 ;; file into default-generic-mode if the first few lines of a file in 103 ;; default-generic-mode if the first few lines of a file in
100 ;; fundamental mode start with a hash comment character. To disable 104 ;; fundamental mode start with a hash comment character. To disable
101 ;; this functionality, set the variable `generic-use-find-file-hook' 105 ;; this functionality, set the variable `generic-use-find-file-hook'
102 ;; to nil BEFORE loading generic-mode. See the variables 106 ;; to nil BEFORE loading generic-mode. See the variables
103 ;; `generic-lines-to-scan' and `generic-find-file-regexp' for customization 107 ;; `generic-lines-to-scan' and `generic-find-file-regexp' for
104 ;; options. 108 ;; customization options.
105 ;; 109 ;;
106 ;; GOTCHAS: 110 ;; GOTCHAS:
107 ;; 111 ;;
108 ;; Be careful that your font-lock definitions are correct. Getting them 112 ;; Be careful that your font-lock definitions are correct. Getting
109 ;; wrong can cause emacs to continually attempt to fontify! This problem 113 ;; them wrong can cause Emacs to continually attempt to fontify! This
110 ;; is not specific to generic-mode. 114 ;; problem is not specific to generic-mode.
111 ;; 115 ;;
112 116
113 ;; Credit for suggestions, brainstorming, help with debugging: 117 ;; Credit for suggestions, brainstorming, help with debugging:
114 ;; ACorreir@pervasive-sw.com (Alfred Correira) 118 ;; ACorreir@pervasive-sw.com (Alfred Correira)
115 ;; Extensive cleanup by: 119 ;; Extensive cleanup by:
116 ;; Stefan Monnier (monnier+gnu/emacs@flint.cs.yale.edu) 120 ;; Stefan Monnier (monnier+gnu/emacs@flint.cs.yale.edu)
117 ;; 121 ;;
118 ;;; Code: 122 ;;; Code:
119 123
120 (eval-when-compile
121 (require 'cl))
122
123 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 124 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
124 ;; Internal Variables 125 ;; Internal Variables
125 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 126 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
126 127
127 (defvar generic-font-lock-defaults nil 128 (defvar generic-font-lock-defaults nil
128 "Global defaults for font-lock in a generic mode.") 129 "Global defaults for font-lock in a generic mode.")
129 (make-variable-buffer-local 'generic-font-lock-defaults) 130 (make-variable-buffer-local 'generic-font-lock-defaults)
130 131
132 ;;;###autoload
131 (defvar generic-mode-list nil 133 (defvar generic-mode-list nil
132 "A list of mode names for `generic-mode'. 134 "A list of mode names for `generic-mode'.
133 Do not add entries to this list directly; use `define-generic-mode' 135 Do not add entries to this list directly; use `define-generic-mode'
134 instead (which see).") 136 instead (which see).")
135 137
141 "Define simple major modes with comment and font-lock support." 143 "Define simple major modes with comment and font-lock support."
142 :prefix "generic-" 144 :prefix "generic-"
143 :group 'extensions) 145 :group 'extensions)
144 146
145 (defcustom generic-use-find-file-hook t 147 (defcustom generic-use-find-file-hook t
146 "*If non-nil, add a hook to enter default-generic-mode automatically. 148 "*If non-nil, add a hook to enter `default-generic-mode' automatically.
147 This is done if the first few lines of a file in fundamental mode start 149 This is done if the first few lines of a file in fundamental mode
148 with a hash comment character." 150 start with a hash comment character."
149 :group 'generic 151 :group 'generic
150 :type 'boolean 152 :type 'boolean)
151 )
152 153
153 (defcustom generic-lines-to-scan 3 154 (defcustom generic-lines-to-scan 3
154 "*Number of lines that `generic-mode-find-file-hook' looks at. 155 "*Number of lines that `generic-mode-find-file-hook' looks at.
155 Relevant when deciding whether to enter `generic-mode' automatically. 156 Relevant when deciding whether to enter Default-Generic mode automatically.
156 This variable should be set to a small positive number." 157 This variable should be set to a small positive number."
157 :group 'generic 158 :group 'generic
158 :type 'integer 159 :type 'integer)
159 )
160 160
161 (defcustom generic-find-file-regexp "^#" 161 (defcustom generic-find-file-regexp "^#"
162 "*Regular expression used by `generic-mode-find-file-hook'. 162 "*Regular expression used by `generic-mode-find-file-hook'.
163 Files in fundamental mode whose first few lines contain a match for 163 Files in fundamental mode whose first few lines contain a match
164 this regexp, should be put into `default-generic-mode' instead. 164 for this regexp, should be put into Default-Generic mode instead.
165 The number of lines tested for the matches is specified by the value 165 The number of lines tested for the matches is specified by the
166 of the variable `generic-lines-to-scan', which see." 166 value of the variable `generic-lines-to-scan', which see."
167 :group 'generic 167 :group 'generic
168 :type 'regexp 168 :type 'regexp)
169 )
170 169
171 (defcustom generic-ignore-files-regexp "[Tt][Aa][Gg][Ss]\\'" 170 (defcustom generic-ignore-files-regexp "[Tt][Aa][Gg][Ss]\\'"
172 "*Regular expression used by `generic-mode-find-file-hook'. 171 "*Regular expression used by `generic-mode-find-file-hook'.
173 Files whose names match this regular expression should not be put 172 Files whose names match this regular expression should not be put
174 into `default-generic-mode', even if they have lines which match the 173 into Default-Generic mode, even if they have lines which match
175 regexp in `generic-find-file-regexp'. If the value is nil, 174 the regexp in `generic-find-file-regexp'. If the value is nil,
176 `generic-mode-find-file-hook' does not check the file names." 175 `generic-mode-find-file-hook' does not check the file names."
177 :group 'generic 176 :group 'generic
178 :type '(choice (const :tag "Don't check file names" nil) regexp) 177 :type '(choice (const :tag "Don't check file names" nil) regexp))
179 )
180 178
181 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 179 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182 ;; Functions 180 ;; Functions
183 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 181 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
184 182
185 ;;;###autoload 183 ;;;###autoload
186 (defun define-generic-mode (name comment-list keyword-list font-lock-list 184 (defmacro define-generic-mode (mode comment-list keyword-list
187 auto-mode-list function-list 185 font-lock-list auto-mode-list
188 &optional description) 186 function-list &optional docstring)
189 "Create a new generic mode with NAME. 187 "Create a new generic mode MODE.
190 188
191 NAME should be a symbol; its string representation is used as the function 189 MODE is the name of the command for the generic mode; it need not
192 name. If DESCRIPTION is provided, it is used as the docstring for the new 190 be quoted. The optional DOCSTRING is the documentation for the
193 function. 191 mode command. If you do not supply it, a default documentation
194 192 string will be used instead.
195 COMMENT-LIST is a list, whose entries are either a single character, 193
196 a one or two character string or a cons pair. If the entry is a character 194 COMMENT-LIST is a list, whose entries are either a single
197 or a one-character string, it is added to the mode's syntax table with 195 character, a one or two character string or a cons pair. If the
198 `comment-start' syntax. If the entry is a cons pair, the elements of the 196 entry is a character or a string, it is added to the mode's
199 pair are considered to be `comment-start' and `comment-end' respectively. 197 syntax table with `comment-start' syntax. If the entry is a cons
200 \(The latter should be nil if you want comments to end at end of line.) 198 pair, the elements of the pair are considered to be
201 Note that Emacs has limitations regarding comment characters. 199 `comment-start' and `comment-end' respectively. (The latter
202 200 should be nil if you want comments to end at end of line.) Note
203 KEYWORD-LIST is a list of keywords to highlight with `font-lock-keyword-face'. 201 that Emacs has limitations regarding comment characters.
204 Each keyword should be a string. 202
205 203 KEYWORD-LIST is a list of keywords to highlight with
206 FONT-LOCK-LIST is a list of additional expressions to highlight. Each entry 204 `font-lock-keyword-face'. Each keyword should be a string.
207 in the list should have the same form as an entry in `font-lock-keywords'. 205
208 206 FONT-LOCK-LIST is a list of additional expressions to highlight.
209 AUTO-MODE-LIST is a list of regular expressions to add to `auto-mode-alist'. 207 Each entry in the list should have the same form as an entry in
210 These regexps are added to `auto-mode-alist' as soon as `define-generic-mode' 208 `font-lock-keywords'.
211 is called; any old regexps with the same name are removed. 209
212 210 AUTO-MODE-LIST is a list of regular expressions to add to
213 FUNCTION-LIST is a list of functions to call to do some additional setup. 211 `auto-mode-alist'. These regexps are added to `auto-mode-alist'
212 as soon as `define-generic-mode' is called.
213
214 FUNCTION-LIST is a list of functions to call to do some
215 additional setup.
214 216
215 See the file generic-x.el for some examples of `define-generic-mode'." 217 See the file generic-x.el for some examples of `define-generic-mode'."
216 218 (let* ((name-unquoted (if (eq (car-safe mode) 'quote) ; Backward compatibility.
217 ;; Add a new entry 219 (eval mode)
218 (add-to-list 'generic-mode-list (symbol-name name)) 220 mode))
219 221 (name-string (symbol-name name-unquoted))
220 ;; Add it to auto-mode-alist 222 (pretty-name (capitalize (replace-regexp-in-string
221 (dolist (re auto-mode-list) 223 "-mode\\'" "" name-string))))
222 (add-to-list 'auto-mode-alist (cons re name))) 224
223 225 `(progn
224 ;; Define a function for it using `defalias' (not `fset') to make 226 ;; Add a new entry.
225 ;; the mode appear on load-history. 227 (add-to-list 'generic-mode-list ,name-string)
226 (defalias name 228
227 `(lambda nil 229 ;; Add it to auto-mode-alist
228 ,(or description (concat "Generic mode for type " (symbol-name name))) 230 (dolist (re ,auto-mode-list)
229 (interactive) 231 (add-to-list 'auto-mode-alist (cons re ',name-unquoted)))
230 (generic-mode-internal ',name ',comment-list ',keyword-list 232
231 ',font-lock-list ',function-list))) 233 (defun ,name-unquoted ()
232 ) 234 ,(or docstring
233 235 (concat pretty-name " mode.\n"
236 "This a generic mode defined with `define-generic-mode'."))
237 (interactive)
238 (generic-mode-internal ',name-unquoted ,comment-list ,keyword-list
239 ,font-lock-list ,function-list)))))
240
241 ;;;###autoload
234 (defun generic-mode-internal (mode comments keywords font-lock-list funs) 242 (defun generic-mode-internal (mode comments keywords font-lock-list funs)
235 "Go into the generic-mode MODE." 243 "Go into the generic mode MODE."
236 (let* ((generic-mode-hooks (intern (concat (symbol-name mode) "-hook"))) 244 (let* ((modename (symbol-name mode))
237 (modename (symbol-name mode)) 245 (generic-mode-hooks (intern (concat modename "-hook")))
238 (name (if (string-match "-mode\\'" modename) 246 (pretty-name (capitalize (replace-regexp-in-string
239 (substring modename 0 (match-beginning 0)) 247 "-mode\\'" "" modename))))
240 modename)) 248
241 )
242
243 ;; Put this after the point where we read generic-mode-name!
244 (kill-all-local-variables) 249 (kill-all-local-variables)
245 250
246 (setq 251 (setq major-mode mode
247 major-mode mode 252 mode-name pretty-name)
248 mode-name (capitalize name) 253
249 ) 254 (generic-mode-set-comments comments)
250
251 (generic-mode-set-comments comments)
252 255
253 ;; Font-lock functionality 256 ;; Font-lock functionality
254 ;; Font-lock-defaults are always set even if there are no keywords 257 ;; Font-lock-defaults are always set even if there are no keywords
255 ;; or font-lock expressions, so comments can be highlighted. 258 ;; or font-lock expressions, so comments can be highlighted.
256 (setq generic-font-lock-defaults nil) 259 (setq generic-font-lock-defaults nil)
257 (generic-mode-set-font-lock keywords font-lock-list) 260 (generic-mode-set-font-lock keywords font-lock-list)
258 (make-local-variable 'font-lock-defaults) 261 (make-local-variable 'font-lock-defaults)
259 (setq font-lock-defaults (list 'generic-font-lock-defaults nil)) 262 (setq font-lock-defaults (list 'generic-font-lock-defaults nil))
260 263
261 ;; Call a list of functions 264 ;; Call a list of functions
262 (mapcar 'funcall funs) 265 (mapcar 'funcall funs)
263 266
264 (run-hooks generic-mode-hooks) 267 (run-hooks generic-mode-hooks)))
265 )
266 )
267 268
268 ;;;###autoload 269 ;;;###autoload
269 (defun generic-mode (type) 270 (defun generic-mode (mode)
270 "Basic comment and font-lock functionality for `generic' files. 271 "Enter generic mode MODE.
271 \(Files which are too small to warrant their own mode, but have 272
272 comment characters, keywords, and the like.) 273 Generic modes provide basic comment and font-lock functionality
274 for \"generic\" files. (Files which are too small to warrant their
275 own mode, but have comment characters, keywords, and the like.)
273 276
274 To define a generic-mode, use the function `define-generic-mode'. 277 To define a generic-mode, use the function `define-generic-mode'.
275 Some generic modes are defined in `generic-x.el'." 278 Some generic modes are defined in `generic-x.el'."
276 (interactive 279 (interactive
277 (list (completing-read "Generic Type: " generic-mode-list nil t))) 280 (list (completing-read "Generic mode: " generic-mode-list nil t)))
278 (funcall (intern type))) 281 (funcall (intern mode)))
279 282
280 ;;; Comment Functionality 283 ;;; Comment Functionality
281 (defun generic-mode-set-comments (comment-list) 284 (defun generic-mode-set-comments (comment-list)
282 "Set up comment functionality for generic mode." 285 "Set up comment functionality for generic mode."
283 (let ((st (make-syntax-table)) 286 (let ((st (make-syntax-table))
284 (chars nil) 287 (chars nil)
285 (comstyles)) 288 (comstyles))
286 (make-local-variable 'comment-start) 289 (make-local-variable 'comment-start)
287 (make-local-variable 'comment-start-skip) 290 (make-local-variable 'comment-start-skip)
288 (make-local-variable 'comment-end) 291 (make-local-variable 'comment-end)
289 292
290 ;; Go through all the comments 293 ;; Go through all the comments
291 (dolist (start comment-list) 294 (dolist (start comment-list)
292 (let ((end nil) (comstyle "")) 295 (let (end (comstyle ""))
293 ;; Normalize 296 ;; Normalize
294 (when (consp start) 297 (when (consp start)
295 (setq end (or (cdr start) end)) 298 (setq end (cdr start))
296 (setq start (car start))) 299 (setq start (car start)))
297 (when (char-valid-p start) (setq start (char-to-string start))) 300 (when (char-valid-p start) (setq start (char-to-string start)))
298 (cond 301 (cond
299 ((char-valid-p end) (setq end (char-to-string end))) 302 ((char-valid-p end) (setq end (char-to-string end)))
300 ((zerop (length end)) (setq end "\n"))) 303 ((zerop (length end)) (setq end "\n")))
358 (setq imenu-generic-expression 361 (setq imenu-generic-expression
359 '((nil "^\\[\\(.*\\)\\]" 1)) 362 '((nil "^\\[\\(.*\\)\\]" 1))
360 imenu-case-fold-search t)) 363 imenu-case-fold-search t))
361 364
362 ;; This generic mode is always defined 365 ;; This generic mode is always defined
363 (define-generic-mode 'default-generic-mode (list ?#) nil nil nil nil) 366 (define-generic-mode default-generic-mode (list ?#) nil nil nil nil)
364 367
365 ;; A more general solution would allow us to enter generic-mode for 368 ;; A more general solution would allow us to enter generic-mode for
366 ;; *any* comment character, but would require us to synthesize a new 369 ;; *any* comment character, but would require us to synthesize a new
367 ;; generic-mode on the fly. I think this gives us most of what we 370 ;; generic-mode on the fly. I think this gives us most of what we
368 ;; want. 371 ;; want.
369 (defun generic-mode-find-file-hook () 372 (defun generic-mode-find-file-hook ()
370 "Hook function to enter `default-generic-mode' automatically. 373 "Hook function to enter Default-Generic mode automatically.
371 Done if the first few lines of a file in `fundamental-mode' start with 374
372 a match for the regexp in `generic-find-file-regexp', unless the 375 Done if the first few lines of a file in Fundamental mode start
373 file's name matches the regexp which is the value of the variable 376 with a match for the regexp in `generic-find-file-regexp', unless
374 `generic-ignore-files-regexp'. 377 the file's name matches the regexp which is the value of the
378 variable `generic-ignore-files-regexp'.
379
375 This hook will be installed if the variable 380 This hook will be installed if the variable
376 `generic-use-find-file-hook' is non-nil. The variable 381 `generic-use-find-file-hook' is non-nil. The variable
377 `generic-lines-to-scan' determines the number of lines to look at." 382 `generic-lines-to-scan' determines the number of lines to look at."
378 (when (and (eq major-mode 'fundamental-mode) 383 (when (and (eq major-mode 'fundamental-mode)
379 (or (null generic-ignore-files-regexp) 384 (or (null generic-ignore-files-regexp)
388 (point)) t) 393 (point)) t)
389 (goto-char (point-min)) 394 (goto-char (point-min))
390 (default-generic-mode))))) 395 (default-generic-mode)))))
391 396
392 (defun generic-mode-ini-file-find-file-hook () 397 (defun generic-mode-ini-file-find-file-hook ()
393 "Hook function to enter default-generic-mode automatically for INI files. 398 "Hook function to enter Default-Generic mode automatically for INI files.
394 Done if the first few lines of a file in `fundamental-mode' look like an 399 Done if the first few lines of a file in Fundamental mode look like an
395 INI file. This hook is NOT installed by default." 400 INI file. This hook is NOT installed by default."
396 (and (eq major-mode 'fundamental-mode) 401 (and (eq major-mode 'fundamental-mode)
397 (save-excursion 402 (save-excursion
398 (goto-char (point-min)) 403 (goto-char (point-min))
399 (and (looking-at "^\\s-*\\[.*\\]") 404 (and (looking-at "^\\s-*\\[.*\\]")