Add 2010 to copyright years.
[bpt/emacs.git] / lisp / whitespace.el
index b78106f..fbdc6d1 100644 (file)
@@ -1,30 +1,28 @@
 ;;; whitespace.el --- minor mode to visualize TAB, (HARD) SPACE, NEWLINE
 
-;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
 ;;   Free Software Foundation, Inc.
 
 ;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
 ;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
 ;; Keywords: data, wp
-;; Version: 9.2
+;; Version: 12.1
 ;; X-URL: http://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published
-;; by the Free Software Foundation; either version 3, or (at your
-;; option) any later version.
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
-;; GNU Emacs is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;; General Public License for more details.
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
 
 ;; 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., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -46,8 +44,8 @@
 ;;   it provides a visual mark for characters, for example, at the end
 ;;   of line (?\xB6), at SPACEs (?\xB7) and at TABs (?\xBB).
 ;;
-;; The `whitespace-style' and `whitespace-chars' variables are used to
-;; select which way should be used to visualize blanks.
+;; The `whitespace-style' variable selects which way blanks are
+;; visualized.
 ;;
 ;; Note that when whitespace is turned on, whitespace saves the
 ;; font-lock state, that is, if font-lock is on or off.  And
 ;; characters over the default mechanism of `nobreak-char-display'
 ;; (which see) and `show-trailing-whitespace' (which see).
 ;;
+;; The trailing spaces are not highlighted while point is at end of line.
+;; Also the spaces at beginning of buffer are not highlighted while point is at
+;; beginning of buffer; and the spaces at end of buffer are not highlighted
+;; while point is at end of buffer.
+;;
 ;; There are two ways of using whitespace: local and global.
 ;;
 ;; * Local whitespace affects only the current buffer.
@@ -87,7 +90,7 @@
 ;;
 ;; To use whitespace, insert in your ~/.emacs:
 ;;
-;;    (require 'whitespace-mode)
+;;    (require 'whitespace)
 ;;
 ;; Or autoload at least one of the commands`whitespace-mode',
 ;; `whitespace-toggle-options', `global-whitespace-mode' or
 ;;
 ;; There are also the following useful commands:
 ;;
+;; `whitespace-newline-mode'
+;;    Toggle NEWLINE minor mode visualization ("nl" on modeline).
+;;
+;; `global-whitespace-newline-mode'
+;;    Toggle NEWLINE global minor mode visualization ("NL" on modeline).
+;;
+;; `whitespace-report'
+;;    Report some blank problems in buffer.
+;;
+;; `whitespace-report-region'
+;;    Report some blank problems in a region.
+;;
 ;; `whitespace-cleanup'
 ;;    Cleanup some blank problems in all buffer or at region.
 ;;
 ;; `whitespace-cleanup-region'
 ;;    Cleanup some blank problems at region.
 ;;
-;; `whitespace-buffer'
-;;    Turn on `whitespace-mode' forcing some settings.
-;;
 ;; The problems, which are cleaned up, are:
 ;;
 ;; 1. empty lines at beginning of buffer.
 ;; 2. empty lines at end of buffer.
-;;    If `whitespace-chars' has `empty' as an element, remove all
+;;    If `whitespace-style' includes the value `empty', remove all
 ;;    empty lines at beginning and/or end of buffer.
 ;;
 ;; 3. 8 or more SPACEs at beginning of line.
-;;    If `whitespace-chars' has `indentation' as an element, replace 8
-;;    or more SPACEs at beginning of line by TABs.
+;;    If `whitespace-style' includes the value `indentation':
+;;    replace 8 or more SPACEs at beginning of line by TABs, if
+;;    `indent-tabs-mode' is non-nil; otherwise, replace TABs by
+;;    SPACEs.
+;;    If `whitespace-style' includes the value `indentation::tab',
+;;    replace 8 or more SPACEs at beginning of line by TABs.
+;;    If `whitespace-style' includes the value `indentation::space',
+;;    replace TABs by SPACEs.
 ;;
 ;; 4. SPACEs before TAB.
-;;    If `whitespace-chars' has `space-before-tab' as an element,
-;;    replace SPACEs by TABs.
+;;    If `whitespace-style' includes the value `space-before-tab':
+;;    replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
+;;    otherwise, replace TABs by SPACEs.
+;;    If `whitespace-style' includes the value
+;;    `space-before-tab::tab', replace SPACEs by TABs.
+;;    If `whitespace-style' includes the value
+;;    `space-before-tab::space', replace TABs by SPACEs.
 ;;
 ;; 5. SPACEs or TABs at end of line.
-;;    If `whitespace-chars' has `trailing' as an element, remove all
-;;    SPACEs or TABs at end of line."
+;;    If `whitespace-style' includes the value `trailing', remove all
+;;    SPACEs or TABs at end of line.
 ;;
 ;; 6. 8 or more SPACEs after TAB.
-;;    If `whitespace-chars' has `space-after-tab' as an element,
+;;    If `whitespace-style' includes the value `space-after-tab':
+;;    replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
+;;    otherwise, replace TABs by SPACEs.
+;;    If `whitespace-style' includes the value `space-after-tab::tab',
 ;;    replace SPACEs by TABs.
+;;    If `whitespace-style' includes the value
+;;    `space-after-tab::space', replace TABs by SPACEs.
 ;;
 ;;
 ;; Hooks
 ;; Below it's shown a brief description of whitespace options, please,
 ;; see the options declaration in the code for a long documentation.
 ;;
-;; `whitespace-style'          Specify the visualization style.
-;;
-;; `whitespace-chars'          Specify which kind of blank is
+;; `whitespace-style'          Specify which kind of blank is
 ;;                             visualized.
 ;;
 ;; `whitespace-space'          Face used to visualize SPACE.
 ;; `whitespace-display-mappings'       Specify an alist of mappings
 ;;                                     for displaying characters.
 ;;
-;; `whitespace-global-modes'   Modes for which global `whitespace-mode' is
-;;                             automagically turned on.
+;; `whitespace-global-modes'   Modes for which global
+;;                             `whitespace-mode' is automagically
+;;                             turned on.
+;;
+;; `whitespace-action'         Specify which action is taken when a
+;;                             buffer is visited or written.
 ;;
 ;;
 ;; Acknowledgements
 ;; ----------------
 ;;
+;; Thanks to David Reitter <david.reitter@gmail.com> for suggesting a
+;; `whitespace-newline' initialization with low contrast relative to
+;; the background color.
+;;
+;; Thanks to Stephen Deasey <sdeasey@gmail.com> for the
+;; `indent-tabs-mode' usage suggestion.
+;;
+;; Thanks to Eric Cooper <ecc@cmu.edu> for the suggestion to have hook
+;; actions when buffer is written as the original whitespace package
+;; had.
+;;
 ;; Thanks to nschum (EmacsWiki) for the idea about highlight "long"
 ;; lines tail.  See EightyColumnRule (EmacsWiki).
 ;;
 ;; "long" lines.  See EightyColumnRule (EmacsWiki).
 ;;
 ;; Thanks to Yanghui Bian <yanghuibian@gmail.com> for indicating a new
-;; newline character mapping.
+;; NEWLINE character mapping.
 ;;
 ;; Thanks to Pete Forman <pete.forman@westgeo.com> for indicating
 ;; whitespace-mode.el on XEmacs.
 (defgroup whitespace nil
   "Visualize blanks (TAB, (HARD) SPACE and NEWLINE)."
   :link '(emacs-library-link :tag "Source Lisp File" "whitespace.el")
-  :version "22.2"
+  :version "23.1"
   :group 'wp
   :group 'data)
 
 
-(defcustom whitespace-style '(mark color)
-  "*Specify the visualization style.
-
-It's a list which element value can be:
-
-   mark                display mappings are visualized.
-
-   color       faces are visualized.
-
-Any other value is ignored.
-
-If nil, don't visualize TABs, (HARD) SPACEs and NEWLINEs.
-
-See also `whitespace-display-mappings' for documentation."
-  :type '(repeat :tag "Style of Blank"
-                (choice :tag "Style of Blank"
-                        (const :tag "Display Table" mark)
-                        (const :tag "Faces" color)))
-  :group 'whitespace)
-
-
-(defcustom whitespace-chars
+(defcustom whitespace-style
   '(tabs spaces trailing lines space-before-tab newline
-        indentation empty space-after-tab)
-  "*Specify which kind of blank is visualized.
+        indentation empty space-after-tab
+        space-mark tab-mark newline-mark)
+  "Specify which kind of blank is visualized.
 
-It's a list which element value can be:
+It's a list containing some or all of the following values:
 
-   trailing            trailing blanks are visualized.
+   trailing            trailing blanks are visualized via faces.
 
-   tabs                        TABs are visualized.
+   tabs                        TABs are visualized via faces.
 
-   spaces              SPACEs and HARD SPACEs are visualized.
+   spaces              SPACEs and HARD SPACEs are visualized via
+                       faces.
 
    lines               lines whose have columns beyond
-                       `whitespace-line-column' are highlighted.
+                       `whitespace-line-column' are highlighted via
+                       faces .
                        Whole line is highlighted.
-                       It has precedence over
-                       `lines-tail' (see below).
+                       It has precedence over `lines-tail' (see
+                       below).
 
    lines-tail          lines whose have columns beyond
-                       `whitespace-line-column' are highlighted.
+                       `whitespace-line-column' are highlighted via
+                       faces.
                        But only the part of line which goes
                        beyond `whitespace-line-column' column.
                        It has effect only if `lines' (see above)
-                       is not present in `whitespace-chars'.
+                       is not present in `whitespace-style'.
+
+   newline             NEWLINEs are visualized via faces.
+
+   empty               empty lines at beginning and/or end of buffer
+                       are visualized via faces.
 
-   space-before-tab    SPACEs before TAB are visualized.
+   indentation::tab    8 or more SPACEs at beginning of line are
+                       visualized via faces.
 
-   newline             NEWLINEs are visualized.
+   indentation::space  TABs at beginning of line are visualized via
+                       faces.
 
    indentation         8 or more SPACEs at beginning of line are
-                       visualized.
+                       visualized, if `indent-tabs-mode' (which see)
+                       is non-nil; otherwise, TABs at beginning of
+                       line are visualized via faces.
 
-   empty               empty lines at beginning and/or end of buffer
-                       are visualized.
+   space-after-tab::tab                8 or more SPACEs after a TAB are
+                               visualized via faces.
+
+   space-after-tab::space      TABs are visualized when 8 or more
+                               SPACEs occur after a TAB, via faces.
+
+   space-after-tab             8 or more SPACEs after a TAB are
+                               visualized, if `indent-tabs-mode'
+                               (which see) is non-nil; otherwise,
+                               the TABs are visualized via faces.
 
-   space-after-tab     8 or more SPACEs after a TAB are visualized.
+   space-before-tab::tab       SPACEs before TAB are visualized via
+                               faces.
+
+   space-before-tab::space     TABs are visualized when SPACEs occur
+                               before TAB, via faces.
+
+   space-before-tab            SPACEs before TAB are visualized, if
+                               `indent-tabs-mode' (which see) is
+                               non-nil; otherwise, the TABs are
+                               visualized via faces.
+
+   space-mark          SPACEs and HARD SPACEs are visualized via
+                       display table.
+
+   tab-mark            TABs are visualized via display table.
+
+   newline-mark                NEWLINEs are visualized via display table.
 
 Any other value is ignored.
 
-If nil, don't visualize TABs, (HARD) SPACEs and NEWLINEs.
+If nil, don't visualize TABs, (HARD) SPACEs and NEWLINEs via faces and
+via display table.
+
+There is an evaluation order for some values, if some values are
+included in `whitespace-style' list.  For example, if
+indentation, indentation::tab and/or indentation::space are
+included in `whitespace-style' list.  The evaluation order for
+these values is:
+
+ * For indentation:
+   1. indentation
+   2. indentation::tab
+   3. indentation::space
+
+ * For SPACEs after TABs:
+   1. space-after-tab
+   2. space-after-tab::tab
+   3. space-after-tab::space
 
-Used when `whitespace-style' has `color' as an element.
-Used also when `whitespace-chars' has `newline' as an element and
-`whitespace-style' has `mark' as an element."
+ * For SPACEs before TABs:
+   1. space-before-tab
+   2. space-before-tab::tab
+   3. space-before-tab::space
+
+So, for example, if indentation and indentation::space are
+included in `whitespace-style' list, the indentation value is
+evaluated instead of indentation::space value.
+
+See also `whitespace-display-mappings' for documentation."
   :type '(repeat :tag "Kind of Blank"
-                (choice :tag "Kind of Blank"
-                        (const :tag "Trailing TABs, SPACEs and HARD SPACEs"
+                (choice :tag "Kind of Blank Face"
+                        (const :tag "(Face) Trailing TABs, SPACEs and HARD SPACEs"
                                trailing)
-                        (const :tag "SPACEs and HARD SPACEs" spaces)
-                        (const :tag "TABs" tabs)
-                        (const :tag "Lines" lines)
-                        (const :tag "SPACEs before TAB"
+                        (const :tag "(Face) SPACEs and HARD SPACEs"
+                               spaces)
+                        (const :tag "(Face) TABs" tabs)
+                        (const :tag "(Face) Lines" lines)
+                        (const :tag "(Face) SPACEs before TAB"
                                space-before-tab)
-                        (const :tag "NEWLINEs" newline)
-                        (const :tag "Indentation SPACEs" indentation)
-                        (const :tag "Empty Lines At BOB And/Or EOB"
+                        (const :tag "(Face) NEWLINEs" newline)
+                        (const :tag "(Face) Indentation SPACEs"
+                               indentation)
+                        (const :tag "(Face) Empty Lines At BOB And/Or EOB"
                                empty)
-                        (const :tag "SPACEs after TAB"
-                               space-after-tab)))
+                        (const :tag "(Face) SPACEs after TAB"
+                               space-after-tab)
+                        (const :tag "(Mark) SPACEs and HARD SPACEs"
+                               space-mark)
+                        (const :tag "(Mark) TABs" tab-mark)
+                        (const :tag "(Mark) NEWLINEs" newline-mark)))
   :group 'whitespace)
 
 
 (defcustom whitespace-space 'whitespace-space
-  "*Symbol face used to visualize SPACE.
+  "Symbol face used to visualize SPACE.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `spaces'."
   :type 'face
   :group 'whitespace)
 
@@ -444,9 +531,9 @@ Used when `whitespace-style' has `color' as an element."
 
 
 (defcustom whitespace-hspace 'whitespace-hspace
-  "*Symbol face used to visualize HARD SPACE.
+  "Symbol face used to visualize HARD SPACE.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `spaces'."
   :type 'face
   :group 'whitespace)
 
@@ -462,9 +549,9 @@ Used when `whitespace-style' has `color' as an element."
 
 
 (defcustom whitespace-tab 'whitespace-tab
-  "*Symbol face used to visualize TAB.
+  "Symbol face used to visualize TAB.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `tabs'."
   :type 'face
   :group 'whitespace)
 
@@ -480,22 +567,22 @@ Used when `whitespace-style' has `color' as an element."
 
 
 (defcustom whitespace-newline 'whitespace-newline
-  "*Symbol face used to visualize NEWLINE char mapping.
+  "Symbol face used to visualize NEWLINE char mapping.
 
 See `whitespace-display-mappings'.
 
-Used when `whitespace-style' has `mark' and `color' as elements
-and `whitespace-chars' has `newline' as an element."
+Used when `whitespace-style' includes the values `newline-mark'
+and `newline'."
   :type 'face
   :group 'whitespace)
 
 
 (defface whitespace-newline
   '((((class color) (background dark))
-     (:background "grey26" :foreground "aquamarine3" :bold t))
+     (:foreground "darkgray" :bold nil))
     (((class color) (background light))
-     (:background "linen"  :foreground "aquamarine3" :bold t))
-    (t (:bold t :underline t)))
+     (:foreground "lightgray" :bold nil))
+    (t (:underline t :bold nil)))
   "Face used to visualize NEWLINE char mapping.
 
 See `whitespace-display-mappings'."
@@ -503,9 +590,9 @@ See `whitespace-display-mappings'."
 
 
 (defcustom whitespace-trailing 'whitespace-trailing
-  "*Symbol face used to visualize traling blanks.
+  "Symbol face used to visualize trailing blanks.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `trailing'."
   :type 'face
   :group 'whitespace)
 
@@ -518,11 +605,11 @@ Used when `whitespace-style' has `color' as an element."
 
 
 (defcustom whitespace-line 'whitespace-line
-  "*Symbol face used to visualize \"long\" lines.
+  "Symbol face used to visualize \"long\" lines.
 
 See `whitespace-line-column'.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `line'."
   :type 'face
   :group 'whitespace)
 
@@ -537,9 +624,9 @@ See `whitespace-line-column'."
 
 
 (defcustom whitespace-space-before-tab 'whitespace-space-before-tab
-  "*Symbol face used to visualize SPACEs before TAB.
+  "Symbol face used to visualize SPACEs before TAB.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `space-before-tab'."
   :type 'face
   :group 'whitespace)
 
@@ -552,9 +639,9 @@ Used when `whitespace-style' has `color' as an element."
 
 
 (defcustom whitespace-indentation 'whitespace-indentation
-  "*Symbol face used to visualize 8 or more SPACEs at beginning of line.
+  "Symbol face used to visualize 8 or more SPACEs at beginning of line.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `indentation'."
   :type 'face
   :group 'whitespace)
 
@@ -567,9 +654,9 @@ Used when `whitespace-style' has `color' as an element."
 
 
 (defcustom whitespace-empty 'whitespace-empty
-  "*Symbol face used to visualize empty lines at beginning and/or end of buffer.
+  "Symbol face used to visualize empty lines at beginning and/or end of buffer.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `empty'."
   :type 'face
   :group 'whitespace)
 
@@ -582,9 +669,9 @@ Used when `whitespace-style' has `color' as an element."
 
 
 (defcustom whitespace-space-after-tab 'whitespace-space-after-tab
-  "*Symbol face used to visualize 8 or more SPACEs after TAB.
+  "Symbol face used to visualize 8 or more SPACEs after TAB.
 
-Used when `whitespace-style' has `color' as an element."
+Used when `whitespace-style' includes the value `space-after-tab'."
   :type 'face
   :group 'whitespace)
 
@@ -598,9 +685,9 @@ Used when `whitespace-style' has `color' as an element."
 
 (defcustom whitespace-hspace-regexp
   "\\(\\(\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)"
-  "*Specify HARD SPACE characters regexp.
+  "Specify HARD SPACE characters regexp.
 
-If you're using `mule' package, it may exist other characters besides:
+If you're using `mule' package, there may be other characters besides:
 
    \"\\xA0\"   \"\\x8A0\"   \"\\x920\"   \"\\xE20\"   \"\\xF20\"
 
@@ -620,16 +707,15 @@ visualize only HARD SPACEs between TABs.
 NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
       Use exactly one pair of enclosing \\\\( and \\\\).
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `spaces' as an element."
+Used when `whitespace-style' includes `spaces'."
   :type '(regexp :tag "HARD SPACE Chars")
   :group 'whitespace)
 
 
 (defcustom whitespace-space-regexp "\\( +\\)"
-  "*Specify SPACE characters regexp.
+  "Specify SPACE characters regexp.
 
-If you're using `mule' package, it may exist other characters
+If you're using `mule' package, there may be other characters
 besides \" \" that should be considered SPACE.
 
 Here are some examples:
@@ -643,16 +729,15 @@ visualize leading and/or trailing SPACEs.
 NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
       Use exactly one pair of enclosing \\\\( and \\\\).
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `spaces' as an element."
+Used when `whitespace-style' includes `spaces'."
   :type '(regexp :tag "SPACE Chars")
   :group 'whitespace)
 
 
 (defcustom whitespace-tab-regexp "\\(\t+\\)"
-  "*Specify TAB characters regexp.
+  "Specify TAB characters regexp.
 
-If you're using `mule' package, it may exist other characters
+If you're using `mule' package, there may be other characters
 besides \"\\t\" that should be considered TAB.
 
 Here are some examples:
@@ -666,158 +751,168 @@ visualize leading and/or trailing TABs.
 NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
       Use exactly one pair of enclosing \\\\( and \\\\).
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `tabs' as an element."
+Used when `whitespace-style' includes `tabs'."
   :type '(regexp :tag "TAB Chars")
   :group 'whitespace)
 
 
 (defcustom whitespace-trailing-regexp
-  "\t\\| \\|\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20"
-  "*Specify trailing characters regexp.
+  "\\(\\(\t\\| \\|\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)$"
+  "Specify trailing characters regexp.
 
-If you're using `mule' package, it may exist other characters besides:
+If you're using `mule' package, there may be other characters besides:
 
    \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
 \"\\xF20\"
 
 that should be considered blank.
 
-NOTE: DO NOT enclose by \\\\( and \\\\) the elements to highlight.
-      `whitespace-mode' surrounds this regexp by \"\\\\(\\\\(\" and
-      \"\\\\)+\\\\)$\".
+NOTE: Enclose always by \"\\\\(\" and \"\\\\)$\" the elements to highlight.
+      Use exactly one pair of enclosing elements above.
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `trailing' as an element."
+Used when `whitespace-style' includes `trailing'."
   :type '(regexp :tag "Trailing Chars")
   :group 'whitespace)
 
 
-(defcustom whitespace-space-before-tab-regexp "\\( +\\)\t"
-  "*Specify SPACEs before TAB regexp.
+(defcustom whitespace-space-before-tab-regexp "\\( +\\)\\(\t+\\)"
+  "Specify SPACEs before TAB regexp.
 
-If you're using `mule' package, it may exist other characters besides:
+If you're using `mule' package, there may be other characters besides:
 
    \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
 \"\\xF20\"
 
 that should be considered blank.
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `space-before-tab' as an element."
+Used when `whitespace-style' includes `space-before-tab',
+`space-before-tab::tab' or  `space-before-tab::space'."
   :type '(regexp :tag "SPACEs Before TAB")
   :group 'whitespace)
 
 
 (defcustom whitespace-indentation-regexp
-  "^\t*\\(\\( \\{8\\}\\)+\\)[^\n\t]"
-  "*Specify regexp for 8 or more SPACEs at beginning of line.
+  '("^\t*\\(\\( \\{%d\\}\\)+\\)[^\n\t]"
+    . "^ *\\(\t+\\)[^\n]")
+  "Specify regexp for 8 or more SPACEs at beginning of line.
+
+It is a cons where the cons car is used for SPACEs visualization
+and the cons cdr is used for TABs visualization.
 
-If you're using `mule' package, it may exist other characters besides:
+If you're using `mule' package, there may be other characters besides:
 
    \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
 \"\\xF20\"
 
 that should be considered blank.
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `indentation' as an element."
-  :type '(regexp :tag "Indentation SPACEs")
+Used when `whitespace-style' includes `indentation',
+`indentation::tab' or  `indentation::space'."
+  :type '(cons (regexp :tag "Indentation SPACEs")
+              (regexp :tag "Indentation TABs"))
   :group 'whitespace)
 
 
 (defcustom whitespace-empty-at-bob-regexp "\\`\\(\\([ \t]*\n\\)+\\)"
-  "*Specify regexp for empty lines at beginning of buffer.
+  "Specify regexp for empty lines at beginning of buffer.
 
-If you're using `mule' package, it may exist other characters besides:
+If you're using `mule' package, there may be other characters besides:
 
    \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
 \"\\xF20\"
 
 that should be considered blank.
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `empty' as an element."
+Used when `whitespace-style' includes `empty'."
   :type '(regexp :tag "Empty Lines At Beginning Of Buffer")
   :group 'whitespace)
 
 
 (defcustom whitespace-empty-at-eob-regexp "^\\([ \t\n]+\\)\\'"
-  "*Specify regexp for empty lines at end of buffer.
+  "Specify regexp for empty lines at end of buffer.
 
-If you're using `mule' package, it may exist other characters besides:
+If you're using `mule' package, there may be other characters besides:
 
    \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
 \"\\xF20\"
 
 that should be considered blank.
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `empty' as an element."
+Used when `whitespace-style' includes `empty'."
   :type '(regexp :tag "Empty Lines At End Of Buffer")
   :group 'whitespace)
 
 
-(defcustom whitespace-space-after-tab-regexp "\t\\(\\( \\{8\\}\\)+\\)"
-  "*Specify regexp for 8 or more SPACEs after TAB.
+(defcustom whitespace-space-after-tab-regexp
+  '("\t+\\(\\( \\{%d\\}\\)+\\)"
+    . "\\(\t+\\) +")
+  "Specify regexp for 8 or more SPACEs after TAB.
 
-If you're using `mule' package, it may exist other characters besides:
+It is a cons where the cons car is used for SPACEs visualization
+and the cons cdr is used for TABs visualization.
+
+If you're using `mule' package, there may be other characters besides:
 
    \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
 \"\\xF20\"
 
 that should be considered blank.
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `space-after-tab' as an element."
+Used when `whitespace-style' includes `space-after-tab',
+`space-after-tab::tab' or `space-after-tab::space'."
   :type '(regexp :tag "SPACEs After TAB")
   :group 'whitespace)
 
 
 (defcustom whitespace-line-column 80
-  "*Specify column beyond which the line is highlighted.
+  "Specify column beyond which the line is highlighted.
 
-Used when `whitespace-style' has `color' as an element, and
-`whitespace-chars' has `lines' or `lines-tail' as an element."
+Used when `whitespace-style' includes `lines' or `lines-tail'."
   :type '(integer :tag "Line Length")
   :group 'whitespace)
 
 
 ;; Hacked from `visible-whitespace-mappings' in visws.el
 (defcustom whitespace-display-mappings
-  ;; Due to limitations of glyph representation, the char code can not
-  ;; be above ?\x1FFFF.  Probably, this will be fixed after Emacs
-  ;; unicode merging.
   '(
-    (?\     [?\xB7]       [?.])                ; space - centered dot
-    (?\xA0  [?\xA4]       [?_])                ; hard space - currency
-    (?\x8A0 [?\x8A4]      [?_])                ; hard space - currency
-    (?\x920 [?\x924]      [?_])                ; hard space - currency
-    (?\xE20 [?\xE24]      [?_])                ; hard space - currency
-    (?\xF20 [?\xF24]      [?_])                ; hard space - currency
+    (space-mark   ?\     [?\u00B7]     [?.])           ; space - centered dot
+    (space-mark   ?\xA0  [?\u00A4]     [?_])           ; hard space - currency
+    (space-mark   ?\x8A0 [?\x8A4]      [?_])           ; hard space - currency
+    (space-mark   ?\x920 [?\x924]      [?_])           ; hard space - currency
+    (space-mark   ?\xE20 [?\xE24]      [?_])           ; hard space - currency
+    (space-mark   ?\xF20 [?\xF24]      [?_])           ; hard space - currency
     ;; NEWLINE is displayed using the face `whitespace-newline'
-    (?\n    [?$ ?\n])                  ; end-of-line - dollar sign
-    ;; (?\n    [?\u21B5 ?\n] [?$ ?\n]) ; end-of-line - downwards arrow
-    ;; (?\n    [?\xB6 ?\n]   [?$ ?\n]) ; end-of-line - pilcrow
-    ;; (?\n    [?\x8AF ?\n]  [?$ ?\n]) ; end-of-line - overscore
-    ;; (?\n    [?\x8AC ?\n]  [?$ ?\n]) ; end-of-line - negation
-    ;; (?\n    [?\x8B0 ?\n]  [?$ ?\n]) ; end-of-line - grade
+    (newline-mark ?\n    [?$ ?\n])                     ; eol - dollar sign
+    ;; (newline-mark ?\n    [?\u21B5 ?\n] [?$ ?\n])    ; eol - downwards arrow
+    ;; (newline-mark ?\n    [?\u00B6 ?\n] [?$ ?\n])    ; eol - pilcrow
+    ;; (newline-mark ?\n    [?\x8AF ?\n]  [?$ ?\n])    ; eol - overscore
+    ;; (newline-mark ?\n    [?\x8AC ?\n]  [?$ ?\n])    ; eol - negation
+    ;; (newline-mark ?\n    [?\x8B0 ?\n]  [?$ ?\n])    ; eol - grade
     ;;
     ;; WARNING: the mapping below has a problem.
     ;; When a TAB occupies exactly one column, it will display the
     ;; character ?\xBB at that column followed by a TAB which goes to
     ;; the next TAB column.
     ;; If this is a problem for you, please, comment the line below.
-    (?\t    [?\xBB ?\t]   [?\\ ?\t])   ; tab - left quote mark
+    (tab-mark     ?\t    [?\u00BB ?\t] [?\\ ?\t])      ; tab - left quote mark
     )
-  "*Specify an alist of mappings for displaying characters.
+  "Specify an alist of mappings for displaying characters.
 
 Each element has the following form:
 
-   (CHAR VECTOR...)
+   (KIND CHAR VECTOR...)
 
 Where:
 
+KIND   is the kind of character.
+       It can be one of the following symbols:
+
+       tab-mark        for TAB character
+
+       space-mark      for SPACE or HARD SPACE character
+
+       newline-mark    for NEWLINE character
+
 CHAR   is the character to be mapped.
 
 VECTOR is a vector of characters to be displayed in place of CHAR.
@@ -826,13 +921,16 @@ VECTOR    is a vector of characters to be displayed in place of CHAR.
        that character is displayed unmodified.
 
 The NEWLINE character is displayed using the face given by
-`whitespace-newline' variable.  The characters in the vector to
-be displayed will not have this face applied if the character
-code is above #x1FFFF.
+`whitespace-newline' variable.
 
-Used when `whitespace-style' has `mark' as an element."
+Used when `whitespace-style' includes `tab-mark', `space-mark' or
+`newline-mark'."
   :type '(repeat
          (list :tag "Character Mapping"
+               (choice :tag "Char Kind"
+                       (const :tag "Tab" tab-mark)
+                       (const :tag "Space" space-mark)
+                       (const :tag "Newline" newline-mark))
                (character :tag "Char")
                (repeat :inline t :tag "Vector List"
                        (vector :tag ""
@@ -843,7 +941,7 @@ Used when `whitespace-style' has `mark' as an element."
 
 
 (defcustom whitespace-global-modes t
-  "*Modes for which global `whitespace-mode' is automagically turned on.
+  "Modes for which global `whitespace-mode' is automagically turned on.
 
 Global `whitespace-mode' is controlled by the command
 `global-whitespace-mode'.
@@ -862,7 +960,8 @@ of the list is negated if it begins with `not'.  For example:
 
 means that `whitespace-mode' is turned on for buffers in C and
 C++ modes only."
-  :type '(choice (const :tag "None" nil)
+  :type '(choice :tag "Global Modes"
+                (const :tag "None" nil)
                 (const :tag "All" t)
                 (set :menu-tag "Mode Specific" :tag "Modes"
                      :value (not)
@@ -871,6 +970,46 @@ C++ modes only."
                              (symbol :tag "Mode"))))
   :group 'whitespace)
 
+
+(defcustom whitespace-action nil
+  "Specify which action is taken when a buffer is visited or written.
+
+It's a list containing some or all of the following values:
+
+   nil                 no action is taken.
+
+   cleanup             cleanup any bogus whitespace always when local
+                       whitespace is turned on.
+                       See `whitespace-cleanup' and
+                       `whitespace-cleanup-region'.
+
+   report-on-bogus     report if there is any bogus whitespace always
+                       when local whitespace is turned on.
+
+   auto-cleanup                cleanup any bogus whitespace when buffer is
+                       written.
+                       See `whitespace-cleanup' and
+                       `whitespace-cleanup-region'.
+
+   abort-on-bogus      abort if there is any bogus whitespace and the
+                       buffer is written.
+
+   warn-if-read-only   give a warning if `cleanup' or `auto-cleanup'
+                       is included in `whitespace-action' and the
+                       buffer is read-only.
+
+Any other value is treated as nil."
+  :type '(choice :tag "Actions"
+                (const :tag "None" nil)
+                (repeat :tag "Action List"
+                 (choice :tag "Action"
+                         (const :tag "Cleanup When On" cleanup)
+                         (const :tag "Report On Bogus" report-on-bogus)
+                         (const :tag "Auto Cleanup" auto-cleanup)
+                         (const :tag "Abort On Bogus" abort-on-bogus)
+                         (const :tag "Warn If Read-Only" warn-if-read-only))))
+  :group 'whitespace)
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;; User commands - Local mode
@@ -883,7 +1022,9 @@ C++ modes only."
 If ARG is null, toggle whitespace visualization.
 If ARG is a number greater than zero, turn on visualization;
 otherwise, turn off visualization.
-Only useful with a windowing system."
+
+See also `whitespace-style', `whitespace-newline' and
+`whitespace-display-mappings'."
   :lighter    " ws"
   :init-value nil
   :global     nil
@@ -892,23 +1033,51 @@ Only useful with a windowing system."
    (noninteractive                     ; running a batch job
     (setq whitespace-mode nil))
    (whitespace-mode                    ; whitespace-mode on
-    (whitespace-turn-on))
+    (whitespace-turn-on)
+    (whitespace-action-when-on))
    (t                                  ; whitespace-mode off
     (whitespace-turn-off))))
 
+
+;;;###autoload
+(define-minor-mode whitespace-newline-mode
+  "Toggle NEWLINE minor mode visualization (\"nl\" on modeline).
+
+If ARG is null, toggle NEWLINE visualization.
+If ARG is a number greater than zero, turn on visualization;
+otherwise, turn off visualization.
+
+Use `whitespace-newline-mode' only for NEWLINE visualization
+exclusively.  For other visualizations, including NEWLINE
+visualization together with (HARD) SPACEs and/or TABs, please,
+use `whitespace-mode'.
+
+See also `whitespace-newline' and `whitespace-display-mappings'."
+  :lighter    " nl"
+  :init-value nil
+  :global     nil
+  :group      'whitespace
+  (let ((whitespace-style '(newline-mark newline)))
+    (whitespace-mode whitespace-newline-mode)
+    ;; sync states (running a batch job)
+    (setq whitespace-newline-mode whitespace-mode)))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;; User commands - Global mode
 
 
+;;;###autoload
 (define-minor-mode global-whitespace-mode
   "Toggle whitespace global minor mode visualization (\"WS\" on modeline).
 
 If ARG is null, toggle whitespace visualization.
 If ARG is a number greater than zero, turn on visualization;
 otherwise, turn off visualization.
-Only useful with a windowing system."
-  :lighter    " BL"
+
+See also `whitespace-style', `whitespace-newline' and
+`whitespace-display-mappings'."
+  :lighter    " WS"
   :init-value nil
   :global     t
   :group      'whitespace
@@ -917,18 +1086,14 @@ Only useful with a windowing system."
     (setq global-whitespace-mode nil))
    (global-whitespace-mode             ; global-whitespace-mode on
     (save-excursion
-      (if (boundp 'find-file-hook)
-         (add-hook 'find-file-hook 'whitespace-turn-on-if-enabled t)
-       (add-hook 'find-file-hooks 'whitespace-turn-on-if-enabled t))
+      (add-hook 'find-file-hook 'whitespace-turn-on-if-enabled)
       (dolist (buffer (buffer-list))   ; adjust all local mode
        (set-buffer buffer)
        (unless whitespace-mode
          (whitespace-turn-on-if-enabled)))))
    (t                                  ; global-whitespace-mode off
     (save-excursion
-      (if (boundp 'find-file-hook)
-         (remove-hook 'find-file-hook 'whitespace-turn-on-if-enabled)
-       (remove-hook 'find-file-hooks 'whitespace-turn-on-if-enabled))
+      (remove-hook 'find-file-hook 'whitespace-turn-on-if-enabled)
       (dolist (buffer (buffer-list))   ; adjust all local mode
        (set-buffer buffer)
        (unless whitespace-mode
@@ -957,48 +1122,81 @@ Only useful with a windowing system."
        ;; Otherwise, turn on whitespace mode.
        (whitespace-turn-on)))))
 
+
+;;;###autoload
+(define-minor-mode global-whitespace-newline-mode
+  "Toggle NEWLINE global minor mode visualization (\"NL\" on modeline).
+
+If ARG is null, toggle NEWLINE visualization.
+If ARG is a number greater than zero, turn on visualization;
+otherwise, turn off visualization.
+
+Use `global-whitespace-newline-mode' only for NEWLINE
+visualization exclusively.  For other visualizations, including
+NEWLINE visualization together with (HARD) SPACEs and/or TABs,
+please, use `global-whitespace-mode'.
+
+See also `whitespace-newline' and `whitespace-display-mappings'."
+  :lighter    " NL"
+  :init-value nil
+  :global     t
+  :group      'whitespace
+  (let ((whitespace-style '(newline-mark newline)))
+    (global-whitespace-mode global-whitespace-newline-mode)
+    ;; sync states (running a batch job)
+    (setq global-whitespace-newline-mode global-whitespace-mode)))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;; User commands - Toggle
 
 
-(defconst whitespace-chars-value-list
+(defconst whitespace-style-value-list
   '(tabs
     spaces
     trailing
-    space-before-tab
     lines
     lines-tail
     newline
-    indentation
     empty
+    indentation
+    indentation::tab
+    indentation::space
     space-after-tab
-    )
-  "List of valid `whitespace-chars' values.")
-
-
-(defconst whitespace-style-value-list
-  '(color
-    mark
+    space-after-tab::tab
+    space-after-tab::space
+    space-before-tab
+    space-before-tab::tab
+    space-before-tab::space
+    help-newline       ; value used by `whitespace-insert-option-mark'
+    tab-mark
+    space-mark
+    newline-mark
     )
   "List of valid `whitespace-style' values.")
 
 
 (defconst whitespace-toggle-option-alist
-  '((?t . tabs)
-    (?s . spaces)
-    (?r . trailing)
-    (?b . space-before-tab)
-    (?l . lines)
-    (?L . lines-tail)
-    (?n . newline)
-    (?i . indentation)
-    (?e . empty)
-    (?a . space-after-tab)
-    (?c . color)
-    (?m . mark)
-    (?x . whitespace-chars)
-    (?z . whitespace-style)
+  '((?t    . tabs)
+    (?s    . spaces)
+    (?r    . trailing)
+    (?l    . lines)
+    (?L    . lines-tail)
+    (?n    . newline)
+    (?e    . empty)
+    (?\C-i . indentation)
+    (?I    . indentation::tab)
+    (?i    . indentation::space)
+    (?\C-a . space-after-tab)
+    (?A    . space-after-tab::tab)
+    (?a    . space-after-tab::space)
+    (?\C-b . space-before-tab)
+    (?B    . space-before-tab::tab)
+    (?b    . space-before-tab::space)
+    (?T    . tab-mark)
+    (?S    . space-mark)
+    (?N    . newline-mark)
+    (?x    . whitespace-style)
     )
   "Alist of toggle options.
 
@@ -1011,17 +1209,25 @@ Where:
 CHAR   is a char which the user will have to type.
 
 SYMBOL is a valid symbol associated with CHAR.
-       See `whitespace-chars-value-list' and
-       `whitespace-style-value-list'.")
+       See `whitespace-style-value-list'.")
 
 
-(defvar whitespace-active-chars nil
-  "Used to save locally `whitespace-chars' value.")
-(make-variable-buffer-local 'whitespace-active-chars)
-
 (defvar whitespace-active-style nil
   "Used to save locally `whitespace-style' value.")
-(make-variable-buffer-local 'whitespace-active-style)
+
+(defvar whitespace-indent-tabs-mode indent-tabs-mode
+  "Used to save locally `indent-tabs-mode' value.")
+
+(defvar whitespace-tab-width tab-width
+  "Used to save locally `tab-width' value.")
+
+(defvar whitespace-point (point)
+  "Used to save locally current point value.
+Used by `whitespace-trailing-regexp' function (which see).")
+
+(defvar whitespace-font-lock-refontify nil
+  "Used to save locally the font-lock refontify state.
+Used by `whitespace-post-command-hook' function (which see).")
 
 
 ;;;###autoload
@@ -1037,20 +1243,30 @@ and restart local whitespace-mode.
 Interactively, it reads one of the following chars:
 
   CHAR MEANING
+  (VIA FACES)
    t   toggle TAB visualization
    s   toggle SPACE and HARD SPACE visualization
    r   toggle trailing blanks visualization
-   b   toggle SPACEs before TAB visualization
    l   toggle \"long lines\" visualization
    L   toggle \"long lines\" tail visualization
    n   toggle NEWLINE visualization
-   i   toggle indentation SPACEs visualization
    e   toggle empty line at bob and/or eob visualization
-   a   toggle SPACEs after TAB visualization
-   c   toggle color faces
-   m   toggle visual mark
-   x   restore `whitespace-chars' value
-   z   restore `whitespace-style' value
+   C-i toggle indentation SPACEs visualization (via `indent-tabs-mode')
+   I   toggle indentation SPACEs visualization
+   i   toggle indentation TABs visualization
+   C-a toggle SPACEs after TAB visualization (via `indent-tabs-mode')
+   A   toggle SPACEs after TAB: SPACEs visualization
+   a   toggle SPACEs after TAB: TABs visualization
+   C-b toggle SPACEs before TAB visualization (via `indent-tabs-mode')
+   B   toggle SPACEs before TAB: SPACEs visualization
+   b   toggle SPACEs before TAB: TABs visualization
+
+  (VIA DISPLAY TABLE)
+   T   toggle TAB visualization
+   S   toggle SPACEs before TAB visualization
+   N   toggle NEWLINE visualization
+
+   x   restore `whitespace-style' value
    ?   display brief help
 
 Non-interactively, ARG should be a symbol or a list of symbols.
@@ -1059,34 +1275,34 @@ The valid symbols are:
    tabs                        toggle TAB visualization
    spaces              toggle SPACE and HARD SPACE visualization
    trailing            toggle trailing blanks visualization
-   space-before-tab    toggle SPACEs before TAB visualization
    lines               toggle \"long lines\" visualization
    lines-tail          toggle \"long lines\" tail visualization
    newline             toggle NEWLINE visualization
-   indentation         toggle indentation SPACEs visualization
    empty               toggle empty line at bob and/or eob visualization
-   space-after-tab     toggle SPACEs after TAB visualization
-   color               toggle color faces
-   mark                        toggle visual mark
-   whitespace-chars            restore `whitespace-chars' value
-   whitespace-style            restore `whitespace-style' value
-
-Only useful with a windowing system."
+   indentation         toggle indentation SPACEs visualization
+   indentation::tab    toggle indentation SPACEs visualization
+   indentation::space  toggle indentation TABs visualization
+   space-after-tab             toggle SPACEs after TAB visualization
+   space-after-tab::tab                toggle SPACEs after TAB: SPACEs visualization
+   space-after-tab::space      toggle SPACEs after TAB: TABs visualization
+   space-before-tab            toggle SPACEs before TAB visualization
+   space-before-tab::tab       toggle SPACEs before TAB: SPACEs visualization
+   space-before-tab::space     toggle SPACEs before TAB: TABs visualization
+
+   tab-mark            toggle TAB visualization
+   space-mark          toggle SPACEs before TAB visualization
+   newline-mark                toggle NEWLINE visualization
+
+   whitespace-style    restore `whitespace-style' value
+
+See `whitespace-style' and `indent-tabs-mode' for documentation."
   (interactive (whitespace-interactive-char t))
-  (let ((whitespace-chars
-        (whitespace-toggle-list
-         t arg whitespace-active-chars whitespace-chars
-         'whitespace-chars whitespace-chars-value-list))
-       (whitespace-style
-        (whitespace-toggle-list
-         t arg whitespace-active-style whitespace-style
-         'whitespace-style whitespace-style-value-list)))
+  (let ((whitespace-style
+        (whitespace-toggle-list t arg whitespace-active-style)))
     (whitespace-mode 0)
     (whitespace-mode 1)))
 
 
-(defvar whitespace-toggle-chars nil
-  "Used to toggle the global `whitespace-chars' value.")
 (defvar whitespace-toggle-style nil
   "Used to toggle the global `whitespace-style' value.")
 
@@ -1101,23 +1317,33 @@ and turn on global whitespace-mode.
 If global whitespace-mode is on, toggle the option given by ARG
 and restart global whitespace-mode.
 
-Interactively, it reads one of the following chars:
+Interactively, it accepts one of the following chars:
 
   CHAR MEANING
+  (VIA FACES)
    t   toggle TAB visualization
    s   toggle SPACE and HARD SPACE visualization
    r   toggle trailing blanks visualization
-   b   toggle SPACEs before TAB visualization
    l   toggle \"long lines\" visualization
    L   toggle \"long lines\" tail visualization
    n   toggle NEWLINE visualization
-   i   toggle indentation SPACEs visualization
    e   toggle empty line at bob and/or eob visualization
-   a   toggle SPACEs after TAB visualization
-   c   toggle color faces
-   m   toggle visual mark
-   x   restore `whitespace-chars' value
-   z   restore `whitespace-style' value
+   C-i toggle indentation SPACEs visualization (via `indent-tabs-mode')
+   I   toggle indentation SPACEs visualization
+   i   toggle indentation TABs visualization
+   C-a toggle SPACEs after TAB visualization (via `indent-tabs-mode')
+   A   toggle SPACEs after TAB: SPACEs visualization
+   a   toggle SPACEs after TAB: TABs visualization
+   C-b toggle SPACEs before TAB visualization (via `indent-tabs-mode')
+   B   toggle SPACEs before TAB: SPACEs visualization
+   b   toggle SPACEs before TAB: TABs visualization
+
+  (VIA DISPLAY TABLE)
+   T   toggle TAB visualization
+   S   toggle SPACEs before TAB visualization
+   N   toggle NEWLINE visualization
+
+   x   restore `whitespace-style' value
    ?   display brief help
 
 Non-interactively, ARG should be a symbol or a list of symbols.
@@ -1126,30 +1352,31 @@ The valid symbols are:
    tabs                        toggle TAB visualization
    spaces              toggle SPACE and HARD SPACE visualization
    trailing            toggle trailing blanks visualization
-   space-before-tab    toggle SPACEs before TAB visualization
    lines               toggle \"long lines\" visualization
    lines-tail          toggle \"long lines\" tail visualization
    newline             toggle NEWLINE visualization
-   indentation         toggle indentation SPACEs visualization
    empty               toggle empty line at bob and/or eob visualization
-   space-after-tab     toggle SPACEs after TAB visualization
-   color               toggle color faces
-   mark                        toggle visual mark
-   whitespace-chars            restore `whitespace-chars' value
-   whitespace-style            restore `whitespace-style' value
-
-Only useful with a windowing system."
+   indentation         toggle indentation SPACEs visualization
+   indentation::tab    toggle indentation SPACEs visualization
+   indentation::space  toggle indentation TABs visualization
+   space-after-tab             toggle SPACEs after TAB visualization
+   space-after-tab::tab                toggle SPACEs after TAB: SPACEs visualization
+   space-after-tab::space      toggle SPACEs after TAB: TABs visualization
+   space-before-tab            toggle SPACEs before TAB visualization
+   space-before-tab::tab       toggle SPACEs before TAB: SPACEs visualization
+   space-before-tab::space     toggle SPACEs before TAB: TABs visualization
+
+   tab-mark            toggle TAB visualization
+   space-mark          toggle SPACEs before TAB visualization
+   newline-mark                toggle NEWLINE visualization
+
+   whitespace-style    restore `whitespace-style' value
+
+See `whitespace-style' and `indent-tabs-mode' for documentation."
   (interactive (whitespace-interactive-char nil))
-  (let ((whitespace-chars
-        (whitespace-toggle-list
-         nil arg whitespace-toggle-chars whitespace-chars
-         'whitespace-chars whitespace-chars-value-list))
-       (whitespace-style
-        (whitespace-toggle-list
-         nil arg whitespace-toggle-style whitespace-style
-         'whitespace-style whitespace-style-value-list)))
-    (setq whitespace-toggle-chars whitespace-chars
-         whitespace-toggle-style whitespace-style)
+  (let ((whitespace-style
+        (whitespace-toggle-list nil arg whitespace-toggle-style)))
+    (setq whitespace-toggle-style whitespace-style)
     (global-whitespace-mode 0)
     (global-whitespace-mode 1)))
 
@@ -1164,52 +1391,76 @@ Only useful with a windowing system."
 
 It usually applies to the whole buffer, but in transient mark
 mode when the mark is active, it applies to the region.  It also
-applies to the region when it is not in transiente mark mode, the
-mark is active and it was pressed `C-u' just before calling
-`whitespace-cleanup' interactively.
+applies to the region when it is not in transient mark mode, the
+mark is active and \\[universal-argument] was pressed just before
+calling `whitespace-cleanup' interactively.
 
 See also `whitespace-cleanup-region'.
 
-The problems, which are cleaned up, are:
+The problems cleaned up are:
 
 1. empty lines at beginning of buffer.
 2. empty lines at end of buffer.
-   If `whitespace-chars' has `empty' as an element, remove all
+   If `whitespace-style' includes the value `empty', remove all
    empty lines at beginning and/or end of buffer.
 
 3. 8 or more SPACEs at beginning of line.
-   If `whitespace-chars' has `indentation' as an element, replace
-   8 or more SPACEs at beginning of line by TABs.
+   If `whitespace-style' includes the value `indentation':
+   replace 8 or more SPACEs at beginning of line by TABs, if
+   `indent-tabs-mode' is non-nil; otherwise, replace TABs by
+   SPACEs.
+   If `whitespace-style' includes the value `indentation::tab',
+   replace 8 or more SPACEs at beginning of line by TABs.
+   If `whitespace-style' includes the value `indentation::space',
+   replace TABs by SPACEs.
 
 4. SPACEs before TAB.
-   If `whitespace-chars' has `space-before-tab' as an element,
-   replace SPACEs by TABs.
+   If `whitespace-style' includes the value `space-before-tab':
+   replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
+   otherwise, replace TABs by SPACEs.
+   If `whitespace-style' includes the value
+   `space-before-tab::tab', replace SPACEs by TABs.
+   If `whitespace-style' includes the value
+   `space-before-tab::space', replace TABs by SPACEs.
 
 5. SPACEs or TABs at end of line.
-   If `whitespace-chars' has `trailing' as an element, remove all
-   SPACEs or TABs at end of line.
+   If `whitespace-style' includes the value `trailing', remove
+   all SPACEs or TABs at end of line.
 
 6. 8 or more SPACEs after TAB.
-   If `whitespace-chars' has `space-after-tab' as an element,
-   replace SPACEs by TABs."
-  (interactive "@*")
-  (if (and (or transient-mark-mode
-              current-prefix-arg)
-          mark-active)
-      ;; region active
-      ;; problems 1 and 2 are not handled in region
-      ;; problem 3: 8 or more SPACEs at bol
-      ;; problem 4: SPACEs before TAB
-      ;; problem 5: SPACEs or TABs at eol
-      ;; problem 6: 8 or more SPACEs after TAB
-      (whitespace-cleanup-region (region-beginning) (region-end))
-    ;; whole buffer
+   If `whitespace-style' includes the value `space-after-tab':
+   replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
+   otherwise, replace TABs by SPACEs.
+   If `whitespace-style' includes the value
+   `space-after-tab::tab', replace SPACEs by TABs.
+   If `whitespace-style' includes the value
+   `space-after-tab::space', replace TABs by SPACEs.
+
+See `whitespace-style', `indent-tabs-mode' and `tab-width' for
+documentation."
+  (interactive "@")
+  (cond
+   ;; read-only buffer
+   (buffer-read-only
+    (whitespace-warn-read-only "cleanup"))
+   ;; region active
+   ((and (or transient-mark-mode
+            current-prefix-arg)
+        mark-active)
+    ;; PROBLEMs 1 and 2 are not handled in region
+    ;; PROBLEM 3: 8 or more SPACEs at bol
+    ;; PROBLEM 4: SPACEs before TAB
+    ;; PROBLEM 5: SPACEs or TABs at eol
+    ;; PROBLEM 6: 8 or more SPACEs after TAB
+    (whitespace-cleanup-region (region-beginning) (region-end)))
+   ;; whole buffer
+   (t
     (save-excursion
       (save-match-data
-       ;; problem 1: empty lines at bob
-       ;; problem 2: empty lines at eob
-       ;; action: remove all empty lines at bob and/or eob
-       (when (memq 'empty whitespace-chars)
+       ;; PROBLEM 1: empty lines at bob
+       ;; PROBLEM 2: empty lines at eob
+       ;; ACTION: remove all empty lines at bob and/or eob
+       (when (memq 'empty whitespace-style)
          (let (overwrite-mode)         ; enforce no overwrite
            (goto-char (point-min))
            (when (re-search-forward
@@ -1218,135 +1469,397 @@ The problems, which are cleaned up, are:
            (when (re-search-forward
                   whitespace-empty-at-eob-regexp nil t)
              (delete-region (match-beginning 1) (match-end 1)))))))
-    ;; problem 3: 8 or more SPACEs at bol
-    ;; problem 4: SPACEs before TAB
-    ;; problem 5: SPACEs or TABs at eol
-    ;; problem 6: 8 or more SPACEs after TAB
-    (whitespace-cleanup-region (point-min) (point-max))))
+    ;; PROBLEM 3: 8 or more SPACEs at bol
+    ;; PROBLEM 4: SPACEs before TAB
+    ;; PROBLEM 5: SPACEs or TABs at eol
+    ;; PROBLEM 6: 8 or more SPACEs after TAB
+    (whitespace-cleanup-region (point-min) (point-max)))))
 
 
 ;;;###autoload
 (defun whitespace-cleanup-region (start end)
   "Cleanup some blank problems at region.
 
-The problems, which are cleaned up, are:
+The problems cleaned up are:
 
 1. 8 or more SPACEs at beginning of line.
-   If `whitespace-chars' has `indentation' as an element, replace
-   8 or more SPACEs at beginning of line by TABs.
+   If `whitespace-style' includes the value `indentation':
+   replace 8 or more SPACEs at beginning of line by TABs, if
+   `indent-tabs-mode' is non-nil; otherwise, replace TABs by
+   SPACEs.
+   If `whitespace-style' includes the value `indentation::tab',
+   replace 8 or more SPACEs at beginning of line by TABs.
+   If `whitespace-style' includes the value `indentation::space',
+   replace TABs by SPACEs.
 
 2. SPACEs before TAB.
-   If `whitespace-chars' has `space-before-tab' as an element,
-   replace SPACEs by TABs.
+   If `whitespace-style' includes the value `space-before-tab':
+   replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
+   otherwise, replace TABs by SPACEs.
+   If `whitespace-style' includes the value
+   `space-before-tab::tab', replace SPACEs by TABs.
+   If `whitespace-style' includes the value
+   `space-before-tab::space', replace TABs by SPACEs.
 
 3. SPACEs or TABs at end of line.
-   If `whitespace-chars' has `trailing' as an element, remove all
-   SPACEs or TABs at end of line.
+   If `whitespace-style' includes the value `trailing', remove
+   all SPACEs or TABs at end of line.
 
 4. 8 or more SPACEs after TAB.
-   If `whitespace-chars' has `space-after-tab' as an element,
-   replace SPACEs by TABs."
-  (interactive "@*r")
-  (let ((rstart           (min start end))
-       (rend             (copy-marker (max start end)))
-       (tab-width        8)            ; assure TAB width
-       (indent-tabs-mode t)            ; always insert TABs
-       overwrite-mode                  ; enforce no overwrite
-       tmp)
-    (save-excursion
-      (save-match-data
-       ;; problem 1: 8 or more SPACEs at bol
-       ;; action: replace 8 or more SPACEs at bol by TABs
-       (when (memq 'indentation whitespace-chars)
-         (goto-char rstart)
-         (while (re-search-forward
-                 whitespace-indentation-regexp rend t)
-           (setq tmp (current-indentation))
-           (delete-horizontal-space)
-           (unless (eolp)
-             (indent-to tmp))))
-       ;; problem 3: SPACEs or TABs at eol
-       ;; action: remove all SPACEs or TABs at eol
-       (when (memq 'trailing whitespace-chars)
-         (let ((regexp (concat "\\(\\(" whitespace-trailing-regexp
-                               "\\)+\\)$")))
-           (goto-char rstart)
-           (while (re-search-forward regexp rend t)
-             (delete-region (match-beginning 1) (match-end 1)))))
-       ;; problem 4: 8 or more SPACEs after TAB
-       ;; action: replace 8 or more SPACEs by TABs
-       (when (memq 'space-after-tab whitespace-chars)
-         (whitespace-replace-spaces-by-tabs
-          rstart rend whitespace-space-after-tab-regexp))
-       ;; problem 2: SPACEs before TAB
-       ;; action: replace SPACEs before TAB by TABs
-       (when (memq 'space-before-tab whitespace-chars)
-         (whitespace-replace-spaces-by-tabs
-          rstart rend whitespace-space-before-tab-regexp))))
-    (set-marker rend nil)))            ; point marker to nowhere
-
-
-(defun whitespace-replace-spaces-by-tabs (rstart rend regexp)
-  "Replace all SPACEs by TABs matched by REGEXP between RSTART and REND."
+   If `whitespace-style' includes the value `space-after-tab':
+   replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
+   otherwise, replace TABs by SPACEs.
+   If `whitespace-style' includes the value
+   `space-after-tab::tab', replace SPACEs by TABs.
+   If `whitespace-style' includes the value
+   `space-after-tab::space', replace TABs by SPACEs.
+
+See `whitespace-style', `indent-tabs-mode' and `tab-width' for
+documentation."
+  (interactive "@r")
+  (if buffer-read-only
+      ;; read-only buffer
+      (whitespace-warn-read-only "cleanup region")
+    ;; non-read-only buffer
+    (let ((rstart           (min start end))
+         (rend             (copy-marker (max start end)))
+         (indent-tabs-mode whitespace-indent-tabs-mode)
+         (tab-width        whitespace-tab-width)
+         overwrite-mode                ; enforce no overwrite
+         tmp)
+      (save-excursion
+       (save-match-data
+         ;; PROBLEM 1: 8 or more SPACEs at bol
+         (cond
+          ;; ACTION: replace 8 or more SPACEs at bol by TABs, if
+          ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs
+          ;; by SPACEs.
+          ((memq 'indentation whitespace-style)
+           (let ((regexp (whitespace-indentation-regexp)))
+             (goto-char rstart)
+             (while (re-search-forward regexp rend t)
+               (setq tmp (current-indentation))
+               (goto-char (match-beginning 0))
+               (delete-horizontal-space)
+               (unless (eolp)
+                 (indent-to tmp)))))
+          ;; ACTION: replace 8 or more SPACEs at bol by TABs.
+          ((memq 'indentation::tab whitespace-style)
+           (whitespace-replace-action
+            'tabify rstart rend
+            (whitespace-indentation-regexp 'tab) 0))
+          ;; ACTION: replace TABs by SPACEs.
+          ((memq 'indentation::space whitespace-style)
+           (whitespace-replace-action
+            'untabify rstart rend
+            (whitespace-indentation-regexp 'space) 0)))
+         ;; PROBLEM 3: SPACEs or TABs at eol
+         ;; ACTION: remove all SPACEs or TABs at eol
+         (when (memq 'trailing whitespace-style)
+           (whitespace-replace-action
+            'delete-region rstart rend
+            whitespace-trailing-regexp 1))
+         ;; PROBLEM 4: 8 or more SPACEs after TAB
+         (cond
+          ;; ACTION: replace 8 or more SPACEs by TABs, if
+          ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs
+          ;; by SPACEs.
+          ((memq 'space-after-tab whitespace-style)
+           (whitespace-replace-action
+            (if whitespace-indent-tabs-mode 'tabify 'untabify)
+            rstart rend (whitespace-space-after-tab-regexp) 1))
+          ;; ACTION: replace 8 or more SPACEs by TABs.
+          ((memq 'space-after-tab::tab whitespace-style)
+           (whitespace-replace-action
+            'tabify rstart rend
+            (whitespace-space-after-tab-regexp 'tab) 1))
+          ;; ACTION: replace TABs by SPACEs.
+          ((memq 'space-after-tab::space whitespace-style)
+           (whitespace-replace-action
+            'untabify rstart rend
+            (whitespace-space-after-tab-regexp 'space) 1)))
+         ;; PROBLEM 2: SPACEs before TAB
+         (cond
+          ;; ACTION: replace SPACEs before TAB by TABs, if
+          ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs
+          ;; by SPACEs.
+          ((memq 'space-before-tab whitespace-style)
+           (whitespace-replace-action
+            (if whitespace-indent-tabs-mode 'tabify 'untabify)
+            rstart rend whitespace-space-before-tab-regexp
+            (if whitespace-indent-tabs-mode 1 2)))
+          ;; ACTION: replace SPACEs before TAB by TABs.
+          ((memq 'space-before-tab::tab whitespace-style)
+           (whitespace-replace-action
+            'tabify rstart rend
+            whitespace-space-before-tab-regexp 1))
+          ;; ACTION: replace TABs by SPACEs.
+          ((memq 'space-before-tab::space whitespace-style)
+           (whitespace-replace-action
+            'untabify rstart rend
+            whitespace-space-before-tab-regexp 2)))))
+      (set-marker rend nil))))         ; point marker to nowhere
+
+
+(defun whitespace-replace-action (action rstart rend regexp index)
+  "Do ACTION in the string matched by REGEXP between RSTART and REND.
+
+INDEX is the level group matched by REGEXP and used by ACTION.
+
+See also `tab-width'."
   (goto-char rstart)
   (while (re-search-forward regexp rend t)
-    (goto-char (match-beginning 1))
-    (let* ((scol (current-column))
-          (ecol (save-excursion
-                  (goto-char (match-end 1))
-                  (current-column))))
-      (delete-region (match-beginning 1) (match-end 1))
-      (insert-char ?\t
-                  (/ (- (- ecol (% ecol 8))  ; prev end col
-                        (- scol (% scol 8))) ; prev start col
-                     8)))))
+    (goto-char (match-end index))
+    (funcall action (match-beginning index) (match-end index))))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;; User command - old whitespace compatibility
+;;;; User command - report
+
+
+(defun whitespace-regexp (regexp &optional kind)
+  "Return REGEXP depending on `whitespace-indent-tabs-mode'."
+  (cond
+   ((or (eq kind 'tab)
+       whitespace-indent-tabs-mode)
+    (format (car regexp) whitespace-tab-width))
+   ((or (eq kind 'space)
+       (not whitespace-indent-tabs-mode))
+    (cdr regexp))))
+
+
+(defun whitespace-indentation-regexp (&optional kind)
+  "Return the indentation regexp depending on `whitespace-indent-tabs-mode'."
+  (whitespace-regexp whitespace-indentation-regexp kind))
+
+
+(defun whitespace-space-after-tab-regexp (&optional kind)
+  "Return the space-after-tab regexp depending on `whitespace-indent-tabs-mode'."
+  (whitespace-regexp whitespace-space-after-tab-regexp kind))
+
+
+(defconst whitespace-report-list
+  (list
+   (cons 'empty                   whitespace-empty-at-bob-regexp)
+   (cons 'empty                   whitespace-empty-at-eob-regexp)
+   (cons 'trailing                whitespace-trailing-regexp)
+   (cons 'indentation             nil)
+   (cons 'indentation::tab        nil)
+   (cons 'indentation::space      nil)
+   (cons 'space-before-tab        whitespace-space-before-tab-regexp)
+   (cons 'space-before-tab::tab   whitespace-space-before-tab-regexp)
+   (cons 'space-before-tab::space whitespace-space-before-tab-regexp)
+   (cons 'space-after-tab         nil)
+   (cons 'space-after-tab::tab    nil)
+   (cons 'space-after-tab::space  nil)
+   )
+   "List of whitespace bogus symbol and corresponding regexp.")
+
+
+(defconst whitespace-report-text
+  '( ;; `indent-tabs-mode' has non-nil value
+    "\
+ Whitespace Report
+
+ Current Setting                       Whitespace Problem
+
+ empty                    []     []  empty lines at beginning of buffer
+ empty                    []     []  empty lines at end of buffer
+ trailing                 []     []  SPACEs or TABs at end of line
+ indentation              []     []  8 or more SPACEs at beginning of line
+ indentation::tab         []     []  8 or more SPACEs at beginning of line
+ indentation::space       []     []  TABs at beginning of line
+ space-before-tab         []     []  SPACEs before TAB
+ space-before-tab::tab    []     []  SPACEs before TAB: SPACEs
+ space-before-tab::space  []     []  SPACEs before TAB: TABs
+ space-after-tab          []     []  8 or more SPACEs after TAB
+ space-after-tab::tab     []     []  8 or more SPACEs after TAB: SPACEs
+ space-after-tab::space   []     []  8 or more SPACEs after TAB: TABs
+
+ indent-tabs-mode =
+ tab-width        = \n\n"
+    . ;; `indent-tabs-mode' has nil value
+    "\
+ Whitespace Report
+
+ Current Setting                       Whitespace Problem
+
+ empty                    []     []  empty lines at beginning of buffer
+ empty                    []     []  empty lines at end of buffer
+ trailing                 []     []  SPACEs or TABs at end of line
+ indentation              []     []  TABs at beginning of line
+ indentation::tab         []     []  8 or more SPACEs at beginning of line
+ indentation::space       []     []  TABs at beginning of line
+ space-before-tab         []     []  SPACEs before TAB
+ space-before-tab::tab    []     []  SPACEs before TAB: SPACEs
+ space-before-tab::space  []     []  SPACEs before TAB: TABs
+ space-after-tab          []     []  8 or more SPACEs after TAB
+ space-after-tab::tab     []     []  8 or more SPACEs after TAB: SPACEs
+ space-after-tab::space   []     []  8 or more SPACEs after TAB: TABs
+
+ indent-tabs-mode =
+ tab-width        = \n\n")
+  "Text for whitespace bogus report.
+
+It is a cons of strings, where the car part is used when
+`indent-tabs-mode' is non-nil, and the cdr part is used when
+`indent-tabs-mode' is nil.")
+
+
+(defconst whitespace-report-buffer-name "*Whitespace Report*"
+  "The buffer name for whitespace bogus report.")
 
 
 ;;;###autoload
-(defun whitespace-buffer ()
-  "Turn on `whitespace-mode' forcing some settings.
+(defun whitespace-report (&optional force report-if-bogus)
+  "Report some whitespace problems in buffer.
 
-It forces `whitespace-style' to have `color'.
+Return nil if there is no whitespace problem; otherwise, return
+non-nil.
 
-It also forces `whitespace-chars' to have:
+If FORCE is non-nil or \\[universal-argument] was pressed just
+before calling `whitespace-report' interactively, it forces
+`whitespace-style' to have:
 
+   empty
    trailing
    indentation
    space-before-tab
+   space-after-tab
+
+If REPORT-IF-BOGUS is non-nil, it reports only when there are any
+whitespace problems in buffer.
+
+Report if some of the following whitespace problems exist:
+
+* If `indent-tabs-mode' is non-nil:
+   empty               1. empty lines at beginning of buffer.
+   empty               2. empty lines at end of buffer.
+   trailing            3. SPACEs or TABs at end of line.
+   indentation         4. 8 or more SPACEs at beginning of line.
+   space-before-tab    5. SPACEs before TAB.
+   space-after-tab     6. 8 or more SPACEs after TAB.
+
+* If `indent-tabs-mode' is nil:
+   empty               1. empty lines at beginning of buffer.
+   empty               2. empty lines at end of buffer.
+   trailing            3. SPACEs or TABs at end of line.
+   indentation         4. TABS at beginning of line.
+   space-before-tab    5. SPACEs before TAB.
+   space-after-tab     6. 8 or more SPACEs after TAB.
+
+See `whitespace-style' for documentation.
+See also `whitespace-cleanup' and `whitespace-cleanup-region' for
+cleaning up these problems."
+  (interactive (list current-prefix-arg))
+  (whitespace-report-region (point-min) (point-max)
+                           force report-if-bogus))
+
+
+;;;###autoload
+(defun whitespace-report-region (start end &optional force report-if-bogus)
+  "Report some whitespace problems in a region.
+
+Return nil if there is no whitespace problem; otherwise, return
+non-nil.
+
+If FORCE is non-nil or \\[universal-argument] was pressed just
+before calling `whitespace-report-region' interactively, it
+forces `whitespace-style' to have:
+
    empty
+   indentation
+   space-before-tab
+   trailing
    space-after-tab
 
-So, it is possible to visualize the following problems:
+If REPORT-IF-BOGUS is non-nil, it reports only when there are any
+whitespace problems in buffer.
+
+Report if some of the following whitespace problems exist:
 
+* If `indent-tabs-mode' is non-nil:
    empty               1. empty lines at beginning of buffer.
    empty               2. empty lines at end of buffer.
-   indentation         3. 8 or more SPACEs at beginning of line.
-   space-before-tab    4. SPACEs before TAB.
-   trailing            5. SPACEs or TABs at end of line.
+   trailing            3. SPACEs or TABs at end of line.
+   indentation         4. 8 or more SPACEs at beginning of line.
+   space-before-tab    5. SPACEs before TAB.
    space-after-tab     6. 8 or more SPACEs after TAB.
 
-See `whitespace-chars' and `whitespace-style' for documentation.
+* If `indent-tabs-mode' is nil:
+   empty               1. empty lines at beginning of buffer.
+   empty               2. empty lines at end of buffer.
+   trailing            3. SPACEs or TABs at end of line.
+   indentation         4. TABS at beginning of line.
+   space-before-tab    5. SPACEs before TAB.
+   space-after-tab     6. 8 or more SPACEs after TAB.
+
+See `whitespace-style' for documentation.
 See also `whitespace-cleanup' and `whitespace-cleanup-region' for
 cleaning up these problems."
-  (interactive)
-  (whitespace-mode 0)                  ; assure is off
-  ;; keep original values
-  (let ((whitespace-style (copy-sequence whitespace-style))
-       (whitespace-chars (copy-sequence whitespace-chars)))
-    ;; adjust options for whitespace bogus blanks
-    (add-to-list 'whitespace-style 'color)
-    (mapc #'(lambda (option)
-             (add-to-list 'whitespace-chars option))
-         '(trailing
-           indentation
-           space-before-tab
-           empty
-           space-after-tab))
-    (whitespace-mode 1)))              ; turn on
+  (interactive "r")
+  (setq force (or current-prefix-arg force))
+  (save-excursion
+    (save-match-data
+      (let* ((has-bogus nil)
+            (rstart    (min start end))
+            (rend      (max start end))
+            (bogus-list
+             (mapcar
+              #'(lambda (option)
+                  (when force
+                    (add-to-list 'whitespace-style (car option)))
+                  (goto-char rstart)
+                  (let ((regexp
+                         (cond
+                          ((eq (car option) 'indentation)
+                           (whitespace-indentation-regexp))
+                          ((eq (car option) 'indentation::tab)
+                           (whitespace-indentation-regexp 'tab))
+                          ((eq (car option) 'indentation::space)
+                           (whitespace-indentation-regexp 'space))
+                          ((eq (car option) 'space-after-tab)
+                           (whitespace-space-after-tab-regexp))
+                          ((eq (car option) 'space-after-tab::tab)
+                           (whitespace-space-after-tab-regexp 'tab))
+                          ((eq (car option) 'space-after-tab::space)
+                           (whitespace-space-after-tab-regexp 'space))
+                          (t
+                           (cdr option)))))
+                    (and (re-search-forward regexp rend t)
+                         (setq has-bogus t))))
+              whitespace-report-list)))
+       (when (if report-if-bogus has-bogus t)
+         (whitespace-kill-buffer whitespace-report-buffer-name)
+         ;; `whitespace-indent-tabs-mode' is local to current buffer
+         ;; `whitespace-tab-width' is local to current buffer
+         (let ((ws-indent-tabs-mode whitespace-indent-tabs-mode)
+               (ws-tab-width whitespace-tab-width))
+           (with-current-buffer (get-buffer-create
+                                 whitespace-report-buffer-name)
+             (erase-buffer)
+             (insert (if ws-indent-tabs-mode
+                         (car whitespace-report-text)
+                       (cdr whitespace-report-text)))
+             (goto-char (point-min))
+             (forward-line 3)
+             (dolist (option whitespace-report-list)
+               (forward-line 1)
+               (whitespace-mark-x
+                27 (memq (car option) whitespace-style))
+               (whitespace-mark-x 7 (car bogus-list))
+               (setq bogus-list (cdr bogus-list)))
+             (forward-line 1)
+             (whitespace-insert-value ws-indent-tabs-mode)
+             (whitespace-insert-value ws-tab-width)
+             (when has-bogus
+               (goto-char (point-max))
+               (insert " Type `M-x whitespace-cleanup'"
+                       " to cleanup the buffer.\n\n"
+                       " Type `M-x whitespace-cleanup-region'"
+                       " to cleanup a region.\n\n"))
+             (whitespace-display-window (current-buffer)))))
+       has-bogus))))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1355,37 +1868,42 @@ cleaning up these problems."
 
 (defvar whitespace-font-lock-mode nil
   "Used to remember whether a buffer had font lock mode on or not.")
-(make-variable-buffer-local 'whitespace-font-lock-mode)
 
 (defvar whitespace-font-lock nil
   "Used to remember whether a buffer initially had font lock on or not.")
-(make-variable-buffer-local 'whitespace-font-lock)
 
 (defvar whitespace-font-lock-keywords nil
   "Used to save locally `font-lock-keywords' value.")
-(make-variable-buffer-local 'whitespace-font-lock-keywords)
 
 
 (defconst whitespace-help-text
   "\
-      whitespace-mode toggle options:
-
- []  t - toggle TAB visualization
- []  s - toggle SPACE and HARD SPACE visualization
- []  r - toggle trailing blanks visualization
- []  b - toggle SPACEs before TAB visualization
- []  l - toggle \"long lines\" visualization
- []  L - toggle \"long lines\" tail visualization
- []  n - toggle NEWLINE visualization
- []  i - toggle indentation SPACEs visualization
- []  e - toggle empty line at bob and/or eob visualization
- []  a - toggle SPACEs after TAB visualization
-
- []  c - toggle color faces
- []  m - toggle visual mark
-
-      x - restore `whitespace-chars' value
-      z - restore `whitespace-style' value
+ Whitespace Toggle Options
+
+ FACES
+ []  t   - toggle TAB visualization
+ []  s   - toggle SPACE and HARD SPACE visualization
+ []  r   - toggle trailing blanks visualization
+ []  l   - toggle \"long lines\" visualization
+ []  L   - toggle \"long lines\" tail visualization
+ []  n   - toggle NEWLINE visualization
+ []  e   - toggle empty line at bob and/or eob visualization
+ []  C-i - toggle indentation SPACEs visualization (via `indent-tabs-mode')
+ []  I   - toggle indentation SPACEs visualization
+ []  i   - toggle indentation TABs visualization
+ []  C-a - toggle SPACEs after TAB visualization (via `indent-tabs-mode')
+ []  A   - toggle SPACEs after TAB: SPACEs visualization
+ []  a   - toggle SPACEs after TAB: TABs visualization
+ []  C-b - toggle SPACEs before TAB visualization (via `indent-tabs-mode')
+ []  B   - toggle SPACEs before TAB: SPACEs visualization
+ []  b   - toggle SPACEs before TAB: TABs visualization
+
+ DISPLAY TABLE
+ []  T - toggle TAB visualization
+ []  S - toggle SPACE and HARD SPACE visualization
+ []  N - toggle NEWLINE visualization
+
+      x - restore `whitespace-style' value
 
       ? - display this text\n\n"
   "Text for whitespace toggle options.")
@@ -1395,82 +1913,110 @@ cleaning up these problems."
   "The buffer name for whitespace toggle options.")
 
 
+(defun whitespace-insert-value (value)
+  "Insert VALUE at column 20 of next line."
+  (forward-line 1)
+  (move-to-column 20 t)
+  (insert (format "%s" value)))
+
+
+(defun whitespace-mark-x (nchars condition)
+  "Insert the mark ('X' or ' ') after NCHARS depending on CONDITION."
+  (forward-char nchars)
+  (insert (if condition "X" " ")))
+
+
 (defun whitespace-insert-option-mark (the-list the-value)
   "Insert the option mark ('X' or ' ') in toggle options buffer."
-  (forward-line 1)
+  (goto-char (point-min))
+  (forward-line 2)
   (dolist (sym  the-list)
-    (forward-line 1)
-    (forward-char 2)
-    (insert (if (memq sym the-value) "X" " "))))
+    (if (eq sym 'help-newline)
+       (forward-line 2)
+      (forward-line 1)
+      (whitespace-mark-x 2 (memq sym the-value)))))
 
 
-(defun whitespace-help-on (chars style)
+(defun whitespace-help-on (style)
   "Display the whitespace toggle options."
   (unless (get-buffer whitespace-help-buffer-name)
     (delete-other-windows)
     (let ((buffer (get-buffer-create whitespace-help-buffer-name)))
-      (save-excursion
-       (set-buffer buffer)
+      (with-current-buffer buffer
        (erase-buffer)
        (insert whitespace-help-text)
-       (goto-char (point-min))
-       (whitespace-insert-option-mark
-        whitespace-chars-value-list chars)
        (whitespace-insert-option-mark
         whitespace-style-value-list style)
-       (goto-char (point-min))
-       (set-buffer-modified-p nil)
-       (let ((size (- (window-height)
-                      (max window-min-height
-                           (1+ (count-lines (point-min)
-                                            (point-max)))))))
-         (when (<= size 0)
-           (kill-buffer buffer)
-           (error "Frame height is too small; \
+       (whitespace-display-window buffer)))))
+
+
+(defun whitespace-display-window (buffer)
+  "Display BUFFER in a new window."
+  (goto-char (point-min))
+  (set-buffer-modified-p nil)
+  (let ((size (- (window-height)
+                (max window-min-height
+                     (1+ (count-lines (point-min)
+                                      (point-max)))))))
+    (when (<= size 0)
+      (kill-buffer buffer)
+      (error "Frame height is too small; \
 can't split window to display whitespace toggle options"))
-         (set-window-buffer (split-window nil size) buffer))))))
+    (set-window-buffer (split-window nil size) buffer)))
 
 
-(defun whitespace-help-off ()
-  "Remove the buffer and window of the whitespace toggle options."
-  (let ((buffer (get-buffer whitespace-help-buffer-name)))
+(defun whitespace-kill-buffer (buffer-name)
+  "Kill buffer BUFFER-NAME and windows related with it."
+  (let ((buffer (get-buffer buffer-name)))
     (when buffer
       (delete-windows-on buffer)
       (kill-buffer buffer))))
 
 
+(defun whitespace-help-off ()
+  "Remove the buffer and window of the whitespace toggle options."
+  (whitespace-kill-buffer whitespace-help-buffer-name))
+
+
 (defun whitespace-interactive-char (local-p)
   "Interactive function to read a char and return a symbol.
 
 If LOCAL-P is non-nil, it uses a local context; otherwise, it
 uses a global context.
 
-It reads one of the following chars:
+It accepts one of the following chars:
 
   CHAR MEANING
+  (VIA FACES)
    t   toggle TAB visualization
    s   toggle SPACE and HARD SPACE visualization
    r   toggle trailing blanks visualization
-   b   toggle SPACEs before TAB visualization
    l   toggle \"long lines\" visualization
    L   toggle \"long lines\" tail visualization
    n   toggle NEWLINE visualization
-   i   toggle indentation SPACEs visualization
    e   toggle empty line at bob and/or eob visualization
-   a   toggle SPACEs after TAB visualization
-   c   toggle color faces
-   m   toggle visual mark
-   x   restore `whitespace-chars' value
-   z   restore `whitespace-style' value
+   C-i toggle indentation SPACEs visualization (via `indent-tabs-mode')
+   I   toggle indentation SPACEs visualization
+   i   toggle indentation TABs visualization
+   C-a toggle SPACEs after TAB visualization (via `indent-tabs-mode')
+   A   toggle SPACEs after TAB: SPACEs visualization
+   a   toggle SPACEs after TAB: TABs visualization
+   C-b toggle SPACEs before TAB visualization (via `indent-tabs-mode')
+   B   toggle SPACEs before TAB: SPACEs visualization
+   b   toggle SPACEs before TAB: TABs visualization
+
+  (VIA DISPLAY TABLE)
+   T   toggle TAB visualization
+   S   toggle SPACE and HARD SPACE visualization
+   N   toggle NEWLINE visualization
+
+   x   restore `whitespace-style' value
    ?   display brief help
 
 See also `whitespace-toggle-option-alist'."
   (let* ((is-off (not (if local-p
                          whitespace-mode
                        global-whitespace-mode)))
-        (chars  (cond (is-off  whitespace-chars) ; use default value
-                      (local-p whitespace-active-chars)
-                      (t       whitespace-toggle-chars)))
         (style  (cond (is-off  whitespace-style) ; use default value
                       (local-p whitespace-active-style)
                       (t       whitespace-toggle-style)))
@@ -1492,7 +2038,7 @@ See also `whitespace-toggle-option-alist'."
                          (assq ch whitespace-toggle-option-alist)))))
              ;; while body
              (if (eq ch ?\?)
-                 (whitespace-help-on chars style)
+                 (whitespace-help-on style)
                (ding)))
            (whitespace-help-off)
            (message " "))              ; clean echo area
@@ -1503,8 +2049,7 @@ See also `whitespace-toggle-option-alist'."
     (list sym)))                       ; return the apropriate symbol
 
 
-(defun whitespace-toggle-list (local-p arg the-list default-list
-                                      sym-restore sym-list)
+(defun whitespace-toggle-list (local-p arg the-list)
   "Toggle options in THE-LIST based on list ARG.
 
 If LOCAL-P is non-nil, it uses a local context; otherwise, it
@@ -1513,91 +2058,127 @@ uses a global context.
 ARG is a list of options to be toggled.
 
 THE-LIST is a list of options.  This list will be toggled and the
-resultant list will be returned.
-
-DEFAULT-LIST is the default list of options.  It is used to
-restore the options in THE-LIST.
-
-SYM-RESTORE is the symbol which indicates to restore the options
-in THE-LIST.
-
-SYM-LIST is a list of valid options, used to check if the ARG's
-options are valid."
+resultant list will be returned."
   (unless (if local-p whitespace-mode global-whitespace-mode)
-    (setq the-list default-list))
+    (setq the-list whitespace-style))
   (setq the-list (copy-sequence the-list)) ; keep original list
   (dolist (sym (if (listp arg) arg (list arg)))
     (cond
+     ;; ignore help value
+     ((eq sym 'help-newline))
      ;; restore default values
-     ((eq sym sym-restore)
-      (setq the-list default-list))
+     ((eq sym 'whitespace-style)
+      (setq the-list whitespace-style))
      ;; toggle valid values
-     ((memq sym sym-list)
+     ((memq sym whitespace-style-value-list)
       (setq the-list (if (memq sym the-list)
                         (delq sym the-list)
                       (cons sym the-list))))))
   the-list)
 
 
+(defvar whitespace-display-table nil
+  "Used to save a local display table.")
+
+(defvar whitespace-display-table-was-local nil
+  "Used to remember whether a buffer initially had a local display table.")
+
+
 (defun whitespace-turn-on ()
   "Turn on whitespace visualization."
-  (setq whitespace-active-style (if (listp whitespace-style)
-                                   whitespace-style
-                                 (list whitespace-style)))
-  (setq whitespace-active-chars (if (listp whitespace-chars)
-                                   whitespace-chars
-                                 (list whitespace-chars)))
-  (when (memq 'color whitespace-active-style)
-    (whitespace-color-on))
-  (when (memq 'mark  whitespace-active-style)
+  ;; prepare local hooks
+  (add-hook 'write-file-functions 'whitespace-write-file-hook nil t)
+  ;; create whitespace local buffer environment
+  (set (make-local-variable 'whitespace-font-lock-mode) nil)
+  (set (make-local-variable 'whitespace-font-lock) nil)
+  (set (make-local-variable 'whitespace-font-lock-keywords) nil)
+  (set (make-local-variable 'whitespace-display-table) nil)
+  (set (make-local-variable 'whitespace-display-table-was-local) nil)
+  (set (make-local-variable 'whitespace-active-style)
+       (if (listp whitespace-style)
+          whitespace-style
+        (list whitespace-style)))
+  (set (make-local-variable 'whitespace-indent-tabs-mode)
+       indent-tabs-mode)
+  (set (make-local-variable 'whitespace-tab-width)
+       tab-width)
+  ;; turn on whitespace
+  (when whitespace-active-style
+    (whitespace-color-on)
     (whitespace-display-char-on)))
 
 
 (defun whitespace-turn-off ()
-  "Turn off whitesapce visualization."
-  (when (memq 'color whitespace-active-style)
-    (whitespace-color-off))
-  (when (memq 'mark  whitespace-active-style)
+  "Turn off whitespace visualization."
+  (remove-hook 'write-file-functions 'whitespace-write-file-hook t)
+  (when whitespace-active-style
+    (whitespace-color-off)
     (whitespace-display-char-off)))
 
 
+(defun whitespace-style-face-p ()
+  "Return t if there is some visualization via face."
+  (or (memq 'tabs                    whitespace-active-style)
+      (memq 'spaces                  whitespace-active-style)
+      (memq 'trailing                whitespace-active-style)
+      (memq 'lines                   whitespace-active-style)
+      (memq 'lines-tail              whitespace-active-style)
+      (memq 'newline                 whitespace-active-style)
+      (memq 'empty                   whitespace-active-style)
+      (memq 'indentation             whitespace-active-style)
+      (memq 'indentation::tab        whitespace-active-style)
+      (memq 'indentation::space      whitespace-active-style)
+      (memq 'space-after-tab         whitespace-active-style)
+      (memq 'space-after-tab::tab    whitespace-active-style)
+      (memq 'space-after-tab::space  whitespace-active-style)
+      (memq 'space-before-tab        whitespace-active-style)
+      (memq 'space-before-tab::tab   whitespace-active-style)
+      (memq 'space-before-tab::space whitespace-active-style)))
+
+
 (defun whitespace-color-on ()
   "Turn on color visualization."
-  (when whitespace-active-chars
+  (when (whitespace-style-face-p)
     (unless whitespace-font-lock
       (setq whitespace-font-lock t
            whitespace-font-lock-keywords
            (copy-sequence font-lock-keywords)))
+    ;; save current point and refontify when necessary
+    (set (make-local-variable 'whitespace-point)
+        (point))
+    (set (make-local-variable 'whitespace-font-lock-refontify)
+        nil)
+    (add-hook 'post-command-hook #'whitespace-post-command-hook nil t)
     ;; turn off font lock
-    (setq whitespace-font-lock-mode font-lock-mode)
+    (set (make-local-variable 'whitespace-font-lock-mode)
+        font-lock-mode)
     (font-lock-mode 0)
     ;; add whitespace-mode color into font lock
-    (when (memq 'spaces whitespace-active-chars)
+    (when (memq 'spaces whitespace-active-style)
       (font-lock-add-keywords
        nil
        (list
        ;; Show SPACEs
-       (list whitespace-space-regexp  1 whitespace-space  t)
+       (list #'whitespace-space-regexp  1 whitespace-space  t)
        ;; Show HARD SPACEs
        (list whitespace-hspace-regexp 1 whitespace-hspace t))
        t))
-    (when (memq 'tabs whitespace-active-chars)
+    (when (memq 'tabs whitespace-active-style)
       (font-lock-add-keywords
        nil
        (list
        ;; Show TABs
-       (list whitespace-tab-regexp 1 whitespace-tab t))
+       (list #'whitespace-tab-regexp 1 whitespace-tab t))
        t))
-    (when (memq 'trailing whitespace-active-chars)
+    (when (memq 'trailing whitespace-active-style)
       (font-lock-add-keywords
        nil
        (list
        ;; Show trailing blanks
-       (list (concat "\\(\\(" whitespace-trailing-regexp "\\)+\\)$")
-             1 whitespace-trailing t))
+       (list #'whitespace-trailing-regexp 1 whitespace-trailing t))
        t))
-    (when (or (memq 'lines      whitespace-active-chars)
-             (memq 'lines-tail whitespace-active-chars))
+    (when (or (memq 'lines      whitespace-active-style)
+             (memq 'lines-tail whitespace-active-style))
       (font-lock-add-keywords
        nil
        (list
@@ -1605,89 +2186,187 @@ options are valid."
        (list
         (format
          "^\\([^\t\n]\\{%s\\}\\|[^\t\n]\\{0,%s\\}\t\\)\\{%d\\}%s\\(.+\\)$"
-         tab-width (1- tab-width)
-         (/ whitespace-line-column tab-width)
-         (let ((rem (% whitespace-line-column tab-width)))
+         whitespace-tab-width (1- whitespace-tab-width)
+         (/ whitespace-line-column whitespace-tab-width)
+         (let ((rem (% whitespace-line-column whitespace-tab-width)))
            (if (zerop rem)
                ""
              (format ".\\{%d\\}" rem))))
-        (if (memq 'lines whitespace-active-chars)
+        (if (memq 'lines whitespace-active-style)
             0                          ; whole line
           2)                           ; line tail
         whitespace-line t))
        t))
-    (when (memq 'space-before-tab whitespace-active-chars)
+    (cond
+     ((memq 'space-before-tab whitespace-active-style)
+      (font-lock-add-keywords
+       nil
+       (list
+       ;; Show SPACEs before TAB (indent-tabs-mode)
+       (list whitespace-space-before-tab-regexp
+             (if whitespace-indent-tabs-mode 1 2)
+             whitespace-space-before-tab t))
+       t))
+     ((memq 'space-before-tab::tab whitespace-active-style)
       (font-lock-add-keywords
        nil
        (list
-       ;; Show SPACEs before TAB
+       ;; Show SPACEs before TAB (SPACEs)
        (list whitespace-space-before-tab-regexp
              1 whitespace-space-before-tab t))
        t))
-    (when (memq 'indentation whitespace-active-chars)
+     ((memq 'space-before-tab::space whitespace-active-style)
       (font-lock-add-keywords
        nil
        (list
-       ;; Show indentation SPACEs
-       (list whitespace-indentation-regexp
+       ;; Show SPACEs before TAB (TABs)
+       (list whitespace-space-before-tab-regexp
+             2 whitespace-space-before-tab t))
+       t)))
+    (cond
+     ((memq 'indentation whitespace-active-style)
+      (font-lock-add-keywords
+       nil
+       (list
+       ;; Show indentation SPACEs (indent-tabs-mode)
+       (list (whitespace-indentation-regexp)
              1 whitespace-indentation t))
        t))
-    (when (memq 'empty whitespace-active-chars)
+     ((memq 'indentation::tab whitespace-active-style)
+      (font-lock-add-keywords
+       nil
+       (list
+       ;; Show indentation SPACEs (SPACEs)
+       (list (whitespace-indentation-regexp 'tab)
+             1 whitespace-indentation t))
+       t))
+     ((memq 'indentation::space whitespace-active-style)
+      (font-lock-add-keywords
+       nil
+       (list
+       ;; Show indentation SPACEs (TABs)
+       (list (whitespace-indentation-regexp 'space)
+             1 whitespace-indentation t))
+       t)))
+    (when (memq 'empty whitespace-active-style)
       (font-lock-add-keywords
        nil
        (list
        ;; Show empty lines at beginning of buffer
-       (list whitespace-empty-at-bob-regexp
+       (list #'whitespace-empty-at-bob-regexp
              1 whitespace-empty t))
        t)
       (font-lock-add-keywords
        nil
        (list
        ;; Show empty lines at end of buffer
-       (list whitespace-empty-at-eob-regexp
+       (list #'whitespace-empty-at-eob-regexp
              1 whitespace-empty t))
        t))
-    (when (memq 'space-after-tab whitespace-active-chars)
+    (cond
+     ((memq 'space-after-tab whitespace-active-style)
+      (font-lock-add-keywords
+       nil
+       (list
+       ;; Show SPACEs after TAB (indent-tabs-mode)
+       (list (whitespace-space-after-tab-regexp)
+             1 whitespace-space-after-tab t))
+       t))
+     ((memq 'space-after-tab::tab whitespace-active-style)
       (font-lock-add-keywords
        nil
        (list
-       ;; Show SPACEs after TAB
-       (list whitespace-space-after-tab-regexp
+       ;; Show SPACEs after TAB (SPACEs)
+       (list (whitespace-space-after-tab-regexp 'tab)
              1 whitespace-space-after-tab t))
        t))
+     ((memq 'space-after-tab::space whitespace-active-style)
+      (font-lock-add-keywords
+       nil
+       (list
+       ;; Show SPACEs after TAB (TABs)
+       (list (whitespace-space-after-tab-regexp 'space)
+             1 whitespace-space-after-tab t))
+       t)))
     ;; now turn on font lock and highlight blanks
     (font-lock-mode 1)))
 
 
 (defun whitespace-color-off ()
   "Turn off color visualization."
-  (when whitespace-active-chars
-    ;; turn off font lock
+  ;; turn off font lock
+  (when (whitespace-style-face-p)
     (font-lock-mode 0)
+    (remove-hook 'post-command-hook #'whitespace-post-command-hook)
     (when whitespace-font-lock
       (setq whitespace-font-lock nil
            font-lock-keywords   whitespace-font-lock-keywords))
     ;; restore original font lock state
     (font-lock-mode whitespace-font-lock-mode)))
 
+
+(defun whitespace-trailing-regexp (limit)
+  "Match trailing spaces which do not contain the point at end of line."
+  (let ((status t))
+    (while (if (re-search-forward whitespace-trailing-regexp limit t)
+              (save-match-data
+                (= whitespace-point (match-end 1))) ;; loop if point at eol
+            (setq status nil)))                     ;; end of buffer
+    status))
+
+
+(defun whitespace-empty-at-bob-regexp (limit)
+  "Match spaces at beginning of buffer which do not contain the point at \
+beginning of buffer."
+  (and (/= whitespace-point 1)
+       (re-search-forward whitespace-empty-at-bob-regexp limit t)))
+
+
+(defun whitespace-empty-at-eob-regexp (limit)
+  "Match spaces at end of buffer which do not contain the point at end of \
+buffer."
+  (and (/= whitespace-point (1+ (buffer-size)))
+       (re-search-forward whitespace-empty-at-eob-regexp limit t)))
+
+
+(defun whitespace-space-regexp (limit)
+  "Match spaces."
+  (setq whitespace-font-lock-refontify t)
+  (re-search-forward whitespace-space-regexp limit t))
+
+
+(defun whitespace-tab-regexp (limit)
+  "Match tabs."
+  (setq whitespace-font-lock-refontify t)
+  (re-search-forward whitespace-tab-regexp limit t))
+
+
+(defun whitespace-post-command-hook ()
+  "Save current point into `whitespace-point' variable.
+Also refontify when necessary."
+  (setq whitespace-point (point))
+  (let ((refontify (or (eolp)                   ; end of line
+                      (= whitespace-point 1)))) ; beginning of buffer
+    (when (or whitespace-font-lock-refontify refontify)
+      (setq whitespace-font-lock-refontify refontify)
+      (jit-lock-refontify))))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;; Hacked from visws.el (Miles Bader <miles@gnu.org>)
 
 
-(defvar whitespace-display-table nil
-  "Used to save a local display table.")
-(make-variable-buffer-local 'whitespace-display-table)
-
-(defvar whitespace-display-table-was-local nil
-  "Used to remember whether a buffer initially had a local display table.")
-(make-variable-buffer-local 'whitespace-display-table-was-local)
+(defun whitespace-style-mark-p ()
+  "Return t if there is some visualization via display table."
+  (or (memq 'tab-mark     whitespace-active-style)
+      (memq 'space-mark   whitespace-active-style)
+      (memq 'newline-mark whitespace-active-style)))
 
 
 (defsubst whitespace-char-valid-p (char)
   ;; This check should be improved!!!
   (or (< char 256)
-      (char-valid-p char)))
+      (characterp char)))
 
 
 (defun whitespace-display-vector-p (vec)
@@ -1701,60 +2380,97 @@ options are valid."
 
 (defun whitespace-display-char-on ()
   "Turn on character display mapping."
-  (when whitespace-display-mappings
+  (when (and whitespace-display-mappings
+            (whitespace-style-mark-p))
     (let (vecs vec)
       ;; Remember whether a buffer has a local display table.
       (unless whitespace-display-table-was-local
        (setq whitespace-display-table-was-local t
              whitespace-display-table
              (copy-sequence buffer-display-table)))
+      ;; asure `buffer-display-table' is unique
+      ;; when two or more windows are visible.
+      (set (make-local-variable 'buffer-display-table)
+          (copy-sequence buffer-display-table))
       (unless buffer-display-table
        (setq buffer-display-table (make-display-table)))
       (dolist (entry whitespace-display-mappings)
-       (setq vecs (cdr entry))
-       ;; Get a displayable mapping.
-       (while (and vecs
-                   (not (whitespace-display-vector-p (car vecs))))
-         (setq vecs (cdr vecs)))
-       ;; Display a valid mapping.
-       (when vecs
-         (setq vec (copy-sequence (car vecs)))
-         (cond
-          ;; Any char except newline
-          ((not (eq (car entry) ?\n))
-           (aset buffer-display-table (car entry) vec))
-          ;; Newline char - display it
-          ((memq 'newline whitespace-active-chars)
-           ;; Only insert face bits on NEWLINE char mapping to avoid
-           ;; obstruction of other faces like TABs and (HARD) SPACEs
-           ;; faces, font-lock faces, etc.
-           (when (memq 'color whitespace-active-style)
+       ;; check if it is to display this mark
+       (when (memq (car entry) whitespace-style)
+         ;; Get a displayable mapping.
+         (setq vecs (cddr entry))
+         (while (and vecs
+                     (not (whitespace-display-vector-p (car vecs))))
+           (setq vecs (cdr vecs)))
+         ;; Display a valid mapping.
+         (when vecs
+           (setq vec (copy-sequence (car vecs)))
+           ;; NEWLINE char
+           (when (and (eq (cadr entry) ?\n)
+                      (memq 'newline whitespace-active-style))
+             ;; Only insert face bits on NEWLINE char mapping to avoid
+             ;; obstruction of other faces like TABs and (HARD) SPACEs
+             ;; faces, font-lock faces, etc.
              (dotimes (i (length vec))
-               ;; Due to limitations of glyph representation, the char
-               ;; code can not be above ?\x1FFFF.  Probably, this will
-               ;; be fixed after Emacs unicode merging.
                (or (eq (aref vec i) ?\n)
-                   (> (aref vec i) #x1FFFF)
                    (aset vec i
                          (make-glyph-code (aref vec i)
                                           whitespace-newline)))))
            ;; Display mapping
-           (aset buffer-display-table (car entry) vec))
-          ;; Newline char - don't display it
-          (t
-           ;; Do nothing
-           )))))))
+           (aset buffer-display-table (cadr entry) vec)))))))
 
 
 (defun whitespace-display-char-off ()
   "Turn off character display mapping."
   (and whitespace-display-mappings
+       (whitespace-style-mark-p)
        whitespace-display-table-was-local
        (setq whitespace-display-table-was-local nil
             buffer-display-table whitespace-display-table)))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Hook
+
+
+(defun whitespace-action-when-on ()
+  "Action to be taken always when local whitespace is turned on."
+  (cond ((memq 'cleanup whitespace-action)
+        (whitespace-cleanup))
+       ((memq 'report-on-bogus whitespace-action)
+        (whitespace-report nil t))))
+
+
+(defun whitespace-write-file-hook ()
+  "Action to be taken when buffer is written.
+It should be added buffer-locally to `write-file-functions'."
+  (cond ((memq 'auto-cleanup whitespace-action)
+        (whitespace-cleanup))
+       ((memq 'abort-on-bogus whitespace-action)
+        (when (whitespace-report nil t)
+          (error "Abort write due to whitespace problems in %s"
+                 (buffer-name)))))
+  nil)                                 ; continue hook processing
+
+
+(defun whitespace-warn-read-only (msg)
+  "Warn if buffer is read-only."
+  (when (memq 'warn-if-read-only whitespace-action)
+    (message "Can't %s: %s is read-only" msg (buffer-name))))
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defun whitespace-unload-function ()
+  "Unload the whitespace library."
+  (global-whitespace-mode -1)
+  ;; be sure all local whitespace mode is turned off
+  (save-current-buffer
+    (dolist (buf (buffer-list))
+      (set-buffer buf)
+      (whitespace-mode -1)))
+  nil)                                 ; continue standard unloading
 
 
 (provide 'whitespace)
@@ -1763,5 +2479,5 @@ options are valid."
 (run-hooks 'whitespace-load-hook)
 
 
-;; arch-tag: f1601e44-15a3-45d1-b4f8-b3ca8ae24242
+;; arch-tag: 1b1e2500-dbd4-4a26-8f7a-5a5edfd3c97e
 ;;; whitespace.el ends here