Sync to HEAD
[bpt/emacs.git] / lisp / whitespace.el
index 6f99f07..e330feb 100644 (file)
@@ -5,7 +5,6 @@
 ;; Author: Rajesh Vaidheeswarran <rv@gnu.org>
 ;; Keywords: convenience
 
-;; $Id: whitespace.el,v 1.17 2001/08/20 10:05:03 gerd Exp $
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; Boston, MA 02111-1307, 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:
 
-(defvar whitespace-version "3.1" "Version of the whitespace library.")
+(defvar whitespace-version "3.4" "Version of the whitespace library.")
 
 (defvar whitespace-all-buffer-files nil
   "An associated list of buffers and files checked for whitespace cleanliness.
@@ -86,6 +133,11 @@ visited by the buffers.")
 (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))
@@ -99,15 +151,32 @@ defgroup"
 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?
+  :link '(emacs-commentary-link "whitespace.el")
   :group 'editing)
 (defgroup whitespace nil
   "Check for and fix five different types of whitespaces in source code."
   :version "21.1"
+  :link '(emacs-commentary-link "whitespace.el")
   :group 'convenience))
 
 (defcustom whitespace-check-leading-whitespace t
@@ -131,7 +200,7 @@ It can be overriden by setting a buffer local variable
   :type 'boolean
   :group 'whitespace)
 
-(defcustom whitespace-spacetab-regexp " \t"
+(defcustom whitespace-spacetab-regexp "[ ]+\t"
   "Regexp to match a space followed by a TAB."
   :type 'regexp
   :group 'whitespace)
@@ -155,7 +224,8 @@ It can be overriden by setting a buffer local variable
   :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 'regexp
   :group 'whitespace)
@@ -165,6 +235,12 @@ It can be overriden by setting a buffer local variable
   :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
@@ -230,6 +306,31 @@ 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
+`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 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)
+
 (if (not (assoc 'whitespace-mode minor-mode-alist))
     (setq minor-mode-alist (cons '(whitespace-mode whitespace-mode-line)
                                 minor-mode-alist)))
@@ -329,6 +430,7 @@ 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)
@@ -406,8 +508,9 @@ and:
                                         (concat "!" whitespace-unchecked)
                                       ""))
                                   whitespace-filename)))
-                 (if (not quiet)
-                     (message "%s clean" whitespace-filename))))))))
+                 (if (and (not quiet) (not (equal whitespace-clean-msg "")))
+                     (message "%s %s" whitespace-filename
+                              whitespace-clean-msg))))))))
     (if whitespace-error
        t
       nil)))
@@ -473,7 +576,8 @@ 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))))
 
@@ -498,7 +602,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 ()
@@ -534,7 +640,9 @@ whitespace problems."
            (end-of-line)
            (setq pmax (point))
            (if (equal pmin pmax)
-               t
+               (progn
+                 (whitespace-highlight-the-space pmin pmax)
+                 t)
              nil))
        nil))))
 
@@ -568,8 +676,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))))
@@ -621,14 +731,30 @@ Also with whitespaces whose testing has been turned off."
        (setq whitespace-mode-line (if whitespace-mode-line
                                       (concat " W:" whitespace-mode-line)
                                     nil))
-       (whitespace-force-mode-line-update))))
+       (whitespace-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 (fboundp 'redraw-modeline)
-      (redraw-modeline)                        ; XEmacs
-    (force-mode-line-update)))         ; Emacs
+(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.
@@ -694,43 +820,27 @@ If timer is not set, then set it to scan the files in
       (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)
+(define-minor-mode whitespace-global-mode
   "Toggle using Whitespace mode in new buffers.
-With ARG, turn the mode on if and only iff ARG is positive.
+With ARG, turn the mode on 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
+`find-file-hook' and `kill-buffer-hook'."
+  :global t
+  :group 'whitespace
+  (if whitespace-global-mode
       (progn
-       (add-hook 'find-file-hooks 'whitespace-buffer)
-       (add-hook 'local-write-file-hooks 'whitespace-write-file-hook)
+       (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-hooks 'whitespace-buffer)
-    (remove-hook 'local-write-file-hooks 'whitespace-write-file-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)))
 
 ;;;###autoload
 (defun whitespace-write-file-hook ()
-  "The local-write-file-hook to be called on the buffer when
-whitespace check is enabled."
+  "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)
   (let ((werr nil))
     (if whitespace-auto-cleanup
@@ -741,67 +851,12 @@ whitespace check is enabled."
                       buffer-file-name))))
   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.
-
-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)."
-  (interactive)
-  (message "Use C-h f whitespace-describe to read about whitespace.el v%s."
-          whitespace-version))
-
 (defun whitespace-unload-hook ()
-  (remove-hook 'find-file-hooks 'whitespace-buffer)
-  (remove-hook 'local-write-file-hooks 'whitespace-write-file-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))
 
 (provide 'whitespace)
 
+;;; arch-tag: 4ff44e87-b63c-402d-95a6-15e51e58bd0c
 ;;; whitespace.el ends here