(toplevel): Provide `descr-text'.
[bpt/emacs.git] / lisp / whitespace.el
index 459383a..e8c4dd4 100644 (file)
@@ -1,10 +1,11 @@
-;;; whitespace.el --- Warn about and clean bogus whitespaces in the file.
+;;; whitespace.el --- warn about and clean bogus whitespaces in the file
 
-;; Copyright (C) 1999 Free Software Foundation, Inc.
+;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
 
-;; Author: Rajesh Vaidheeswarran <rv@dsmit.com>
+;; Author: Rajesh Vaidheeswarran <rv@gnu.org>
 ;; Keywords: convenience
 
+;; $Id: whitespace.el,v 1.18 2001/08/20 20:56:08 rv Exp $
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 
 ;;; Code:
 
-;; add a hook to find-file-hooks and kill-buffer-hook
-(add-hook 'find-file-hooks 'whitespace-buffer)
-(add-hook 'kill-buffer-hook 'whitespace-buffer)
-
-(defvar whitespace-version "2.3" "Version of the whitespace library.")
-;; Find out what type of Emacs we are running in.
-(defvar whitespace-running-emacs (if (string-match "XEmacs\\|Lucid"
-                                                  emacs-version) nil t)
-  "If this is Emacs, not XEmacs, this is t.")
-
-(if whitespace-running-emacs (require 'timer))
+(defvar whitespace-version "3.2" "Version of the whitespace library.")
 
 (defvar whitespace-all-buffer-files nil
   "An associated list of buffers and files checked for whitespace cleanliness.
@@ -59,69 +50,149 @@ visited by the buffers.")
 (defvar whitespace-rescan-timer nil
   "Timer object used to rescan the files in buffers that have been modified.")
 
-;; For users of Emacs 19.x, defgroup and defcustom are not defined.
+;; Tell Emacs about this new kind of minor mode
+(defvar whitespace-mode nil
+  "Non-nil when Whitespace mode (a minor mode) is enabled.")
+(make-variable-buffer-local 'whitespace-mode)
+(put 'whitespace-mode 'permanent-local nil)
+
+(defvar whitespace-mode-line nil
+  "String to display in the mode line for Whitespace mode.")
+(make-variable-buffer-local 'whitespace-mode-line)
+(put 'whitespace-mode-line 'permanent-local nil)
 
+(defvar whitespace-check-buffer-leading nil
+  "Test leading whitespace for file in current buffer if t")
+(make-variable-buffer-local 'whitespace-check-buffer-leading)
+(put 'whitespace-check-buffer-leading 'permanent-local nil)
+
+(defvar whitespace-check-buffer-trailing nil
+  "Test trailing whitespace for file in current buffer if t")
+(make-variable-buffer-local 'whitespace-check-buffer-trailing)
+(put 'whitespace-check-buffer-trailing 'permanent-local nil)
+
+(defvar whitespace-check-buffer-indent nil
+  "Test indentation whitespace for file in current buffer if t")
+(make-variable-buffer-local 'whitespace-check-buffer-indent)
+(put 'whitespace-check-buffer-indent 'permanent-local nil)
+
+(defvar whitespace-check-buffer-spacetab nil
+  "Test Space-followed-by-TABS whitespace for file in current buffer if t")
+(make-variable-buffer-local 'whitespace-check-buffer-spacetab)
+(put 'whitespace-check-buffer-spacetab 'permanent-local nil)
+
+(defvar whitespace-check-buffer-ateol nil
+  "Test end-of-line whitespace for file in current buffer if t")
+(make-variable-buffer-local 'whitespace-check-buffer-ateol)
+(put 'whitespace-check-buffer-ateol 'permanent-local nil)
+
+(defvar whitespace-highlighted-space nil
+  "The variable to store the extent to highlight")
+(make-variable-buffer-local 'whitespace-highlighted-space)
+(put 'whitespace-highlighted-space 'permanent-local nil)
+
+;; For flavors of Emacs which don't define `defgroup' and `defcustom'.
 (eval-when-compile
-  (if (< (string-to-int emacs-version) 20)
-      (progn
-       (defmacro defgroup (sym memb doc &rest args)
-         "Null macro for defgroup in all versions of Emacs < 20.x"
-         t)
-       (defmacro defcustom (sym val doc &rest args)
-         "Macro to alias defcustom to defvar in all versions of Emacs < 20.x"
-         `(defvar ,sym ,val ,doc)))))
-
+  (if (not (fboundp 'defgroup))
+      (defmacro defgroup (sym memb doc &rest args)
+       "Null macro for defgroup in all versions of Emacs that don't define
+defgroup"
+       t))
+  (if (not (fboundp 'defcustom))
+      (defmacro defcustom (sym val doc &rest args)
+       "Macro to alias defcustom to defvar in all versions of Emacs that
+don't define defcustom"
+       `(defvar ,sym ,val ,doc))))
+
+(if (fboundp 'make-overlay)
+    (progn
+      (defalias 'whitespace-make-overlay 'make-overlay)
+      (defalias 'whitespace-overlay-put 'overlay-put)
+      (defalias 'whitespace-delete-overlay 'delete-overlay)
+      (defalias 'whitespace-overlay-start 'overlay-start)
+      (defalias 'whitespace-overlay-end 'overlay-end)
+      (defalias 'whitespace-mode-line-update 'force-mode-line-update))
+  (defalias 'whitespace-make-overlay 'make-extent)
+  (defalias 'whitespace-overlay-put 'set-extent-property)
+  (defalias 'whitespace-delete-overlay 'delete-extent)
+  (defalias 'whitespace-overlay-start 'extent-start)
+  (defalias 'whitespace-overlay-end 'extent-end)
+  (defalias 'whitespace-mode-line-update 'redraw-modeline))
+
+(if (featurep 'xemacs)
 (defgroup whitespace nil
   "Check for and fix five different types of whitespaces in source code."
   ;; Since XEmacs doesn't have a 'convenience group, use the next best group
   ;; which is 'editing?
-  :group (if whitespace-running-emacs 'convenience 'editing))
+  :group 'editing)
+(defgroup whitespace nil
+  "Check for and fix five different types of whitespaces in source code."
+  :version "21.1"
+  :group 'convenience))
 
 (defcustom whitespace-check-leading-whitespace t
-  "Flag to check leading whitespace."
+  "Flag to check leading whitespace. This is the global for the system.
+It can be overriden by setting a buffer local variable
+`whitespace-check-buffer-leading'"
   :type 'boolean
   :group 'whitespace)
 
 (defcustom whitespace-check-trailing-whitespace t
-  "Flag to check trailing whitespace."
+  "Flag to check trailing whitespace. This is the global for the system.
+It can be overriden by setting a buffer local variable
+`whitespace-check-buffer-trailing'"
   :type 'boolean
   :group 'whitespace)
 
 (defcustom whitespace-check-spacetab-whitespace t
-  "Flag to check space followed by a TAB."
+  "Flag to check space followed by a TAB. This is the global for the system.
+It can be overriden by setting a buffer local variable
+`whitespace-check-buffer-spacetab'"
   :type 'boolean
   :group 'whitespace)
 
-(defcustom whitespace-spacetab-regexp " \t"
+(defcustom whitespace-spacetab-regexp "[ ]+\t"
   "Regexp to match a space followed by a TAB."
-  :type 'string
+  :type 'regexp
   :group 'whitespace)
 
-(defcustom whitespace-check-indent-whitespace t
-  "Flag to check indentation whitespace."
+(defcustom whitespace-check-indent-whitespace indent-tabs-mode
+  "Flag to check indentation whitespace. This is the global for the system.
+It can be overriden by setting a buffer local variable
+`whitespace-check-buffer-indent'"
   :type 'boolean
   :group 'whitespace)
 
 (defcustom whitespace-indent-regexp (concat "^\\(\t*\\)    " "    ")
   "Regexp to match (any TABS followed by) 8/more whitespaces at start of line."
-  :type 'string
+  :type 'regexp
   :group 'whitespace)
 
 (defcustom whitespace-check-ateol-whitespace t
-  "Flag to check end-of-line whitespace."
+  "Flag to check end-of-line whitespace. This is the global for the system.
+It can be overriden by setting a buffer local variable
+`whitespace-check-buffer-ateol'"
   :type 'boolean
   :group 'whitespace)
 
-(defcustom whitespace-ateol-regexp "[ \t]$"
+;; (defcustom whitespace-ateol-regexp "[ \t]$"
+(defcustom whitespace-ateol-regexp "[ \t]+$"
   "Regexp to match a TAB or a space at the EOL."
-  :type 'string
+  :type 'regexp
   :group 'whitespace)
 
 (defcustom whitespace-errbuf "*Whitespace Errors*"
-  "The buffer where whitespace related messages will be logged."
+  "The name of the buffer where whitespace related messages will be logged."
   :type 'string
   :group 'whitespace)
 
+(defcustom whitespace-abort-on-error nil
+  "While writing a file, abort if the file is unclean. If
+`whitespace-auto-cleanup' is set, that takes precedence over this
+variable."
+  :type  'boolean
+  :group 'whitespace)
+
 (defcustom whitespace-auto-cleanup nil
   "Cleanup a buffer automatically on finding it whitespace unclean."
   :type  'boolean
@@ -153,7 +224,7 @@ Errors*' buffer before opening (or closing) another file."
 
   "Major Modes in which we turn on whitespace checking.
 
-These are mostly programming and documentation modes. But you may add other
+These are mostly programming and documentation modes.  But you may add other
 modes that you want whitespaces checked in by adding something like the
 following to your `.emacs':
 
@@ -161,9 +232,10 @@ following to your `.emacs':
                                            whitespace-modes))\)
 
 Or, alternately, you can use the Emacs `customize' command to set this."
+  :type '(repeat symbol)
   :group 'whitespace)
 
-(defcustom whitespace-rescan-timer-time 60
+(defcustom whitespace-rescan-timer-time 600
   "Period in seconds to rescan modified buffers for whitespace creep.
 
 This is the period after which the timer will fire causing
@@ -174,19 +246,51 @@ To disable timer scans, set this to zero."
   :type 'integer
   :group 'whitespace)
 
-;; Tell Emacs about this new kind of minor mode
-(make-variable-buffer-local 'whitespace-mode)
-(put 'whitespace-mode 'permanent-local nil)
-(set-default 'whitespace-mode nil)
+(defcustom whitespace-display-in-modeline t
+  "Display whitespace errors on the modeline."
+  :type 'boolean
+  :group 'whitespace)
 
-(make-variable-buffer-local 'whitespace-mode-line)
-(put 'whitespace-mode-line 'permanent-local nil)
-(set-default 'whitespace-mode-line nil)
+(defcustom whitespace-display-spaces-in-color t
+  "Display the bogus whitespaces by coloring them with
+`whitespace-highlight-face'."
+  :type 'boolean
+  :group 'whitespace)
+
+(defgroup whitespace-faces nil
+  "Faces used in whitespace."
+  :prefix "whitespace-"
+  :group 'whitespace
+  :group 'faces)
+
+(defface whitespace-highlight-face '((((class color) (background light))
+                                   (:background "green"))
+                                  (((class color) (background dark))
+                                   (:background "sea green"))
+                                  (((class grayscale monochrome)
+                                    (background light))
+                                   (:background "black"))
+                                  (((class grayscale monochrome)
+                                    (background dark))
+                                   (:background "white")))
+  "Face used for highlighting the bogus whitespaces that exist in the buffer."
+  :group 'whitespace-faces)
 
 (if (not (assoc 'whitespace-mode minor-mode-alist))
     (setq minor-mode-alist (cons '(whitespace-mode whitespace-mode-line)
                                 minor-mode-alist)))
 
+(set-default 'whitespace-check-buffer-leading
+            whitespace-check-leading-whitespace)
+(set-default 'whitespace-check-buffer-trailing
+            whitespace-check-trailing-whitespace)
+(set-default 'whitespace-check-buffer-indent
+            whitespace-check-indent-whitespace)
+(set-default 'whitespace-check-buffer-spacetab
+            whitespace-check-spacetab-whitespace)
+(set-default 'whitespace-check-buffer-ateol
+            whitespace-check-ateol-whitespace)
+
 (defun whitespace-check-whitespace-mode (&optional arg)
   "Test and set the whitespace-mode in qualifying buffers."
   (if (null whitespace-mode)
@@ -196,9 +300,64 @@ To disable timer scans, set this to zero."
              nil))))
 
 ;;;###autoload
-(defun whitespace-buffer (&optional quiet)
-  "Find five different types of white spaces in buffer:
+(defun whitespace-toggle-leading-check ()
+  "Toggle the check for leading space in the local buffer."
+  (interactive)
+  (let ((current-val whitespace-check-buffer-leading))
+    (setq whitespace-check-buffer-leading (not current-val))
+    (message "Will%s check for leading space in buffer."
+            (if whitespace-check-buffer-leading "" " not"))
+    (if whitespace-check-buffer-leading (whitespace-buffer-leading))))
+
+;;;###autoload
+(defun whitespace-toggle-trailing-check ()
+  "Toggle the check for trailing space in the local buffer."
+  (interactive)
+  (let ((current-val whitespace-check-buffer-trailing))
+    (setq whitespace-check-buffer-trailing (not current-val))
+    (message "Will%s check for trailing space in buffer."
+            (if whitespace-check-buffer-trailing "" " not"))
+    (if whitespace-check-buffer-trailing (whitespace-buffer-trailing))))
+
+;;;###autoload
+(defun whitespace-toggle-indent-check ()
+  "Toggle the check for indentation space in the local buffer."
+  (interactive)
+  (let ((current-val whitespace-check-buffer-indent))
+    (setq whitespace-check-buffer-indent (not current-val))
+    (message "Will%s check for indentation space in buffer."
+            (if whitespace-check-buffer-indent "" " not"))
+    (if whitespace-check-buffer-indent
+       (whitespace-buffer-search whitespace-indent-regexp))))
+
+;;;###autoload
+(defun whitespace-toggle-spacetab-check ()
+  "Toggle the check for space-followed-by-TABs in the local buffer."
+  (interactive)
+  (let ((current-val whitespace-check-buffer-spacetab))
+    (setq whitespace-check-buffer-spacetab (not current-val))
+    (message "Will%s check for space-followed-by-TABs in buffer."
+            (if whitespace-check-buffer-spacetab "" " not"))
+    (if whitespace-check-buffer-spacetab
+       (whitespace-buffer-search whitespace-spacetab-regexp))))
+
+
+;;;###autoload
+(defun whitespace-toggle-ateol-check ()
+  "Toggle the check for end-of-line space in the local buffer."
+  (interactive)
+  (let ((current-val whitespace-check-buffer-ateol))
+    (setq whitespace-check-buffer-ateol (not current-val))
+    (message "Will%s check for end-of-line space in buffer."
+            (if whitespace-check-buffer-ateol "" " not"))
+    (if whitespace-check-buffer-ateol
+       (whitespace-buffer-search whitespace-ateol-regexp))))
+
 
+;;;###autoload
+(defun whitespace-buffer (&optional quiet)
+  "Find five different types of white spaces in buffer.
+These are:
 1. Leading space \(empty lines at the top of a file\).
 2. Trailing space \(empty lines at the end of a file\).
 3. Indentation space \(8 or more spaces, that should be replaced with TABS\).
@@ -210,95 +369,99 @@ and:
 1. the major mode is one of the whitespace-modes, or
 2. `whitespace-buffer' was explicitly called with a prefix argument."
   (interactive)
-  (whitespace-check-whitespace-mode current-prefix-arg)
-  (if (and buffer-file-name (> (buffer-size) 0) whitespace-mode)
-      (progn
-       (whitespace-check-buffer-list (buffer-name) buffer-file-name)
-       (whitespace-tickle-timer)
-       (if whitespace-auto-cleanup
-           (if (and (not quiet) buffer-read-only)
-               (message "Can't Cleanup: %s is read-only." (buffer-name))
-             (whitespace-cleanup))
-         (let ((whitespace-leading (if whitespace-check-leading-whitespace
-                                       (whitespace-buffer-leading)
-                                     nil))
-               (whitespace-trailing (if whitespace-check-trailing-whitespace
-                                        (whitespace-buffer-trailing)
-                                      nil))
-               (whitespace-indent (if whitespace-check-indent-whitespace
-                                      (whitespace-buffer-search
-                                       whitespace-indent-regexp)
-                                    nil))
-               (whitespace-spacetab (if whitespace-check-spacetab-whitespace
+  (let ((whitespace-error nil))
+    (whitespace-check-whitespace-mode current-prefix-arg)
+    (if (and buffer-file-name (> (buffer-size) 0) whitespace-mode)
+       (progn
+         (whitespace-check-buffer-list (buffer-name) buffer-file-name)
+         (whitespace-tickle-timer)
+         (whitespace-unhighlight-the-space)
+         (if whitespace-auto-cleanup
+             (if buffer-read-only
+                 (if (not quiet)
+                     (message "Can't cleanup: %s is read-only" (buffer-name)))
+               (whitespace-cleanup))
+           (let ((whitespace-leading (if whitespace-check-buffer-leading
+                                         (whitespace-buffer-leading)
+                                       nil))
+                 (whitespace-trailing (if whitespace-check-buffer-trailing
+                                          (whitespace-buffer-trailing)
+                                        nil))
+                 (whitespace-indent (if whitespace-check-buffer-indent
                                         (whitespace-buffer-search
-                                         whitespace-spacetab-regexp)
+                                         whitespace-indent-regexp)
                                       nil))
-               (whitespace-ateol (if whitespace-check-ateol-whitespace
-                                     (whitespace-buffer-search
-                                      whitespace-ateol-regexp)
-                                   nil))
-               (whitespace-errmsg nil)
-               (whitespace-error nil)
-               (whitespace-filename buffer-file-name)
-               (whitespace-this-modeline ""))
-
-           ;; Now let's complain if we found any of the above.
-           (setq whitespace-error (or whitespace-leading whitespace-indent
-                                      whitespace-spacetab whitespace-ateol
-                                      whitespace-trailing))
-
-           (if whitespace-error
-               (progn
-                 (setq whitespace-errmsg
-                       (concat whitespace-filename " contains:\n"
-                               (if whitespace-leading "Leading whitespace\n")
-                               (if whitespace-indent
-                                   (concat "Indentation whitespace"
-                                           whitespace-indent "\n"))
-                               (if whitespace-spacetab
-                                   (concat "Space followed by Tab"
-                                           whitespace-spacetab "\n"))
-                               (if whitespace-ateol
-                                   (concat "End-of-line whitespace"
-                                           whitespace-ateol "\n"))
-                               (if whitespace-trailing
-                                   "Trailing whitespace.\n")
-                               "\ntype "
-                               "`whitespace-cleanup' to cleanup the file."))
-                 (setq whitespace-this-modeline
-                       (concat (if whitespace-ateol "e")
-                               (if whitespace-indent "i")
-                               (if whitespace-leading "l")
-                               (if whitespace-spacetab "s")
-                               (if whitespace-trailing "t")))
-                 (setq whitespace-mode-line
-                       (concat " W:" whitespace-this-modeline))
-                 (whitespace-force-mode-line-update)))
-
-           ;; Now test and set the whitespaces that are not checked.
-           (whitespace-display-unchecked-whitespaces
-            (if whitespace-error
-                (concat " W:" whitespace-this-modeline)))
-           (save-excursion
-             (get-buffer-create whitespace-errbuf)
-             (kill-buffer whitespace-errbuf)
-             (get-buffer-create whitespace-errbuf)
-             (set-buffer whitespace-errbuf)
-             (if whitespace-errmsg
+                 (whitespace-spacetab (if whitespace-check-buffer-spacetab
+                                          (whitespace-buffer-search
+                                           whitespace-spacetab-regexp)
+                                        nil))
+                 (whitespace-ateol (if whitespace-check-buffer-ateol
+                                       (whitespace-buffer-search
+                                        whitespace-ateol-regexp)
+                                     nil))
+                 (whitespace-errmsg nil)
+                 (whitespace-filename buffer-file-name)
+                 (whitespace-this-modeline ""))
+
+             ;; Now let's complain if we found any of the above.
+             (setq whitespace-error (or whitespace-leading whitespace-indent
+                                        whitespace-spacetab whitespace-ateol
+                                        whitespace-trailing))
+
+             (if whitespace-error
                  (progn
-                   (insert whitespace-errmsg)
-                   (if (not (or quiet whitespace-silent))
-                       (display-buffer whitespace-errbuf t))
-                   (if (not quiet)
-                       (message "Whitespaces: [%s] in %s"
-                                whitespace-this-modeline
-                                whitespace-filename)))
-               (if (not quiet)
-                   (message "%s clean" whitespace-filename)))))))))
+                   (setq whitespace-errmsg
+                         (concat whitespace-filename " contains:\n"
+                                 (if whitespace-leading
+                                     "Leading whitespace\n")
+                                 (if whitespace-indent
+                                     (concat "Indentation whitespace"
+                                             whitespace-indent "\n"))
+                                 (if whitespace-spacetab
+                                     (concat "Space followed by Tab"
+                                             whitespace-spacetab "\n"))
+                                 (if whitespace-ateol
+                                     (concat "End-of-line whitespace"
+                                             whitespace-ateol "\n"))
+                                 (if whitespace-trailing
+                                     "Trailing whitespace\n")
+                                 "\ntype `M-x whitespace-cleanup' to "
+                                 "cleanup the file."))
+                   (setq whitespace-this-modeline
+                         (concat (if whitespace-ateol "e")
+                                 (if whitespace-indent "i")
+                                 (if whitespace-leading "l")
+                                 (if whitespace-spacetab "s")
+                                 (if whitespace-trailing "t")))))
+             (whitespace-update-modeline whitespace-this-modeline)
+             (save-excursion
+               (get-buffer-create whitespace-errbuf)
+               (kill-buffer whitespace-errbuf)
+               (get-buffer-create whitespace-errbuf)
+               (set-buffer whitespace-errbuf)
+               (if whitespace-errmsg
+                   (progn
+                     (insert whitespace-errmsg)
+                     (if (not (or quiet whitespace-silent))
+                         (display-buffer whitespace-errbuf t))
+                     (if (not quiet)
+                         (message "Whitespaces: [%s%s] in %s"
+                                  whitespace-this-modeline
+                                  (let ((whitespace-unchecked
+                                         (whitespace-unchecked-whitespaces)))
+                                    (if whitespace-unchecked
+                                        (concat "!" whitespace-unchecked)
+                                      ""))
+                                  whitespace-filename)))
+                 (if (not quiet)
+                     (message "%s clean" whitespace-filename))))))))
+    (if whitespace-error
+       t
+      nil)))
 
 ;;;###autoload
 (defun whitespace-region (s e)
-  "Check a region specified by point and mark for whitespace errors."
+  "Check the region for whitespace errors."
   (interactive "r")
   (save-excursion
     (save-restriction
@@ -323,31 +486,31 @@ whitespace problems."
        ;; they are displayed.
        (setq tab-width whitespace-tabwith)
 
-       (if (and whitespace-check-leading-whitespace
+       (if (and whitespace-check-buffer-leading
                 (whitespace-buffer-leading))
            (progn
              (whitespace-buffer-leading-cleanup)
              (setq whitespace-any t)))
 
-       (if (and whitespace-check-trailing-whitespace
+       (if (and whitespace-check-buffer-trailing
                 (whitespace-buffer-trailing))
            (progn
              (whitespace-buffer-trailing-cleanup)
              (setq whitespace-any t)))
 
-       (if (and whitespace-check-indent-whitespace
+       (if (and whitespace-check-buffer-indent
                 (whitespace-buffer-search whitespace-indent-regexp))
            (progn
              (whitespace-indent-cleanup)
              (setq whitespace-any t)))
 
-       (if (and whitespace-check-spacetab-whitespace
+       (if (and whitespace-check-buffer-spacetab
                 (whitespace-buffer-search whitespace-spacetab-regexp))
            (progn
              (whitespace-buffer-cleanup whitespace-spacetab-regexp "\t")
              (setq whitespace-any t)))
 
-       (if (and whitespace-check-ateol-whitespace
+       (if (and whitespace-check-buffer-ateol
                 (whitespace-buffer-search whitespace-ateol-regexp))
            (progn
              (whitespace-buffer-cleanup whitespace-ateol-regexp "")
@@ -358,14 +521,12 @@ whitespace problems."
            (whitespace-cleanup)
          (progn
            (message "%s clean" buffer-file-name)
-           (setq whitespace-mode-line nil)
-           (whitespace-force-mode-line-update)
-           (whitespace-display-unchecked-whitespaces)))
+           (whitespace-update-modeline)))
        (setq tab-width whitespace-tabwith-saved))))
 
 ;;;###autoload
 (defun whitespace-cleanup-region (s e)
-  "Whitespace cleanup on a region specified by point and mark."
+  "Whitespace cleanup on the region."
   (interactive "r")
   (save-excursion
     (save-restriction
@@ -384,7 +545,9 @@ whitespace problems."
       (end-of-line)
       (setq pmax (point))
       (if (equal pmin pmax)
-         t
+         (progn
+           (whitespace-highlight-the-space pmin pmax)
+           t)
        nil))))
 
 (defun whitespace-buffer-leading-cleanup ()
@@ -420,7 +583,9 @@ whitespace problems."
            (end-of-line)
            (setq pmax (point))
            (if (equal pmin pmax)
-               t
+               (progn
+                 (whitespace-highlight-the-space pmin pmax)
+                 t)
              nil))
        nil))))
 
@@ -454,8 +619,10 @@ whitespace problems."
     (save-excursion
       (goto-char (point-min))
       (while (re-search-forward regexp nil t)
-       (setq whitespace-retval (format "%s %s " whitespace-retval
-                                       (match-beginning 0))))
+       (progn
+         (setq whitespace-retval (format "%s %s" whitespace-retval
+                                       (match-beginning 0)))
+       (whitespace-highlight-the-space (match-beginning 0) (match-end 0))))
       (if (equal "" whitespace-retval)
          nil
        whitespace-retval))))
@@ -477,26 +644,60 @@ whitespace problems."
        (delete-region (match-beginning 0) (point))
        (indent-to column)))))
 
-(defun whitespace-display-unchecked-whitespaces (&optional whitespace-str)
-  "Update modeline with whitespaces whose testing has been turned off."
-  (let ((whitespace-this-modeline
-        (concat (if (not whitespace-check-ateol-whitespace) "e")
-                (if (not whitespace-check-indent-whitespace) "i")
-                (if (not whitespace-check-leading-whitespace) "l")
-                (if (not whitespace-check-spacetab-whitespace) "s")
-                (if (not whitespace-check-trailing-whitespace) "t"))))
-    (setq whitespace-mode-line whitespace-str)
-    (if (not (equal whitespace-this-modeline ""))
-      (setq whitespace-mode-line
-           (concat whitespace-str " Woff:" whitespace-this-modeline)))
-    (whitespace-force-mode-line-update)))
-
-;; Force mode line updation for different Emacs versions
-(defun whitespace-force-mode-line-update ()
-  "Force the mode line update for different flavors of Emacs."
-  (if whitespace-running-emacs
-      (force-mode-line-update)          ; Emacs
-    (redraw-modeline)))                 ; XEmacs
+(defun whitespace-unchecked-whitespaces ()
+  "Return the list of whitespaces whose testing has been suppressed."
+  (let ((unchecked-spaces
+        (concat (if (not whitespace-check-buffer-ateol) "e")
+                (if (not whitespace-check-buffer-indent) "i")
+                (if (not whitespace-check-buffer-leading) "l")
+                (if (not whitespace-check-buffer-spacetab) "s")
+                (if (not whitespace-check-buffer-trailing) "t"))))
+    (if (not (equal unchecked-spaces ""))
+       unchecked-spaces
+      nil)))
+
+(defun whitespace-update-modeline (&optional whitespace-err)
+  "Update modeline with whitespace errors.
+Also with whitespaces whose testing has been turned off."
+  (if whitespace-display-in-modeline
+      (progn
+       (setq whitespace-mode-line nil)
+       ;; Whitespace errors
+       (if (and whitespace-err (not (equal whitespace-err "")))
+           (setq whitespace-mode-line whitespace-err))
+       ;; Whitespace suppressed errors
+       (let ((whitespace-unchecked (whitespace-unchecked-whitespaces)))
+         (if whitespace-unchecked
+             (setq whitespace-mode-line
+                   (concat whitespace-mode-line "!" whitespace-unchecked))))
+       ;; Add the whitespace modeline prefix
+       (setq whitespace-mode-line (if whitespace-mode-line
+                                      (concat " W:" whitespace-mode-line)
+                                    nil))
+       (whitespace-mode-line-update))))
+
+(defun whitespace-highlight-the-space (b e)
+  "Highlight the current line, unhighlighting a previously jumped to line."
+  (if whitespace-display-spaces-in-color
+      (progn
+       (whitespace-unhighlight-the-space)
+       (add-to-list 'whitespace-highlighted-space
+                    (whitespace-make-overlay b e))
+       (whitespace-overlay-put (whitespace-make-overlay b e) 'face
+                               'whitespace-highlight-face))))
+;;  (add-hook 'pre-command-hook 'whitespace-unhighlight-the-space))
+
+(defun whitespace-unhighlight-the-space ()
+  "Unhighlight the currently highlight line."
+  (if (and whitespace-display-spaces-in-color whitespace-highlighted-space)
+      (let ((whitespace-this-space nil))
+       (while whitespace-highlighted-space
+         (setq whitespace-this-space (car whitespace-highlighted-space))
+         (setq whitespace-highlighted-space
+               (cdr whitespace-highlighted-space))
+         (whitespace-delete-overlay whitespace-this-space))
+       (setq whitespace-highlighted-space nil))
+    (remove-hook 'pre-command-hook 'whitespace-unhighlight-the-space)))
 
 (defun whitespace-check-buffer-list (buf-name buf-file)
   "Add a buffer and its file to the whitespace monitor list.
@@ -515,12 +716,9 @@ If timer is not set, then set it to scan the files in
 `whitespace-rescan-timer-time') for whitespace creep."
   (if (and whitespace-rescan-timer-time (not whitespace-rescan-timer))
       (setq whitespace-rescan-timer
-           (if whitespace-running-emacs
-               (run-at-time nil whitespace-rescan-timer-time
-                            'whitespace-rescan-files-in-buffers)
-             (add-timeout whitespace-rescan-timer-time
-                          'whitespace-rescan-files-in-buffers nil
-                          whitespace-rescan-timer-time)))))
+           (add-timeout whitespace-rescan-timer-time
+                        'whitespace-rescan-files-in-buffers nil
+                        whitespace-rescan-timer-time))))
 
 (defun whitespace-rescan-files-in-buffers (&optional arg)
   "Check monitored files for whitespace creep since last scan."
@@ -528,9 +726,7 @@ If timer is not set, then set it to scan the files in
        buffile bufname thiselt buf)
     (if (not whitespace-all-my-files)
        (progn
-         (if whitespace-running-emacs
-             (cancel-timer whitespace-rescan-timer)
-           (disable-timeout whitespace-rescan-timer))
+         (disable-timeout whitespace-rescan-timer)
          (setq whitespace-rescan-timer nil))
       (while whitespace-all-my-files
        (setq thiselt (car whitespace-all-my-files))
@@ -560,16 +756,59 @@ If timer is not set, then set it to scan the files in
 (defun whitespace-refresh-rescan-list (buffile bufname)
   "Refresh the list of files to be rescaned for whitespace creep."
   (if whitespace-all-buffer-files
+      (setq whitespace-all-buffer-files
+           (delete (list buffile bufname) whitespace-all-buffer-files))
+    (when whitespace-rescan-timer
+      (disable-timeout whitespace-rescan-timer)
+      (setq whitespace-rescan-timer nil))))
+
+;;;###autoload
+(defcustom whitespace-global-mode nil
+  "Toggle global Whitespace mode.
+
+Setting this variable directly does not take effect;
+use either \\[customize] or the function `whitespace-global-mode'
+\(which see)."
+  :set (lambda (sym val)
+        (whitespace-global-mode (or val 0)))
+  :initialize 'custom-initialize-default
+  :type 'boolean
+  :group 'whitespace
+  :require 'whitespace)
+
+;;;###autoload
+(defun whitespace-global-mode (&optional arg)
+  "Toggle using Whitespace mode in new buffers.
+With ARG, turn the mode on if and only iff ARG is positive.
+
+When this mode is active, `whitespace-buffer' is added to
+`find-file-hooks' and `kill-buffer-hook'."
+  (interactive "P")
+  (setq arg (if arg
+               (> (prefix-numeric-value arg) 0)
+             (not whitespace-global-mode)))
+  (if arg
       (progn
-       (setq whitespace-all-buffer-files
-             (delete (list buffile bufname) whitespace-all-buffer-files)))
-    (progn
-      (if (and whitespace-running-emacs (timerp whitespace-rescan-timer))
-         (cancel-timer whitespace-rescan-timer))
-      (if (and (not whitespace-running-emacs) whitespace-rescan-timer)
-         (disable-timeout whitespace-rescan-timer))
-      (if whitespace-rescan-timer
-         (setq whitespace-rescan-timer nil)))))
+       (add-hook 'find-file-hooks 'whitespace-buffer)
+       (add-hook 'local-write-file-hooks 'whitespace-write-file-hook)
+       (add-hook 'kill-buffer-hook 'whitespace-buffer))
+    (remove-hook 'find-file-hooks 'whitespace-buffer)
+    (remove-hook 'local-write-file-hooks 'whitespace-write-file-hook)
+    (remove-hook 'kill-buffer-hook 'whitespace-buffer)))
+
+;;;###autoload
+(defun whitespace-write-file-hook ()
+  "The local-write-file-hook to be called on the buffer when
+whitespace check is enabled."
+  (interactive)
+  (let ((werr nil))
+    (if whitespace-auto-cleanup
+       (whitespace-cleanup)
+      (setq werr (whitespace-buffer)))
+    (if (and whitespace-abort-on-error werr)
+       (error (concat "Abort write due to whitespaces in "
+                      buffer-file-name))))
+  nil)
 
 ;;;###autoload
 (defun whitespace-describe ()
@@ -582,13 +821,13 @@ of whitespace problems that commonly exist in source code.
 2. Trailing space (empty lines at the end of a file).
 3. Indentation space (8 or more spaces at beginning of line, that should be
                      replaced with TABS).
-4. Spaces followed by a TAB. (Almost always, we never want that).
+4. Spaces followed by a TAB.  (Almost always, we never want that).
 5. Spaces or TABS at the end of a line.
 
 Whitespace errors are reported in a buffer, and on the modeline.
 
-Modeline will show a W:<x> to denote a particular type of whitespace, where
-`x' can be one (or more) of:
+Modeline will show a W:<x>!<y> to denote a particular type of whitespace,
+where `x' and `y' can be one (or more) of:
 
 e - End-of-Line whitespace.
 i - Indentation whitespace.
@@ -597,22 +836,22 @@ s - Space followed by Tab.
 t - Trailing whitespace.
 
 If any of the whitespace checks is turned off, the modeline will display a
-Woff:<x>, where `x' can be one (or more) of the above.
+!<y>.
 
     (since (3) is the most controversial one, here is the rationale: Most
     terminal drivers and printer drivers have TAB configured or even
-    hardcoded to be 8 spaces. (Some of them allow configuration, but almost
+    hardcoded to be 8 spaces.  (Some of them allow configuration, but almost
     always they default to 8.)
 
-    Changing tab-width to other than 8 and editing will cause your code to
+    Changing `tab-width' to other than 8 and editing will cause your code to
     look different from within Emacs, and say, if you cat it or more it, or
     even print it.
 
     Almost all the popular programming modes let you define an offset (like
     c-basic-offset or perl-indent-level) to configure the offset, so you
-    should never have to set your tab-width to be other than 8 in all these
-    modes. In fact, with an indent level of say, 4, 2 TABS will cause Emacs
-    to replace your 8 spaces with one \t (try it). If vi users in your
+    should never have to set your `tab-width' to be other than 8 in all these
+    modes.  In fact, with an indent level of say, 4, 2 TABS will cause Emacs
+    to replace your 8 spaces with one \t (try it).  If vi users in your
     office complain, tell them to use vim, which distinguishes between
     tabstop and shiftwidth (vi equivalent of our offsets), and also ask them
     to set smarttab.)
@@ -621,12 +860,16 @@ All the above have caused (and will cause) unwanted codeline integration and
 merge problems.
 
 whitespace.el will complain if it detects whitespaces on opening a file, and
-warn you on closing a file also. (if in case you had inserted any
-whitespaces during the process of your editing.)"
+warn you on closing a file also (in case you had inserted any
+whitespaces during the process of your editing)."
   (interactive)
   (message "Use C-h f whitespace-describe to read about whitespace.el v%s."
           whitespace-version))
 
-(provide 'whitespace)
+(defun whitespace-unload-hook ()
+  (remove-hook 'find-file-hooks 'whitespace-buffer)
+  (remove-hook 'local-write-file-hooks 'whitespace-write-file-hook)
+  (remove-hook 'kill-buffer-hook 'whitespace-buffer))
 
+(provide 'whitespace)
 ;;; whitespace.el ends here