(x_new_font): Update f->scroll_bar_actual_width.
[bpt/emacs.git] / lisp / whitespace.el
index 4e5b33b..492712e 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
 ;;   Free Software Foundation, Inc.
 
 ;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
 ;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
 ;; Keywords: data, wp
-;; Version: 11.1
+;; Version: 12.0
 ;; 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:
 
 ;; 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.
 ;;
 ;; 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.
 ;;
 ;;                             turned on.
 ;;
 ;; `whitespace-action'         Specify which action is taken when a
-;;                             buffer is visited, killed or written.
+;;                             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 or killed as the original whitespace
-;; package had.
+;; 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.
   '(tabs spaces trailing lines space-before-tab newline
         indentation empty space-after-tab
         space-mark tab-mark newline-mark)
-  "*Specify which kind of blank is visualized.
+  "Specify which kind of blank is visualized.
 
 It's a list containing some or all of the following values:
 
@@ -418,8 +431,8 @@ It's a list containing some or all of the following values:
    space-after-tab::tab                8 or more SPACEs after a TAB are
                                visualized via faces.
 
-   space-after-tab::space      TABs are visualized when occurs 8 or
-                               more SPACEs after a TAB 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'
@@ -429,8 +442,8 @@ It's a list containing some or all of the following values:
    space-before-tab::tab       SPACEs before TAB are visualized via
                                faces.
 
-   space-before-tab::space     TABs are visualized when occurs SPACEs
-                               before TAB 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
@@ -500,7 +513,7 @@ See also `whitespace-display-mappings' for documentation."
 
 
 (defcustom whitespace-space 'whitespace-space
-  "*Symbol face used to visualize SPACE.
+  "Symbol face used to visualize SPACE.
 
 Used when `whitespace-style' includes the value `spaces'."
   :type 'face
@@ -518,7 +531,7 @@ Used when `whitespace-style' includes the value `spaces'."
 
 
 (defcustom whitespace-hspace 'whitespace-hspace
-  "*Symbol face used to visualize HARD SPACE.
+  "Symbol face used to visualize HARD SPACE.
 
 Used when `whitespace-style' includes the value `spaces'."
   :type 'face
@@ -536,7 +549,7 @@ Used when `whitespace-style' includes the value `spaces'."
 
 
 (defcustom whitespace-tab 'whitespace-tab
-  "*Symbol face used to visualize TAB.
+  "Symbol face used to visualize TAB.
 
 Used when `whitespace-style' includes the value `tabs'."
   :type 'face
@@ -554,7 +567,7 @@ Used when `whitespace-style' includes the value `tabs'."
 
 
 (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'.
 
@@ -566,10 +579,10 @@ and `newline'."
 
 (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'."
@@ -577,7 +590,7 @@ See `whitespace-display-mappings'."
 
 
 (defcustom whitespace-trailing 'whitespace-trailing
-  "*Symbol face used to visualize trailing blanks.
+  "Symbol face used to visualize trailing blanks.
 
 Used when `whitespace-style' includes the value `trailing'."
   :type 'face
@@ -592,7 +605,7 @@ Used when `whitespace-style' includes the value `trailing'."
 
 
 (defcustom whitespace-line 'whitespace-line
-  "*Symbol face used to visualize \"long\" lines.
+  "Symbol face used to visualize \"long\" lines.
 
 See `whitespace-line-column'.
 
@@ -611,7 +624,7 @@ 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' includes the value `space-before-tab'."
   :type 'face
@@ -626,7 +639,7 @@ Used when `whitespace-style' includes the value `space-before-tab'."
 
 
 (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' includes the value `indentation'."
   :type 'face
@@ -641,7 +654,7 @@ Used when `whitespace-style' includes the value `indentation'."
 
 
 (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' includes the value `empty'."
   :type 'face
@@ -656,7 +669,7 @@ Used when `whitespace-style' includes the value `empty'."
 
 
 (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' includes the value `space-after-tab'."
   :type 'face
@@ -672,7 +685,7 @@ Used when `whitespace-style' includes the value `space-after-tab'."
 
 (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, there may be other characters besides:
 
@@ -700,7 +713,7 @@ Used when `whitespace-style' includes `spaces'."
 
 
 (defcustom whitespace-space-regexp "\\( +\\)"
-  "*Specify SPACE characters regexp.
+  "Specify SPACE characters regexp.
 
 If you're using `mule' package, there may be other characters
 besides \" \" that should be considered SPACE.
@@ -722,7 +735,7 @@ Used when `whitespace-style' includes `spaces'."
 
 
 (defcustom whitespace-tab-regexp "\\(\t+\\)"
-  "*Specify TAB characters regexp.
+  "Specify TAB characters regexp.
 
 If you're using `mule' package, there may be other characters
 besides \"\\t\" that should be considered TAB.
@@ -745,7 +758,7 @@ Used when `whitespace-style' includes `tabs'."
 
 (defcustom whitespace-trailing-regexp
   "\\(\\(\t\\| \\|\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)$"
-  "*Specify trailing characters regexp.
+  "Specify trailing characters regexp.
 
 If you're using `mule' package, there may be other characters besides:
 
@@ -763,7 +776,7 @@ Used when `whitespace-style' includes `trailing'."
 
 
 (defcustom whitespace-space-before-tab-regexp "\\( +\\)\\(\t+\\)"
-  "*Specify SPACEs before TAB regexp.
+  "Specify SPACEs before TAB regexp.
 
 If you're using `mule' package, there may be other characters besides:
 
@@ -781,7 +794,7 @@ Used when `whitespace-style' includes `space-before-tab',
 (defcustom whitespace-indentation-regexp
   '("^\t*\\(\\( \\{%d\\}\\)+\\)[^\n\t]"
     . "^ *\\(\t+\\)[^\n]")
-  "*Specify regexp for 8 or more SPACEs at beginning of line.
+  "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.
@@ -801,7 +814,7 @@ Used when `whitespace-style' includes `indentation',
 
 
 (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, there may be other characters besides:
 
@@ -816,7 +829,7 @@ Used when `whitespace-style' includes `empty'."
 
 
 (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, there may be other characters besides:
 
@@ -833,7 +846,7 @@ Used when `whitespace-style' includes `empty'."
 (defcustom whitespace-space-after-tab-regexp
   '("\t+\\(\\( \\{%d\\}\\)+\\)"
     . "\\(\t+\\) +")
-  "*Specify regexp for 8 or more SPACEs after TAB.
+  "Specify regexp for 8 or more SPACEs after TAB.
 
 It is a cons where the cons car is used for SPACEs visualization
 and the cons cdr is used for TABs visualization.
@@ -852,7 +865,7 @@ Used when `whitespace-style' includes `space-after-tab',
 
 
 (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' includes `lines' or `lines-tail'."
   :type '(integer :tag "Line Length")
@@ -862,8 +875,8 @@ Used when `whitespace-style' includes `lines' or `lines-tail'."
 ;; Hacked from `visible-whitespace-mappings' in visws.el
 (defcustom whitespace-display-mappings
   '(
-    (space-mark   ?\     [?\xB7]       [?.])           ; space - centered dot
-    (space-mark   ?\xA0  [?\xA4]       [?_])           ; 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
@@ -871,7 +884,7 @@ Used when `whitespace-style' includes `lines' or `lines-tail'."
     ;; NEWLINE is displayed using the face `whitespace-newline'
     (newline-mark ?\n    [?$ ?\n])                     ; eol - dollar sign
     ;; (newline-mark ?\n    [?\u21B5 ?\n] [?$ ?\n])    ; eol - downwards arrow
-    ;; (newline-mark ?\n    [?\xB6 ?\n]   [?$ ?\n])    ; eol - pilcrow
+    ;; (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
@@ -881,9 +894,9 @@ Used when `whitespace-style' includes `lines' or `lines-tail'."
     ;; 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.
-    (tab-mark     ?\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:
 
@@ -928,7 +941,7 @@ Used when `whitespace-style' includes `tab-mark', `space-mark' or
 
 
 (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'.
@@ -959,7 +972,7 @@ C++ modes only."
 
 
 (defcustom whitespace-action nil
-  "*Specify which action is taken when a buffer is visited, killed or written.
+  "Specify which action is taken when a buffer is visited or written.
 
 It's a list containing some or all of the following values:
 
@@ -974,12 +987,16 @@ It's a list containing some or all of the following values:
                        when local whitespace is turned on.
 
    auto-cleanup                cleanup any bogus whitespace when buffer is
-                       written or killed.
+                       written.
                        See `whitespace-cleanup' and
                        `whitespace-cleanup-region'.
 
    abort-on-bogus      abort if there is any bogus whitespace and the
-                       buffer is written or killed.
+                       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"
@@ -989,7 +1006,8 @@ Any other value is treated as nil."
                          (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 "Abort On Bogus" abort-on-bogus)
+                         (const :tag "Warn If Read-Only" warn-if-read-only))))
   :group 'whitespace)
 
 \f
@@ -1004,7 +1022,9 @@ Any other value is treated as nil."
 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
@@ -1018,6 +1038,30 @@ Only useful with a windowing system."
    (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
@@ -1030,7 +1074,9 @@ Only useful with a windowing system."
 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     t
@@ -1076,6 +1122,30 @@ 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
@@ -1151,6 +1221,14 @@ SYMBOL   is a valid symbol associated with CHAR.
 (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
 (defun whitespace-toggle-options (arg)
@@ -1217,8 +1295,6 @@ The valid symbols are:
 
    whitespace-style    restore `whitespace-style' value
 
-Only useful with a windowing system.
-
 See `whitespace-style' and `indent-tabs-mode' for documentation."
   (interactive (whitespace-interactive-char t))
   (let ((whitespace-style
@@ -1296,8 +1372,6 @@ The valid symbols are:
 
    whitespace-style    restore `whitespace-style' value
 
-Only useful with a windowing system.
-
 See `whitespace-style' and `indent-tabs-mode' for documentation."
   (interactive (whitespace-interactive-char nil))
   (let ((whitespace-style
@@ -1317,7 +1391,7 @@ See `whitespace-style' and `indent-tabs-mode' for documentation."
 
 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
+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.
 
@@ -1364,18 +1438,23 @@ The problems cleaned up are:
 
 See `whitespace-style', `indent-tabs-mode' and `tab-width' for
 documentation."
-  (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
+  (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
@@ -1394,7 +1473,7 @@ documentation."
     ;; 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))))
+    (whitespace-cleanup-region (point-min) (point-max)))))
 
 
 ;;;###autoload
@@ -1437,85 +1516,89 @@ The problems cleaned up are:
 
 See `whitespace-style', `indent-tabs-mode' and `tab-width' for
 documentation."
-  (interactive "@*r")
-  (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
+  (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)
@@ -1859,8 +1942,7 @@ cleaning up these problems."
   (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)
        (whitespace-insert-option-mark
@@ -2005,7 +2087,7 @@ resultant list will be returned."
 (defun whitespace-turn-on ()
   "Turn on whitespace visualization."
   ;; prepare local hooks
-  (whitespace-add-local-hook)
+  (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)
@@ -2028,7 +2110,7 @@ resultant list will be returned."
 
 (defun whitespace-turn-off ()
   "Turn off whitespace visualization."
-  (whitespace-remove-local-hook)
+  (remove-hook 'write-file-functions 'whitespace-write-file-hook t)
   (when whitespace-active-style
     (whitespace-color-off)
     (whitespace-display-char-off)))
@@ -2061,6 +2143,12 @@ resultant list will be returned."
       (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
     (set (make-local-variable 'whitespace-font-lock-mode)
         font-lock-mode)
@@ -2071,7 +2159,7 @@ resultant list will be returned."
        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))
@@ -2080,14 +2168,14 @@ resultant list will be returned."
        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-style)
       (font-lock-add-keywords
        nil
        (list
        ;; Show trailing blanks
-       (list whitespace-trailing-regexp 1 whitespace-trailing t))
+       (list #'whitespace-trailing-regexp 1 whitespace-trailing t))
        t))
     (when (or (memq 'lines      whitespace-active-style)
              (memq 'lines-tail whitespace-active-style))
@@ -2099,7 +2187,7 @@ resultant list will be returned."
         (format
          "^\\([^\t\n]\\{%s\\}\\|[^\t\n]\\{0,%s\\}\t\\)\\{%d\\}%s\\(.+\\)$"
          whitespace-tab-width (1- whitespace-tab-width)
-         (/ whitespace-line-column tab-width)
+         (/ whitespace-line-column whitespace-tab-width)
          (let ((rem (% whitespace-line-column whitespace-tab-width)))
            (if (zerop rem)
                ""
@@ -2165,14 +2253,14 @@ resultant list will be returned."
        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))
     (cond
@@ -2209,12 +2297,60 @@ resultant list will be returned."
   ;; 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>)
@@ -2301,44 +2437,22 @@ resultant list will be returned."
         (whitespace-report nil t))))
 
 
-(defun whitespace-add-local-hook ()
-  "Add some whitespace hooks locally."
-  (add-hook 'write-file-functions 'whitespace-write-file-hook nil t)
-  (add-hook 'kill-buffer-hook 'whitespace-kill-buffer-hook nil t))
-
-
-(defun whitespace-remove-local-hook ()
-  "Remove some whitespace hooks locally."
-  (remove-hook 'write-file-functions 'whitespace-write-file-hook t)
-  (remove-hook 'kill-buffer-hook 'whitespace-kill-buffer-hook t))
-
-
 (defun whitespace-write-file-hook ()
   "Action to be taken when buffer is written.
 It should be added buffer-locally to `write-file-functions'."
-  (when (whitespace-action)
-    (error "Abort write due to whitespace problems in %s"
-          (buffer-name)))
-  nil)                                 ; continue hook processing
-
-
-(defun whitespace-kill-buffer-hook ()
-  "Action to be taken when buffer is killed.
-It should be added buffer-locally to `kill-buffer-hook'."
-  (whitespace-action)
+  (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-action ()
-  "Action to be taken when buffer is killed or written.
-Return t when the action should be aborted."
-  (cond ((memq 'auto-cleanup whitespace-action)
-        (whitespace-cleanup)
-        nil)
-       ((memq 'abort-on-bogus whitespace-action)
-        (whitespace-report nil t))
-       (t
-        nil)))
+(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
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;