diff options
| author | Stefan Monnier | 2002-04-08 22:45:13 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2002-04-08 22:45:13 +0000 |
| commit | 0b05c8cad1bae245b051f2bc1e44ae5c08bea423 (patch) | |
| tree | 4bbd73b586daf548fc437f71f68ceb383abdd5cc | |
| parent | ce22dd539dd8153c52c47a63a81bcd87ab4c9849 (diff) | |
| download | emacs-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.el | 243 |
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 @@ | |||
| 128 | Never set this variable directly, use the command `cwarn-mode' | 128 | Never set this variable directly, use the command `cwarn-mode' |
| 129 | instead.") | 129 | instead.") |
| 130 | 130 | ||
| 131 | (defcustom global-cwarn-mode nil | ||
| 132 | "When on, suspicious C and C++ constructions are highlighted. | ||
| 133 | |||
| 134 | Set 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 | |||
| 199 | The default is nothing since when this mode is active this text doesn't | ||
| 200 | vary over time, or between buffers. Hence mode line text | ||
| 201 | would 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 | ||
| 223 | Note, in addition to enabling this minor mode, the major mode must | 191 | Note, 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 | |||
| 225 | C++ modes are included. | 193 | C++ modes are included. |
| 226 | 194 | ||
| 227 | With ARG, turn CWarn mode on if and only if arg is positive." | 195 | With 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 | |||
| 258 | With 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) | 239 | If 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 | |||
| 356 | top-level not enclosed within a class definition, t is returned. | 262 | top-level not enclosed within a class definition, t is returned. |
| 357 | Otherwise, a 2-vector is returned where the zeroth element is the | 263 | Otherwise, a 2-vector is returned where the zeroth element is the |
| 358 | buffer position of the start of the class declaration, and the first | 264 | buffer position of the start of the class declaration, and the first |
| 359 | element is the buffer position of the enclosing class's opening | 265 | element is the buffer position of the enclosing class' opening |
| 360 | brace." | 266 | brace." |
| 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'. |
| 425 | Tne semicolon after a `do { ... } while (x);' construction is not matched." | 335 | The 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)) | 369 | The 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 |