changeset 44447:811bba65a69f

(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.
author Stefan Monnier <monnier@iro.umontreal.ca>
date Mon, 08 Apr 2002 22:45:13 +0000
parents 9b08deb1030e
children 0e48638ca6dd
files lisp/progmodes/cwarn.el
diffstat 1 files changed, 67 insertions(+), 176 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/progmodes/cwarn.el	Mon Apr 08 22:39:00 2002 +0000
+++ b/lisp/progmodes/cwarn.el	Mon Apr 08 22:45:13 2002 +0000
@@ -39,7 +39,7 @@
 ;;
 ;; The code contains two, possibly fatal, bugs.  The first is that the
 ;; assignment operator "=" is used as part of the test; the user
-;; probably ment to use the comparison operator "==".
+;; probably meant to use the comparison operator "==".
 ;;
 ;; The second problem is that an extra semicolon is placed after
 ;; closing parenthesis of the test expression.  This makes the body of
@@ -55,7 +55,7 @@
 ;; * C++ functions with reference parameters.
 ;;
 ;; Note that none of the constructions highlighted (especially not C++
-;; reference parameters) are considered errors by the langauage
+;; reference parameters) are considered errors by the language
 ;; definitions.
 
 ;; Usage:
@@ -95,7 +95,7 @@
 ;; * State exactly what you did, what happened, and what you expected
 ;;   to see when you found the bug.
 ;; * If the bug cause an error, set the variable `debug-on-error' to t,
-;;   repreat the operations that triggered the error and include
+;;   repeat the operations that triggered the error and include
 ;;   the backtrace in the letter.
 ;; * If possible, include an example that activates the bug.
 ;; * Should you speculate about the cause of the problem, please
@@ -128,18 +128,6 @@
 Never set this variable directly, use the command `cwarn-mode'
 instead.")
 
-(defcustom global-cwarn-mode nil
-  "When on, suspicious C and C++ constructions are highlighted.
-
-Set this variable using \\[customize] or use the command
-`global-cwarn-mode'."
-  :group 'cwarn
-  :initialize 'custom-initialize-default
-  :set (lambda (symbol value)
-	 (global-cwarn-mode (or value 0)))
-  :type 'boolean
-  :require 'cwarn)
-
 (defcustom cwarn-configuration
   '((c-mode (not reference))
     (c++-mode t))
@@ -187,26 +175,6 @@
   :group 'cwarn
   :type 'string)
 
-(defcustom cwarn-mode-hook nil
-  "*Functions to run when CWarn mode is activated."
-  :tag "CWarn mode hook"                ; To separate it from `global-...'
-  :group 'cwarn
-  :type 'hook)
-
-(defcustom global-cwarn-mode-text ""
-  "*String to display when Global CWarn mode is active.
-
-The default is nothing since when this mode is active this text doesn't
-vary over time, or between buffers.  Hence mode line text
-would only waste precious space."
-  :group 'cwarn
-  :type 'string)
-
-(defcustom global-cwarn-mode-hook nil
-  "*Hook called when Global CWarn mode is activated."
-  :group 'cwarn
-  :type 'hook)
-
 (defcustom cwarn-load-hook nil
   "*Functions to run when CWarn mode is first loaded."
   :tag "Load Hook"
@@ -217,7 +185,7 @@
 ;;{{{ The modes
 
 ;;;###autoload
-(defun cwarn-mode (&optional arg)
+(define-minor-mode cwarn-mode
   "Minor mode that highlights suspicious C and C++ constructions.
 
 Note, in addition to enabling this minor mode, the major mode must
@@ -225,23 +193,9 @@
 C++ modes are included.
 
 With ARG, turn CWarn mode on if and only if arg is positive."
-  (interactive "P")
-  (make-local-variable 'cwarn-mode)
-  (setq cwarn-mode
-	(if (null arg)
-	    (not cwarn-mode)
-	  (> (prefix-numeric-value arg) 0)))
-  (if (and cwarn-verbose
-	   (interactive-p))
-      (message "Cwarn mode is now %s."
-	       (if cwarn-mode "on" "off")))
-  (if (not global-cwarn-mode)
-      (if cwarn-mode
-	  (cwarn-font-lock-add-keywords)
-	(cwarn-font-lock-remove-keywords)))
-  (font-lock-fontify-buffer)
-  (if cwarn-mode
-      (run-hooks 'cwarn-mode-hook)))
+  nil cwarn-mode-text nil
+  (cwarn-font-lock-keywords cwarn-mode)
+  (if font-lock-mode (font-lock-fontify-buffer)))
 
 ;;;###autoload
 (defun turn-on-cwarn-mode ()
@@ -251,46 +205,6 @@
   (add-hook 'c-mode-hook 'turn-on-cwarn-mode)"
   (cwarn-mode 1))
 
-;;;###autoload
-(defun global-cwarn-mode (&optional arg)
-  "Hightlight suspicious C and C++ constructions in all buffers.
-
-With ARG, turn CWarn mode on globally if and only if arg is positive."
-  (interactive "P")
-  (let ((old-global-cwarn-mode global-cwarn-mode))
-    (setq global-cwarn-mode
-	  (if (null arg)
-	      (not global-cwarn-mode)
-	    (> (prefix-numeric-value arg) 0)))
-    (if (and cwarn-verbose
-	     (interactive-p))
-	(message "Global CWarn mode is now %s."
-		 (if global-cwarn-mode "on" "off")))
-    (when (not (eq global-cwarn-mode old-global-cwarn-mode))
-      ;; Update for all future buffers.
-      (dolist (conf cwarn-configuration)
-	(if global-cwarn-mode
-	    (cwarn-font-lock-add-keywords (car conf))
-	  (cwarn-font-lock-remove-keywords (car conf))))
-      ;; Update all existing buffers.
-      (save-excursion
-	(dolist (buffer (buffer-list))
-	  (set-buffer buffer)
-	  ;; Update keywords in alive buffers.
-	  (when (and font-lock-mode
-		     (not cwarn-mode)
-		     (cwarn-is-enabled major-mode))
-	    (if global-cwarn-mode
-		(cwarn-font-lock-add-keywords)
-	      (cwarn-font-lock-remove-keywords))
-	    (font-lock-fontify-buffer))))))
-    ;; Kills all added keywords :-(
-    ;; (font-lock-mode 0)
-    ;; (makunbound 'font-lock-keywords)
-    ;; (font-lock-mode 1))))
-  (when global-cwarn-mode
-    (run-hooks 'global-cwarn-mode-hook)))
-
 ;;}}}
 ;;{{{ Help functions
 
@@ -320,25 +234,17 @@
     (back-to-indentation)
     (eq (char-after) ?#)))
 
-(defun cwarn-font-lock-add-keywords (&optional mode)
-  "Install keywords into major MODE, or into current buffer if nil."
+(defun cwarn-font-lock-keywords (addp)
+  "Install/Remove keywords into current buffer.
+If ADDP is non-nil, install else remove."
   (dolist (pair cwarn-font-lock-feature-keywords-alist)
     (let ((feature (car pair))
 	  (keywords (cdr pair)))
       (if (not (listp keywords))
 	  (setq keywords (symbol-value keywords)))
-      (if (cwarn-is-enabled (or mode major-mode) feature)
-	  (font-lock-add-keywords mode keywords)))))
-
-(defun cwarn-font-lock-remove-keywords (&optional mode)
-  "Remove keywords from major MODE, or from current buffer if nil."
-  (dolist (pair cwarn-font-lock-feature-keywords-alist)
-    (let ((feature (car pair))
-	  (keywords (cdr pair)))
-      (if (not (listp keywords))
-	  (setq keywords (symbol-value keywords)))
-      (if (cwarn-is-enabled (or mode major-mode) feature)
-	  (font-lock-remove-keywords mode keywords)))))
+      (if (cwarn-is-enabled major-mode feature)
+	  (funcall (if addp 'font-lock-add-keywords 'font-lock-remove-keywords)
+		   nil keywords)))))
 
 ;;}}}
 ;;{{{ Backward compatibility
@@ -356,7 +262,7 @@
 top-level not enclosed within a class definition, t is returned.
 Otherwise, a 2-vector is returned where the zeroth element is the
 buffer position of the start of the class declaration, and the first
-element is the buffer position of the enclosing class's opening
+element is the buffer position of the enclosing class' opening
 brace."
   (let ((state (c-parse-state)))
     (or (not (c-most-enclosing-brace state))
@@ -375,7 +281,7 @@
 ;; A match function should act like a normal forward search.  They
 ;; should return non-nil if they found a candidate and the match data
 ;; should correspond to the highlight part of the font-lock keyword.
-;; The functions shold not generate errors, in that case font-lock
+;; The functions should not generate errors, in that case font-lock
 ;; will fail to highlight the buffer.  A match function takes one
 ;; argument, LIMIT, that represent the end of area to be searched.
 ;;
@@ -383,6 +289,21 @@
 ;; mapping from CWarn features to the font-lock keywords defined
 ;; below.
 
+(defmacro cwarn-font-lock-match (re &rest body)
+  "Match RE but only if BODY holds."
+  `(let ((res nil))
+     (while
+	 (progn
+	   (setq res (re-search-forward ,re limit t))
+	   (and res
+		(save-excursion
+		  (when (match-beginning 1) (goto-char (match-beginning 1)))
+		  (condition-case nil	; In case something barfs.
+		      (not (save-match-data
+			     ,@body))
+		    (error t))))))
+     res))
+
 ;;{{{ Assignment in expressions
 
 (defconst cwarn-font-lock-assignment-keywords
@@ -391,28 +312,17 @@
 
 (defun cwarn-font-lock-match-assignment-in-expression (limit)
   "Match assignments inside expressions."
-  (let ((res nil))
-    (while
-	(progn
-	  (setq res (re-search-forward
-		     "[^!<>=]\\(\\([-+*/%&^|]\\|<<\\|>>\\)?=\\)[^=]"
-		     limit t))
-	  (and res
-	       (save-excursion
-		 (goto-char (match-beginning 1))
-		 (condition-case nil    ; In case "backward-up-list" barfs.
-		     (progn
-		       (backward-up-list 1)
-		       (or (not (memq (following-char) '(?\( ?\[)))
-			   (save-match-data
-			     (skip-chars-backward " ")
-			     (skip-chars-backward "a-zA-Z0-9_")
-			     (or
-			      ;; Default parameter of function.
-			      (c-at-toplevel-p)
-			      (looking-at "for\\>")))))
-		   (error t))))))
-      res))
+  (cwarn-font-lock-match
+   "[^!<>=]\\(\\([-+*/%&^|]\\|<<\\|>>\\)?=\\)[^=]"
+   (backward-up-list 1)
+   (and (memq (following-char) '(?\( ?\[))
+	(not (progn
+	       (skip-chars-backward " ")
+	       (skip-chars-backward "a-zA-Z0-9_")
+	       (or
+		;; Default parameter of function.
+		(c-at-toplevel-p)
+		(looking-at "for\\>")))))))
 
 ;;}}}
 ;;{{{ Semicolon
@@ -422,25 +332,17 @@
 
 (defun cwarn-font-lock-match-dangerous-semicolon (limit)
   "Match semicolons directly after `for', `while', and `if'.
-Tne semicolon after a `do { ... } while (x);' construction is not matched."
-  (let ((res nil))
-    (while
-	(progn
-	  (setq res (search-forward ";" limit t))
-	  (and res
-	       (save-excursion
-		 (condition-case nil    ; In case something barfs.
-		     (save-match-data
-		       (backward-sexp 2) ; Expression and keyword.
-		       (not (or (looking-at "\\(for\\|if\\)\\>")
-				(and (looking-at "while\\>")
-				     (condition-case nil
-					 (progn
-					   (backward-sexp 2) ; Body and "do".
-					   (not (looking-at "do\\>")))
-				       (error t))))))
-		   (error t))))))
-      res))
+The semicolon after a `do { ... } while (x);' construction is not matched."
+  (cwarn-font-lock-match
+   ";"
+   (backward-sexp 2)			; Expression and keyword.
+   (or (looking-at "\\(for\\|if\\)\\>")
+       (and (looking-at "while\\>")
+	    (condition-case nil
+		(progn
+		  (backward-sexp 2)	; Body and "do".
+		  (not (looking-at "do\\>")))
+	      (error t))))))
 
 ;;}}}
 ;;{{{ Reference
@@ -450,43 +352,32 @@
 
 (defun cwarn-font-lock-match-reference (limit)
   "Font-lock matcher for C++ reference parameters."
-  (let ((res nil))
-    (while
-	(progn
-	  (setq res (re-search-forward "[^&]\\(&\\)[^&=]" limit t))
-	  (and res
-	       (save-excursion
-		 (goto-char (match-beginning 1))
-		 (condition-case nil    ; In case something barfs.
-		     (save-match-data
-		       (backward-up-list 1)
-		       (or (not (eq (following-char) ?\())
-			   (cwarn-inside-macro)
-			   (not (c-at-toplevel-p))))
-		   (error t))))))
-    res))
+  (cwarn-font-lock-match
+   "[^&]\\(&\\)[^&=]"
+   (backward-up-list 1)
+   (and (eq (following-char) ?\()
+	(not (cwarn-inside-macro))
+	(c-at-toplevel-p))))
 
 ;;}}}
 
 ;;}}}
 ;;{{{ The end
 
-(unless (assq 'cwarn-mode minor-mode-alist)
-  (push '(cwarn-mode cwarn-mode-text)
-	minor-mode-alist))
-(unless (assq 'global-cwarn-mode minor-mode-alist)
-  (push '(global-cwarn-mode global-cwarn-mode-text)
-	minor-mode-alist))
+(defun turn-on-cwarn-mode-if-enabled ()
+  "Turn on CWarn mode in the current buffer if applicable.
+The mode is turned if some feature is enabled for the current
+`major-mode' in `cwarn-configuration'."
+  (if (cwarn-is-enabled major-mode) (turn-on-cwarn-mode)))
+
+;;;###autoload
+(easy-mmode-define-global-mode global-cwarn-mode cwarn-mode
+			       turn-on-cwarn-mode-if-enabled)
 
 (provide 'cwarn)
 
 (run-hooks 'cwarn-load-hook)
 
-;; This makes it possible to set Global CWarn mode from
-;; Customize.
-(if global-cwarn-mode
-    (global-cwarn-mode 1))
-
 ;;}}}
 
 ;;; cwarn.el ends here