]> code.delx.au - gnu-emacs/blobdiff - lisp/whitespace.el
(Abbrevs): A @node line without explicit Prev, Next, and Up links.
[gnu-emacs] / lisp / whitespace.el
index b003798e65ae66f1a313af0d513acf4d7b1ccb73..7f3cbd913ca39c2144fa62186d35683182a383d8 100644 (file)
@@ -1,8 +1,9 @@
-;;; 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, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
-;; Author: Rajesh Vaidheeswarran <rv@dsmit.com>
+;; Author: Rajesh Vaidheeswarran <rv@gnu.org>
 ;; Keywords: convenience
 
 ;; This file is part of GNU Emacs.
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
-
-;; Whitespace.el URL: http://www.dsmit.com/lisp/
-
+;;
+;; URL: http://www.dsmit.com/lisp/
+;;
+;; The whitespace library is intended to find and help fix five different types
+;; of whitespace problems that commonly exist in source code.
+;;
+;; 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 at beginning of line, that should be
+;;                   replaced with TABS).
+;; 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>!<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.
+;; l - Leading whitespace.
+;; s - Space followed by Tab.
+;; t - Trailing whitespace.
+;;
+;; If any of the whitespace checks is turned off, the modeline will display a
+;; !<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
+;;     always they default to 8.)
+;;
+;;     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 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.)
+;;
+;; 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 (in case you had inserted any
+;; whitespaces during the process of your editing).
+;;
 ;; Exported functions:
-
+;;
 ;; `whitespace-buffer' - To check the current buffer for whitespace problems.
 ;; `whitespace-cleanup' - To cleanup all whitespaces in the current buffer.
 ;; `whitespace-region' - To check between point and mark for whitespace
 ;;                       problems.
 ;; `whitespace-cleanup-region' - To cleanup all whitespaces between point
 ;;                               and mark in the current buffer.
-;; `whitespace-describe' - A simple introduction to the library.
 
 ;;; 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.8" "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.5" "Version of the whitespace library.")
 
 (defvar whitespace-all-buffer-files nil
   "An associated list of buffers and files checked for whitespace cleanliness.
@@ -70,70 +109,138 @@ visited by the buffers.")
 (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 (not (fboundp 'defgroup))
       (defmacro defgroup (sym memb doc &rest args)
-       "Null macro for defgroup in all versions of Emacs that don't define
-defgroup"
+       "Null macro for `defgroup' in all versions of Emacs that don't define it."
        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"
+       "Macro to alias `defcustom' to `defvar' in all versions of Emacs that
+don't define it."
        `(defvar ,sym ,val ,doc))))
 
+(defalias 'whitespace-make-overlay
+  (if (featurep 'xemacs) 'make-extent 'make-overlay))
+(defalias 'whitespace-overlay-put
+  (if (featurep 'xemacs) 'set-extent-property 'overlay-put))
+(defalias 'whitespace-delete-overlay
+  (if (featurep 'xemacs) 'delete-extent 'delete-overlay))
+(defalias 'whitespace-overlay-start
+  (if (featurep 'xemacs) 'extent-start 'overlay-start))
+(defalias 'whitespace-overlay-end
+  (if (featurep 'xemacs) 'extent-end 'overlay-end))
+(defalias 'whitespace-mode-line-update
+  (if (featurep 'xemacs) 'redraw-modeline 'force-mode-line-update))
+
 (defgroup whitespace nil
   "Check for and fix five different types of whitespaces in source code."
+  :version "21.1"
+  :link '(emacs-commentary-link "whitespace.el")
   ;; Since XEmacs doesn't have a 'convenience group, use the next best group
   ;; which is 'editing?
-  :group (if whitespace-running-emacs 'convenience 'editing))
+  :group (if (featurep 'xemacs) 'editing '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-clean-msg "clean."
+  "If non-nil, this message will be displayed after a whitespace check
+determines a file to be clean."
   :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
@@ -163,9 +270,9 @@ Errors*' buffer before opening (or closing) another file."
                                       tcl-mode tex-mode texinfo-mode
                                       vrml-mode xml-mode)
 
-  "Major Modes in which we turn on whitespace checking.
+  "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':
 
@@ -173,9 +280,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
@@ -191,10 +299,48 @@ To disable timer scans, set this to zero."
   :type 'boolean
   :group 'whitespace)
 
+(defcustom whitespace-display-spaces-in-color t
+  "Display the bogus whitespaces by coloring them with the face
+`whitespace-highlight'."
+  :type 'boolean
+  :group 'whitespace)
+
+(defgroup whitespace-faces nil
+  "Faces used in whitespace."
+  :prefix "whitespace-"
+  :group 'whitespace
+  :group 'faces)
+
+(defface whitespace-highlight '((((class color) (background light))
+                                (:background "green1"))
+                               (((class color) (background dark))
+                                (:background "sea green"))
+                               (((class grayscale mono)
+                                 (background light))
+                                (:background "black"))
+                               (((class grayscale mono)
+                                 (background dark))
+                                (:background "white")))
+  "Face used for highlighting the bogus whitespaces that exist in the buffer."
+  :group 'whitespace-faces)
+;; backward-compatibility alias
+(put 'whitespace-highlight-face 'face-alias 'whitespace-highlight)
+
 (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)
@@ -204,9 +350,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\).
@@ -224,26 +425,27 @@ and:
        (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-leading-whitespace
+           (let ((whitespace-leading (if whitespace-check-buffer-leading
                                          (whitespace-buffer-leading)
                                        nil))
-                 (whitespace-trailing (if whitespace-check-trailing-whitespace
+                 (whitespace-trailing (if whitespace-check-buffer-trailing
                                           (whitespace-buffer-trailing)
                                         nil))
-                 (whitespace-indent (if whitespace-check-indent-whitespace
+                 (whitespace-indent (if whitespace-check-buffer-indent
                                         (whitespace-buffer-search
                                          whitespace-indent-regexp)
                                       nil))
-                 (whitespace-spacetab (if whitespace-check-spacetab-whitespace
+                 (whitespace-spacetab (if whitespace-check-buffer-spacetab
                                           (whitespace-buffer-search
                                            whitespace-spacetab-regexp)
                                         nil))
-                 (whitespace-ateol (if whitespace-check-ateol-whitespace
+                 (whitespace-ateol (if whitespace-check-buffer-ateol
                                        (whitespace-buffer-search
                                         whitespace-ateol-regexp)
                                      nil))
@@ -282,16 +484,14 @@ and:
                                  (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 (get-buffer whitespace-errbuf)
+                 (kill-buffer whitespace-errbuf))
+             (with-current-buffer (get-buffer-create whitespace-errbuf)
                (if whitespace-errmsg
                    (progn
                      (insert whitespace-errmsg)
                      (if (not (or quiet whitespace-silent))
-                         (display-buffer whitespace-errbuf t))
+                         (display-buffer (current-buffer) t))
                      (if (not quiet)
                          (message "Whitespaces: [%s%s] in %s"
                                   whitespace-this-modeline
@@ -301,15 +501,14 @@ and:
                                         (concat "!" whitespace-unchecked)
                                       ""))
                                   whitespace-filename)))
-                 (if (not quiet)
-                     (message "%s clean" whitespace-filename))))))))
-    (if whitespace-error
-       t
-      nil)))
+                 (if (and (not quiet) (not (equal whitespace-clean-msg "")))
+                     (message "%s %s" whitespace-filename
+                              whitespace-clean-msg))))))))
+    whitespace-error))
 
 ;;;###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
@@ -319,9 +518,7 @@ and:
 ;;;###autoload
 (defun whitespace-cleanup ()
   "Cleanup the five different kinds of whitespace problems.
-
-Use \\[describe-function] whitespace-describe to read a summary of the
-whitespace problems."
+See `whitespace-buffer' docstring for a summary of the problems."
   (interactive)
   ;; If this buffer really contains a file, then run, else quit.
   (whitespace-check-whitespace-mode current-prefix-arg)
@@ -334,31 +531,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 "")
@@ -368,13 +565,14 @@ whitespace problems."
        (if whitespace-any
            (whitespace-cleanup)
          (progn
-           (message "%s clean" buffer-file-name)
+           (if (not whitespace-silent)
+               (message "%s clean" buffer-file-name))
            (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
@@ -393,23 +591,17 @@ whitespace problems."
       (end-of-line)
       (setq pmax (point))
       (if (equal pmin pmax)
-         t
+         (progn
+           (whitespace-highlight-the-space pmin (1+ pmax))
+           t)
        nil))))
 
 (defun whitespace-buffer-leading-cleanup ()
   "Remove any empty lines at the top of the file."
   (save-excursion
-    (let ((pmin nil)
-         (pmax nil))
-      (goto-char (point-min))
-      (beginning-of-line)
-      (setq pmin (point))
-      (end-of-line)
-      (setq pmax (point))
-      (if (equal pmin pmax)
-         (progn
-           (kill-line)
-           (whitespace-buffer-leading-cleanup))))))
+    (goto-char (point-min))
+    (skip-chars-forward "\n")
+    (delete-region (point-min) (point))))
 
 (defun whitespace-buffer-trailing ()
   "Check to see if are is more than one empty line at the bottom."
@@ -429,33 +621,20 @@ whitespace problems."
            (end-of-line)
            (setq pmax (point))
            (if (equal pmin pmax)
-               t
+               (progn
+                 (whitespace-highlight-the-space (- pmin 1) pmax)
+                 t)
              nil))
        nil))))
 
 (defun whitespace-buffer-trailing-cleanup ()
   "Delete all the empty lines at the bottom."
   (save-excursion
-    (let ((pmin nil)
-         (pmax nil))
-      (goto-char (point-max))
-      (beginning-of-line)
-      (setq pmin (point))
-      (end-of-line)
-      (setq pmax (point))
-      (if (equal pmin pmax)
-         (progn
-           (goto-char (1- pmin))
-           (beginning-of-line)
-           (setq pmin (point))
-           (end-of-line)
-           (setq pmax (point))
-           (if (equal pmin pmax)
-               (progn
-                 (goto-char (1- (point-max)))
-                 (beginning-of-line)
-                 (kill-line)
-                 (whitespace-buffer-trailing-cleanup))))))))
+    (goto-char (point-max))
+    (skip-chars-backward "\n")
+    (if (not (bolp))
+       (forward-char 1))
+    (delete-region (point) (point-max))))
 
 (defun whitespace-buffer-search (regexp)
   "Search for any given whitespace REGEXP."
@@ -463,8 +642,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))))
@@ -488,41 +669,51 @@ whitespace problems."
 
 (defun whitespace-unchecked-whitespaces ()
   "Return the list of whitespaces whose testing has been suppressed."
-  (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"))))
-    (if (not (equal whitespace-this-modeline ""))
-       whitespace-this-modeline
+  (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 and whitespaces whose testing has
-been turned off."
+  "Update modeline with whitespace errors.
+Also with whitespaces whose testing has been turned off."
   (if whitespace-display-in-modeline
-      (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-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
+      (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
+      (let ((ol (whitespace-make-overlay b e)))
+       (push ol whitespace-highlighted-space)
+       (whitespace-overlay-put ol 'face 'whitespace-highlight))))
+;;  (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)
+      (progn
+       (mapc 'whitespace-delete-overlay whitespace-highlighted-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.
@@ -541,12 +732,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."
@@ -554,9 +742,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))
@@ -586,73 +772,55 @@ 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
-      (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)))))
+      (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
-(defun whitespace-describe ()
-  "A summary of whitespaces and what this library can do about them.
-
-The whitespace library is intended to find and help fix five different types
-of whitespace problems that commonly exist in source code.
+(defalias 'global-whitespace-mode 'whitespace-global-mode)
 
-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 at beginning of line, that should be
-                     replaced with TABS).
-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>!<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.
-l - Leading whitespace.
-s - Space followed by Tab.
-t - Trailing whitespace.
-
-If any of the whitespace checks is turned off, the modeline will display a
-!<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
-    always they default to 8.)
-
-    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
-    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.)
-
-All the above have caused (and will cause) unwanted codeline integration and
-merge problems.
+;;;###autoload
+(define-minor-mode whitespace-global-mode
+  "Toggle using Whitespace mode in new buffers.
+With ARG, turn the mode on iff ARG is positive.
+
+When this mode is active, `whitespace-buffer' is added to
+`find-file-hook' and `kill-buffer-hook'."
+  :global t
+  :group 'whitespace
+  (if whitespace-global-mode
+      (progn
+       (add-hook 'find-file-hook 'whitespace-buffer)
+       (add-hook 'write-file-functions 'whitespace-write-file-hook nil t)
+       (add-hook 'kill-buffer-hook 'whitespace-buffer))
+    (remove-hook 'find-file-hook 'whitespace-buffer)
+    (remove-hook 'write-file-functions 'whitespace-write-file-hook t)
+    (remove-hook 'kill-buffer-hook 'whitespace-buffer)))
 
-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.)"
+;;;###autoload
+(defun whitespace-write-file-hook ()
+  "Hook function to be called on the buffer when whitespace check is enabled.
+This is meant to be added buffer-locally to `write-file-functions'."
   (interactive)
-  (message "Use C-h f whitespace-describe to read about whitespace.el v%s."
-          whitespace-version))
+  (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)
+
+(defun whitespace-unload-hook ()
+  (remove-hook 'find-file-hook 'whitespace-buffer)
+  (remove-hook 'write-file-functions 'whitespace-write-file-hook t)
+  (remove-hook 'kill-buffer-hook 'whitespace-buffer))
+
+(add-hook 'whitespace-unload-hook 'whitespace-unload-hook)
 
 (provide 'whitespace)
 
+;; arch-tag: 4ff44e87-b63c-402d-95a6-15e51e58bd0c
 ;;; whitespace.el ends here