aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2002-04-08 22:45:13 +0000
committerStefan Monnier2002-04-08 22:45:13 +0000
commit0b05c8cad1bae245b051f2bc1e44ae5c08bea423 (patch)
tree4bbd73b586daf548fc437f71f68ceb383abdd5cc
parentce22dd539dd8153c52c47a63a81bcd87ab4c9849 (diff)
downloademacs-0b05c8cad1bae245b051f2bc1e44ae5c08bea423.tar.gz
emacs-0b05c8cad1bae245b051f2bc1e44ae5c08bea423.zip
(global-cwarn-mode): Use define-minor-mode.
(global-cwarn-mode): Use easy-mmode-define-global-mode. (cwarn-font-lock-keywords): New function. Replaces cwarn-font-lock-remove-keywords cwarn-font-lock-add-keywords. (cwarn-font-lock-match): New macro. (cwarn-font-lock-match-assignment-in-expression) (cwarn-font-lock-match-dangerous-semicolon) (cwarn-font-lock-match-reference): Use it.
-rw-r--r--lisp/progmodes/cwarn.el243
1 files changed, 67 insertions, 176 deletions
diff --git a/lisp/progmodes/cwarn.el b/lisp/progmodes/cwarn.el
index b1f890dea93..aed77324907 100644
--- a/lisp/progmodes/cwarn.el
+++ b/lisp/progmodes/cwarn.el
@@ -39,7 +39,7 @@
39;; 39;;
40;; The code contains two, possibly fatal, bugs. The first is that the 40;; The code contains two, possibly fatal, bugs. The first is that the
41;; assignment operator "=" is used as part of the test; the user 41;; assignment operator "=" is used as part of the test; the user
42;; probably ment to use the comparison operator "==". 42;; probably meant to use the comparison operator "==".
43;; 43;;
44;; The second problem is that an extra semicolon is placed after 44;; The second problem is that an extra semicolon is placed after
45;; closing parenthesis of the test expression. This makes the body of 45;; closing parenthesis of the test expression. This makes the body of
@@ -55,7 +55,7 @@
55;; * C++ functions with reference parameters. 55;; * C++ functions with reference parameters.
56;; 56;;
57;; Note that none of the constructions highlighted (especially not C++ 57;; Note that none of the constructions highlighted (especially not C++
58;; reference parameters) are considered errors by the langauage 58;; reference parameters) are considered errors by the language
59;; definitions. 59;; definitions.
60 60
61;; Usage: 61;; Usage:
@@ -95,7 +95,7 @@
95;; * State exactly what you did, what happened, and what you expected 95;; * State exactly what you did, what happened, and what you expected
96;; to see when you found the bug. 96;; to see when you found the bug.
97;; * If the bug cause an error, set the variable `debug-on-error' to t, 97;; * If the bug cause an error, set the variable `debug-on-error' to t,
98;; repreat the operations that triggered the error and include 98;; repeat the operations that triggered the error and include
99;; the backtrace in the letter. 99;; the backtrace in the letter.
100;; * If possible, include an example that activates the bug. 100;; * If possible, include an example that activates the bug.
101;; * Should you speculate about the cause of the problem, please 101;; * Should you speculate about the cause of the problem, please
@@ -128,18 +128,6 @@
128Never set this variable directly, use the command `cwarn-mode' 128Never set this variable directly, use the command `cwarn-mode'
129instead.") 129instead.")
130 130
131(defcustom global-cwarn-mode nil
132 "When on, suspicious C and C++ constructions are highlighted.
133
134Set this variable using \\[customize] or use the command
135`global-cwarn-mode'."
136 :group 'cwarn
137 :initialize 'custom-initialize-default
138 :set (lambda (symbol value)
139 (global-cwarn-mode (or value 0)))
140 :type 'boolean
141 :require 'cwarn)
142
143(defcustom cwarn-configuration 131(defcustom cwarn-configuration
144 '((c-mode (not reference)) 132 '((c-mode (not reference))
145 (c++-mode t)) 133 (c++-mode t))
@@ -187,26 +175,6 @@ deactivated."
187 :group 'cwarn 175 :group 'cwarn
188 :type 'string) 176 :type 'string)
189 177
190(defcustom cwarn-mode-hook nil
191 "*Functions to run when CWarn mode is activated."
192 :tag "CWarn mode hook" ; To separate it from `global-...'
193 :group 'cwarn
194 :type 'hook)
195
196(defcustom global-cwarn-mode-text ""
197 "*String to display when Global CWarn mode is active.
198
199The default is nothing since when this mode is active this text doesn't
200vary over time, or between buffers. Hence mode line text
201would only waste precious space."
202 :group 'cwarn
203 :type 'string)
204
205(defcustom global-cwarn-mode-hook nil
206 "*Hook called when Global CWarn mode is activated."
207 :group 'cwarn
208 :type 'hook)
209
210(defcustom cwarn-load-hook nil 178(defcustom cwarn-load-hook nil
211 "*Functions to run when CWarn mode is first loaded." 179 "*Functions to run when CWarn mode is first loaded."
212 :tag "Load Hook" 180 :tag "Load Hook"
@@ -217,7 +185,7 @@ would only waste precious space."
217;;{{{ The modes 185;;{{{ The modes
218 186
219;;;###autoload 187;;;###autoload
220(defun cwarn-mode (&optional arg) 188(define-minor-mode cwarn-mode
221 "Minor mode that highlights suspicious C and C++ constructions. 189 "Minor mode that highlights suspicious C and C++ constructions.
222 190
223Note, in addition to enabling this minor mode, the major mode must 191Note, in addition to enabling this minor mode, the major mode must
@@ -225,23 +193,9 @@ be included in the variable `cwarn-configuration'. By default C and
225C++ modes are included. 193C++ modes are included.
226 194
227With ARG, turn CWarn mode on if and only if arg is positive." 195With ARG, turn CWarn mode on if and only if arg is positive."
228 (interactive "P") 196 nil cwarn-mode-text nil
229 (make-local-variable 'cwarn-mode) 197 (cwarn-font-lock-keywords cwarn-mode)
230 (setq cwarn-mode 198 (if font-lock-mode (font-lock-fontify-buffer)))
231 (if (null arg)
232 (not cwarn-mode)
233 (> (prefix-numeric-value arg) 0)))
234 (if (and cwarn-verbose
235 (interactive-p))
236 (message "Cwarn mode is now %s."
237 (if cwarn-mode "on" "off")))
238 (if (not global-cwarn-mode)
239 (if cwarn-mode
240 (cwarn-font-lock-add-keywords)
241 (cwarn-font-lock-remove-keywords)))
242 (font-lock-fontify-buffer)
243 (if cwarn-mode
244 (run-hooks 'cwarn-mode-hook)))
245 199
246;;;###autoload 200;;;###autoload
247(defun turn-on-cwarn-mode () 201(defun turn-on-cwarn-mode ()
@@ -251,46 +205,6 @@ This function is designed to be added to hooks, for example:
251 (add-hook 'c-mode-hook 'turn-on-cwarn-mode)" 205 (add-hook 'c-mode-hook 'turn-on-cwarn-mode)"
252 (cwarn-mode 1)) 206 (cwarn-mode 1))
253 207
254;;;###autoload
255(defun global-cwarn-mode (&optional arg)
256 "Hightlight suspicious C and C++ constructions in all buffers.
257
258With ARG, turn CWarn mode on globally if and only if arg is positive."
259 (interactive "P")
260 (let ((old-global-cwarn-mode global-cwarn-mode))
261 (setq global-cwarn-mode
262 (if (null arg)
263 (not global-cwarn-mode)
264 (> (prefix-numeric-value arg) 0)))
265 (if (and cwarn-verbose
266 (interactive-p))
267 (message "Global CWarn mode is now %s."
268 (if global-cwarn-mode "on" "off")))
269 (when (not (eq global-cwarn-mode old-global-cwarn-mode))
270 ;; Update for all future buffers.
271 (dolist (conf cwarn-configuration)
272 (if global-cwarn-mode
273 (cwarn-font-lock-add-keywords (car conf))
274 (cwarn-font-lock-remove-keywords (car conf))))
275 ;; Update all existing buffers.
276 (save-excursion
277 (dolist (buffer (buffer-list))
278 (set-buffer buffer)
279 ;; Update keywords in alive buffers.
280 (when (and font-lock-mode
281 (not cwarn-mode)
282 (cwarn-is-enabled major-mode))
283 (if global-cwarn-mode
284 (cwarn-font-lock-add-keywords)
285 (cwarn-font-lock-remove-keywords))
286 (font-lock-fontify-buffer))))))
287 ;; Kills all added keywords :-(
288 ;; (font-lock-mode 0)
289 ;; (makunbound 'font-lock-keywords)
290 ;; (font-lock-mode 1))))
291 (when global-cwarn-mode
292 (run-hooks 'global-cwarn-mode-hook)))
293
294;;}}} 208;;}}}
295;;{{{ Help functions 209;;{{{ Help functions
296 210
@@ -320,25 +234,17 @@ The valid features are described by the variable
320 (back-to-indentation) 234 (back-to-indentation)
321 (eq (char-after) ?#))) 235 (eq (char-after) ?#)))
322 236
323(defun cwarn-font-lock-add-keywords (&optional mode) 237(defun cwarn-font-lock-keywords (addp)
324 "Install keywords into major MODE, or into current buffer if nil." 238 "Install/Remove keywords into current buffer.
325 (dolist (pair cwarn-font-lock-feature-keywords-alist) 239If ADDP is non-nil, install else remove."
326 (let ((feature (car pair))
327 (keywords (cdr pair)))
328 (if (not (listp keywords))
329 (setq keywords (symbol-value keywords)))
330 (if (cwarn-is-enabled (or mode major-mode) feature)
331 (font-lock-add-keywords mode keywords)))))
332
333(defun cwarn-font-lock-remove-keywords (&optional mode)
334 "Remove keywords from major MODE, or from current buffer if nil."
335 (dolist (pair cwarn-font-lock-feature-keywords-alist) 240 (dolist (pair cwarn-font-lock-feature-keywords-alist)
336 (let ((feature (car pair)) 241 (let ((feature (car pair))
337 (keywords (cdr pair))) 242 (keywords (cdr pair)))
338 (if (not (listp keywords)) 243 (if (not (listp keywords))
339 (setq keywords (symbol-value keywords))) 244 (setq keywords (symbol-value keywords)))
340 (if (cwarn-is-enabled (or mode major-mode) feature) 245 (if (cwarn-is-enabled major-mode feature)
341 (font-lock-remove-keywords mode keywords))))) 246 (funcall (if addp 'font-lock-add-keywords 'font-lock-remove-keywords)
247 nil keywords)))))
342 248
343;;}}} 249;;}}}
344;;{{{ Backward compatibility 250;;{{{ Backward compatibility
@@ -356,7 +262,7 @@ definition), then nil is returned. Otherwise, if point is at a
356top-level not enclosed within a class definition, t is returned. 262top-level not enclosed within a class definition, t is returned.
357Otherwise, a 2-vector is returned where the zeroth element is the 263Otherwise, a 2-vector is returned where the zeroth element is the
358buffer position of the start of the class declaration, and the first 264buffer position of the start of the class declaration, and the first
359element is the buffer position of the enclosing class's opening 265element is the buffer position of the enclosing class' opening
360brace." 266brace."
361 (let ((state (c-parse-state))) 267 (let ((state (c-parse-state)))
362 (or (not (c-most-enclosing-brace state)) 268 (or (not (c-most-enclosing-brace state))
@@ -375,7 +281,7 @@ brace."
375;; A match function should act like a normal forward search. They 281;; A match function should act like a normal forward search. They
376;; should return non-nil if they found a candidate and the match data 282;; should return non-nil if they found a candidate and the match data
377;; should correspond to the highlight part of the font-lock keyword. 283;; should correspond to the highlight part of the font-lock keyword.
378;; The functions shold not generate errors, in that case font-lock 284;; The functions should not generate errors, in that case font-lock
379;; will fail to highlight the buffer. A match function takes one 285;; will fail to highlight the buffer. A match function takes one
380;; argument, LIMIT, that represent the end of area to be searched. 286;; argument, LIMIT, that represent the end of area to be searched.
381;; 287;;
@@ -383,6 +289,21 @@ brace."
383;; mapping from CWarn features to the font-lock keywords defined 289;; mapping from CWarn features to the font-lock keywords defined
384;; below. 290;; below.
385 291
292(defmacro cwarn-font-lock-match (re &rest body)
293 "Match RE but only if BODY holds."
294 `(let ((res nil))
295 (while
296 (progn
297 (setq res (re-search-forward ,re limit t))
298 (and res
299 (save-excursion
300 (when (match-beginning 1) (goto-char (match-beginning 1)))
301 (condition-case nil ; In case something barfs.
302 (not (save-match-data
303 ,@body))
304 (error t))))))
305 res))
306
386;;{{{ Assignment in expressions 307;;{{{ Assignment in expressions
387 308
388(defconst cwarn-font-lock-assignment-keywords 309(defconst cwarn-font-lock-assignment-keywords
@@ -391,28 +312,17 @@ brace."
391 312
392(defun cwarn-font-lock-match-assignment-in-expression (limit) 313(defun cwarn-font-lock-match-assignment-in-expression (limit)
393 "Match assignments inside expressions." 314 "Match assignments inside expressions."
394 (let ((res nil)) 315 (cwarn-font-lock-match
395 (while 316 "[^!<>=]\\(\\([-+*/%&^|]\\|<<\\|>>\\)?=\\)[^=]"
396 (progn 317 (backward-up-list 1)
397 (setq res (re-search-forward 318 (and (memq (following-char) '(?\( ?\[))
398 "[^!<>=]\\(\\([-+*/%&^|]\\|<<\\|>>\\)?=\\)[^=]" 319 (not (progn
399 limit t)) 320 (skip-chars-backward " ")
400 (and res 321 (skip-chars-backward "a-zA-Z0-9_")
401 (save-excursion 322 (or
402 (goto-char (match-beginning 1)) 323 ;; Default parameter of function.
403 (condition-case nil ; In case "backward-up-list" barfs. 324 (c-at-toplevel-p)
404 (progn 325 (looking-at "for\\>")))))))
405 (backward-up-list 1)
406 (or (not (memq (following-char) '(?\( ?\[)))
407 (save-match-data
408 (skip-chars-backward " ")
409 (skip-chars-backward "a-zA-Z0-9_")
410 (or
411 ;; Default parameter of function.
412 (c-at-toplevel-p)
413 (looking-at "for\\>")))))
414 (error t))))))
415 res))
416 326
417;;}}} 327;;}}}
418;;{{{ Semicolon 328;;{{{ Semicolon
@@ -422,25 +332,17 @@ brace."
422 332
423(defun cwarn-font-lock-match-dangerous-semicolon (limit) 333(defun cwarn-font-lock-match-dangerous-semicolon (limit)
424 "Match semicolons directly after `for', `while', and `if'. 334 "Match semicolons directly after `for', `while', and `if'.
425Tne semicolon after a `do { ... } while (x);' construction is not matched." 335The semicolon after a `do { ... } while (x);' construction is not matched."
426 (let ((res nil)) 336 (cwarn-font-lock-match
427 (while 337 ";"
428 (progn 338 (backward-sexp 2) ; Expression and keyword.
429 (setq res (search-forward ";" limit t)) 339 (or (looking-at "\\(for\\|if\\)\\>")
430 (and res 340 (and (looking-at "while\\>")
431 (save-excursion 341 (condition-case nil
432 (condition-case nil ; In case something barfs. 342 (progn
433 (save-match-data 343 (backward-sexp 2) ; Body and "do".
434 (backward-sexp 2) ; Expression and keyword. 344 (not (looking-at "do\\>")))
435 (not (or (looking-at "\\(for\\|if\\)\\>") 345 (error t))))))
436 (and (looking-at "while\\>")
437 (condition-case nil
438 (progn
439 (backward-sexp 2) ; Body and "do".
440 (not (looking-at "do\\>")))
441 (error t))))))
442 (error t))))))
443 res))
444 346
445;;}}} 347;;}}}
446;;{{{ Reference 348;;{{{ Reference
@@ -450,43 +352,32 @@ Tne semicolon after a `do { ... } while (x);' construction is not matched."
450 352
451(defun cwarn-font-lock-match-reference (limit) 353(defun cwarn-font-lock-match-reference (limit)
452 "Font-lock matcher for C++ reference parameters." 354 "Font-lock matcher for C++ reference parameters."
453 (let ((res nil)) 355 (cwarn-font-lock-match
454 (while 356 "[^&]\\(&\\)[^&=]"
455 (progn 357 (backward-up-list 1)
456 (setq res (re-search-forward "[^&]\\(&\\)[^&=]" limit t)) 358 (and (eq (following-char) ?\()
457 (and res 359 (not (cwarn-inside-macro))
458 (save-excursion 360 (c-at-toplevel-p))))
459 (goto-char (match-beginning 1))
460 (condition-case nil ; In case something barfs.
461 (save-match-data
462 (backward-up-list 1)
463 (or (not (eq (following-char) ?\())
464 (cwarn-inside-macro)
465 (not (c-at-toplevel-p))))
466 (error t))))))
467 res))
468 361
469;;}}} 362;;}}}
470 363
471;;}}} 364;;}}}
472;;{{{ The end 365;;{{{ The end
473 366
474(unless (assq 'cwarn-mode minor-mode-alist) 367(defun turn-on-cwarn-mode-if-enabled ()
475 (push '(cwarn-mode cwarn-mode-text) 368 "Turn on CWarn mode in the current buffer if applicable.
476 minor-mode-alist)) 369The mode is turned if some feature is enabled for the current
477(unless (assq 'global-cwarn-mode minor-mode-alist) 370`major-mode' in `cwarn-configuration'."
478 (push '(global-cwarn-mode global-cwarn-mode-text) 371 (if (cwarn-is-enabled major-mode) (turn-on-cwarn-mode)))
479 minor-mode-alist)) 372
373;;;###autoload
374(easy-mmode-define-global-mode global-cwarn-mode cwarn-mode
375 turn-on-cwarn-mode-if-enabled)
480 376
481(provide 'cwarn) 377(provide 'cwarn)
482 378
483(run-hooks 'cwarn-load-hook) 379(run-hooks 'cwarn-load-hook)
484 380
485;; This makes it possible to set Global CWarn mode from
486;; Customize.
487(if global-cwarn-mode
488 (global-cwarn-mode 1))
489
490;;}}} 381;;}}}
491 382
492;;; cwarn.el ends here 383;;; cwarn.el ends here