]> code.delx.au - gnu-emacs/blobdiff - lisp/whitespace.el
Merge changes from emacs-23 branch
[gnu-emacs] / lisp / whitespace.el
index 7360ccad92c847b91eb7ec914f13d68c76b5cec6..8d25a161b47a8ad37307d2ed95126e68cbf53e85 100644 (file)
@@ -1,12 +1,11 @@
 ;;; whitespace.el --- minor mode to visualize TAB, (HARD) SPACE, NEWLINE
 
-;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 2000-2011  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.2.2
+;; Version: 13.2
 ;; X-URL: http://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
 
 ;; This file is part of GNU Emacs.
 ;; 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.
@@ -85,7 +89,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
   "Visualize blanks (TAB, (HARD) SPACE and NEWLINE)."
   :link '(emacs-library-link :tag "Source Lisp File" "whitespace.el")
   :version "23.1"
-  :group 'wp
-  :group 'data)
+  :group 'convenience)
 
 
 (defcustom whitespace-style
-  '(tabs spaces trailing lines space-before-tab newline
-        indentation empty space-after-tab
-        space-mark tab-mark newline-mark)
+  '(face
+    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.
 
 It's a list containing some or all of the following values:
 
+   face                        enable all visualization via faces (see below).
+
    trailing            trailing blanks are visualized via faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
    tabs                        TABs are visualized via faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
    spaces              SPACEs and HARD SPACEs are visualized via
                        faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
-   lines               lines whose have columns beyond
+   lines               lines which have columns beyond
                        `whitespace-line-column' are highlighted via
-                       faces .
+                       faces.
                        Whole line is highlighted.
                        It has precedence over `lines-tail' (see
                        below).
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
-   lines-tail          lines whose have columns beyond
+   lines-tail          lines which have columns beyond
                        `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-style'.
+                       is not present in `whitespace-style'
+                       and if `face' (see above) is present in
+                       `whitespace-style'.
 
    newline             NEWLINEs are visualized via faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
    empty               empty lines at beginning and/or end of buffer
                        are visualized via faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
    indentation::tab    8 or more SPACEs at beginning of line are
                        visualized via faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
    indentation::space  TABs at beginning of line are visualized via
                        faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
    indentation         8 or more SPACEs at beginning of line are
                        visualized, if `indent-tabs-mode' (which see)
                        is non-nil; otherwise, TABs at beginning of
                        line are visualized via faces.
+                       It has effect only if `face' (see above)
+                       is present in `whitespace-style'.
 
    space-after-tab::tab                8 or more SPACEs after a TAB are
                                visualized via faces.
+                               It has effect only if `face' (see above)
+                               is present in `whitespace-style'.
 
    space-after-tab::space      TABs are visualized when 8 or more
                                SPACEs occur after a TAB, via faces.
+                               It has effect only if `face' (see above)
+                               is present in `whitespace-style'.
 
    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.
+                               It has effect only if `face' (see above)
+                               is present in `whitespace-style'.
 
    space-before-tab::tab       SPACEs before TAB are visualized via
                                faces.
+                               It has effect only if `face' (see above)
+                               is present in `whitespace-style'.
 
    space-before-tab::space     TABs are visualized when SPACEs occur
                                before TAB, via faces.
+                               It has effect only if `face' (see above)
+                               is present in `whitespace-style'.
 
    space-before-tab            SPACEs before TAB are visualized, if
                                `indent-tabs-mode' (which see) is
                                non-nil; otherwise, the TABs are
                                visualized via faces.
+                               It has effect only if `face' (see above)
+                               is present in `whitespace-style'.
 
    space-mark          SPACEs and HARD SPACEs are visualized via
                        display table.
@@ -457,7 +495,7 @@ Any other value is ignored.
 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
+There is an evaluation order for some values, if they 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
@@ -482,9 +520,16 @@ So, for example, if indentation and indentation::space are
 included in `whitespace-style' list, the indentation value is
 evaluated instead of indentation::space value.
 
+One reason for not visualize spaces via faces (if `face' is not
+included in `whitespace-style') is to use exclusively for
+cleanning up a buffer.  See `whitespace-cleanup' and
+`whitespace-cleanup-region' for documentation.
+
 See also `whitespace-display-mappings' for documentation."
   :type '(repeat :tag "Kind of Blank"
                 (choice :tag "Kind of Blank Face"
+                        (const :tag "(Face) Face visualization"
+                               face)
                         (const :tag "(Face) Trailing TABs, SPACEs and HARD SPACEs"
                                trailing)
                         (const :tag "(Face) SPACEs and HARD SPACEs"
@@ -517,9 +562,9 @@ Used when `whitespace-style' includes the value `spaces'."
 
 (defface whitespace-space
   '((((class color) (background dark))
-     (:background "grey20"      :foreground "aquamarine3"))
+     (:background "grey20"      :foreground "darkgray"))
     (((class color) (background light))
-     (:background "LightYellow" :foreground "aquamarine3"))
+     (:background "LightYellow" :foreground "lightgray"))
     (t (:inverse-video t)))
   "Face used to visualize SPACE."
   :group 'whitespace)
@@ -535,9 +580,9 @@ Used when `whitespace-style' includes the value `spaces'."
 
 (defface whitespace-hspace             ; 'nobreak-space
   '((((class color) (background dark))
-     (:background "grey24"        :foreground "aquamarine3"))
+     (:background "grey24"        :foreground "darkgray"))
     (((class color) (background light))
-     (:background "LemonChiffon3" :foreground "aquamarine3"))
+     (:background "LemonChiffon3" :foreground "lightgray"))
     (t (:inverse-video t)))
   "Face used to visualize HARD SPACE."
   :group 'whitespace)
@@ -553,9 +598,9 @@ Used when `whitespace-style' includes the value `tabs'."
 
 (defface whitespace-tab
   '((((class color) (background dark))
-     (:background "grey22" :foreground "aquamarine3"))
+     (:background "grey22" :foreground "darkgray"))
     (((class color) (background light))
-     (:background "beige"  :foreground "aquamarine3"))
+     (:background "beige"  :foreground "lightgray"))
     (t (:inverse-video t)))
   "Face used to visualize TAB."
   :group 'whitespace)
@@ -808,7 +853,7 @@ Used when `whitespace-style' includes `indentation',
   :group 'whitespace)
 
 
-(defcustom whitespace-empty-at-bob-regexp "\\`\\(\\([ \t]*\n\\)+\\)"
+(defcustom whitespace-empty-at-bob-regexp "^\\(\\([ \t]*\n\\)+\\)"
   "Specify regexp for empty lines at beginning of buffer.
 
 If you're using `mule' package, there may be other characters besides:
@@ -823,7 +868,7 @@ Used when `whitespace-style' includes `empty'."
   :group 'whitespace)
 
 
-(defcustom whitespace-empty-at-eob-regexp "^\\([ \t\n]+\\)\\'"
+(defcustom whitespace-empty-at-eob-regexp "^\\([ \t\n]+\\)"
   "Specify regexp for empty lines at end of buffer.
 
 If you're using `mule' package, there may be other characters besides:
@@ -862,16 +907,21 @@ Used when `whitespace-style' includes `space-after-tab',
 (defcustom whitespace-line-column 80
   "Specify column beyond which the line is highlighted.
 
+It must be an integer or nil.  If nil, the `fill-column' variable value is
+used.
+
 Used when `whitespace-style' includes `lines' or `lines-tail'."
-  :type '(integer :tag "Line Length")
+  :type '(choice :tag "Line Length Limit"
+                (integer :tag "Line Length")
+                (const :tag "Use fill-column" nil))
   :group 'whitespace)
 
 
 ;; 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
@@ -879,7 +929,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
@@ -889,7 +939,7 @@ 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.
 
@@ -1017,7 +1067,6 @@ 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'."
@@ -1042,7 +1091,6 @@ See also `whitespace-style', `whitespace-newline' and
 If ARG is null, toggle NEWLINE visualization.
 If ARG is a number greater than zero, turn on visualization;
 otherwise, turn off visualization.
-Only useful with a windowing system.
 
 Use `whitespace-newline-mode' only for NEWLINE visualization
 exclusively.  For other visualizations, including NEWLINE
@@ -1054,7 +1102,7 @@ See also `whitespace-newline' and `whitespace-display-mappings'."
   :init-value nil
   :global     nil
   :group      'whitespace
-  (let ((whitespace-style '(newline-mark newline)))
+  (let ((whitespace-style '(face newline-mark newline)))
     (whitespace-mode whitespace-newline-mode)
     ;; sync states (running a batch job)
     (setq whitespace-newline-mode whitespace-mode)))
@@ -1071,7 +1119,6 @@ See also `whitespace-newline' and `whitespace-display-mappings'."
 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'."
@@ -1128,12 +1175,11 @@ See also `whitespace-style', `whitespace-newline' and
 If ARG is null, toggle NEWLINE visualization.
 If ARG is a number greater than zero, turn on visualization;
 otherwise, turn off visualization.
-Only useful with a windowing system.
 
 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'.
+please use `global-whitespace-mode'.
 
 See also `whitespace-newline' and `whitespace-display-mappings'."
   :lighter    " NL"
@@ -1141,7 +1187,8 @@ See also `whitespace-newline' and `whitespace-display-mappings'."
   :global     t
   :group      'whitespace
   (let ((whitespace-style '(newline-mark newline)))
-    (global-whitespace-mode global-whitespace-newline-mode)
+    (global-whitespace-mode (if global-whitespace-newline-mode
+                                1 -1))
     ;; sync states (running a batch job)
     (setq global-whitespace-newline-mode global-whitespace-mode)))
 
@@ -1151,7 +1198,8 @@ See also `whitespace-newline' and `whitespace-display-mappings'."
 
 
 (defconst whitespace-style-value-list
-  '(tabs
+  '(face
+    tabs
     spaces
     trailing
     lines
@@ -1176,7 +1224,8 @@ See also `whitespace-newline' and `whitespace-display-mappings'."
 
 
 (defconst whitespace-toggle-option-alist
-  '((?t    . tabs)
+  '((?f    . face)
+    (?t    . tabs)
     (?s    . spaces)
     (?r    . trailing)
     (?l    . lines)
@@ -1220,6 +1269,27 @@ 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).")
+
+(defvar whitespace-bob-marker nil
+  "Used to save locally the bob marker value.
+Used by `whitespace-post-command-hook' function (which see).")
+
+(defvar whitespace-eob-marker nil
+  "Used to save locally the eob marker value.
+Used by `whitespace-post-command-hook' function (which see).")
+
+(defvar whitespace-buffer-changed nil
+  "Used to indicate locally if buffer changed.
+Used by `whitespace-post-command-hook' and `whitespace-buffer-changed'
+functions (which see).")
+
 
 ;;;###autoload
 (defun whitespace-toggle-options (arg)
@@ -1235,6 +1305,7 @@ Interactively, it reads one of the following chars:
 
   CHAR MEANING
   (VIA FACES)
+   f   toggle face visualization
    t   toggle TAB visualization
    s   toggle SPACE and HARD SPACE visualization
    r   toggle trailing blanks visualization
@@ -1263,6 +1334,7 @@ Interactively, it reads one of the following chars:
 Non-interactively, ARG should be a symbol or a list of symbols.
 The valid symbols are:
 
+   face                        toggle face visualization
    tabs                        toggle TAB visualization
    spaces              toggle SPACE and HARD SPACE visualization
    trailing            toggle trailing blanks visualization
@@ -1286,8 +1358,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
@@ -1314,6 +1384,7 @@ Interactively, it accepts one of the following chars:
 
   CHAR MEANING
   (VIA FACES)
+   f   toggle face visualization
    t   toggle TAB visualization
    s   toggle SPACE and HARD SPACE visualization
    r   toggle trailing blanks visualization
@@ -1342,6 +1413,7 @@ Interactively, it accepts one of the following chars:
 Non-interactively, ARG should be a symbol or a list of symbols.
 The valid symbols are:
 
+   face                        toggle face visualization
    tabs                        toggle TAB visualization
    spaces              toggle SPACE and HARD SPACE visualization
    trailing            toggle trailing blanks visualization
@@ -1365,8 +1437,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
@@ -1459,10 +1529,10 @@ documentation."
          (let (overwrite-mode)         ; enforce no overwrite
            (goto-char (point-min))
            (when (re-search-forward
-                  whitespace-empty-at-bob-regexp nil t)
+                  (concat "\\`" whitespace-empty-at-bob-regexp) nil t)
              (delete-region (match-beginning 1) (match-end 1)))
            (when (re-search-forward
-                  whitespace-empty-at-eob-regexp nil t)
+                  (concat 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
@@ -1582,12 +1652,12 @@ documentation."
            (whitespace-replace-action
             (if whitespace-indent-tabs-mode 'tabify 'untabify)
             rstart rend whitespace-space-before-tab-regexp
-            (if whitespace-indent-tabs-mode 1 2)))
+            (if whitespace-indent-tabs-mode 0 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))
+            whitespace-space-before-tab-regexp 0))
           ;; ACTION: replace TABs by SPACEs.
           ((memq 'space-before-tab::space whitespace-style)
            (whitespace-replace-action
@@ -1873,9 +1943,10 @@ cleaning up these problems."
 
 (defconst whitespace-help-text
   "\
- Whitespace Toggle Options
-
- FACES
+ Whitespace Toggle Options                  | scroll up  :  SPC   or > |
+                                            | scroll down:  M-SPC or < |
+ FACES                                      \\__________________________/
+ []  f   - toggle face visualization
  []  t   - toggle TAB visualization
  []  s   - toggle SPACE and HARD SPACE visualization
  []  r   - toggle trailing blanks visualization
@@ -1937,8 +2008,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
@@ -1950,15 +2020,13 @@ cleaning up these problems."
   "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; \
+  (when (< (window-height) (* 2 window-min-height))
+    (kill-buffer buffer)
+    (error "Window height is too small; \
 can't split window to display whitespace toggle options"))
-    (set-window-buffer (split-window nil size) buffer)))
+  (let ((win (split-window)))
+    (set-window-buffer win buffer)
+    (shrink-window-if-larger-than-buffer win)))
 
 
 (defun whitespace-kill-buffer (buffer-name)
@@ -1974,6 +2042,24 @@ can't split window to display whitespace toggle options"))
   (whitespace-kill-buffer whitespace-help-buffer-name))
 
 
+(defun whitespace-help-scroll (&optional up)
+  "Scroll help window, if it exists.
+
+If UP is non-nil, scroll up; otherwise, scroll down."
+  (condition-case data-help
+      (let ((buffer (get-buffer whitespace-help-buffer-name)))
+       (if buffer
+           (with-selected-window (get-buffer-window buffer)
+             (if up
+                 (scroll-up 3)
+               (scroll-down 3)))
+         (ding)))
+    ;; handler
+    ((error)
+     ;; just ignore error
+     )))
+
+
 (defun whitespace-interactive-char (local-p)
   "Interactive function to read a char and return a symbol.
 
@@ -1984,6 +2070,7 @@ It accepts one of the following chars:
 
   CHAR MEANING
   (VIA FACES)
+   f   toggle face visualization
    t   toggle TAB visualization
    s   toggle SPACE and HARD SPACE visualization
    r   toggle trailing blanks visualization
@@ -2033,16 +2120,20 @@ See also `whitespace-toggle-option-alist'."
                         (cdr
                          (assq ch whitespace-toggle-option-alist)))))
              ;; while body
-             (if (eq ch ?\?)
-                 (whitespace-help-on style)
-               (ding)))
+             (cond
+              ((eq ch ?\?)   (whitespace-help-on style))
+              ((eq ch ?\ )   (whitespace-help-scroll t))
+              ((eq ch ?\M- ) (whitespace-help-scroll))
+              ((eq ch ?>)    (whitespace-help-scroll t))
+              ((eq ch ?<)    (whitespace-help-scroll))
+              (t             (ding))))
            (whitespace-help-off)
            (message " "))              ; clean echo area
        ;; handler
        ((quit error)
         (whitespace-help-off)
         (error (error-message-string data)))))
-    (list sym)))                       ; return the apropriate symbol
+    (list sym)))                       ; return the appropriate symbol
 
 
 (defun whitespace-toggle-list (local-p arg the-list)
@@ -2114,22 +2205,23 @@ resultant list will be returned."
 
 (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)))
+  (and (memq 'face whitespace-active-style)
+       (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 ()
@@ -2139,6 +2231,19 @@ 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)
+        0)
+    (set (make-local-variable 'whitespace-bob-marker)
+        (point-min-marker))
+    (set (make-local-variable 'whitespace-eob-marker)
+        (point-max-marker))
+    (set (make-local-variable 'whitespace-buffer-changed)
+        nil)
+    (add-hook 'post-command-hook #'whitespace-post-command-hook nil t)
+    (add-hook 'before-change-functions #'whitespace-buffer-changed nil t)
     ;; turn off font lock
     (set (make-local-variable 'whitespace-font-lock-mode)
         font-lock-mode)
@@ -2165,7 +2270,7 @@ resultant list will be returned."
        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))
@@ -2174,14 +2279,16 @@ resultant list will be returned."
        (list
        ;; Show "long" lines
        (list
-        (format
-         "^\\([^\t\n]\\{%s\\}\\|[^\t\n]\\{0,%s\\}\t\\)\\{%d\\}%s\\(.+\\)$"
-         whitespace-tab-width (1- whitespace-tab-width)
-         (/ whitespace-line-column tab-width)
-         (let ((rem (% whitespace-line-column whitespace-tab-width)))
-           (if (zerop rem)
-               ""
-             (format ".\\{%d\\}" rem))))
+        (let ((line-column (or whitespace-line-column fill-column)))
+          (format
+           "^\\([^\t\n]\\{%s\\}\\|[^\t\n]\\{0,%s\\}\t\\)\\{%d\\}%s\\(.+\\)$"
+           whitespace-tab-width
+           (1- whitespace-tab-width)
+           (/ line-column whitespace-tab-width)
+           (let ((rem (% line-column whitespace-tab-width)))
+             (if (zerop rem)
+                 ""
+               (format ".\\{%d\\}" rem)))))
         (if (memq 'lines whitespace-active-style)
             0                          ; whole line
           2)                           ; line tail
@@ -2243,14 +2350,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
@@ -2287,12 +2394,152 @@ 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 t)
+    (remove-hook 'before-change-functions #'whitespace-buffer-changed t)
     (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."
+  (let ((b (point))
+       r)
+    (cond
+     ;; at bob
+     ((= b 1)
+      (setq r (and (/= whitespace-point 1)
+                  (looking-at whitespace-empty-at-bob-regexp)))
+      (if r
+         (set-marker whitespace-bob-marker (match-end 1))
+       (set-marker whitespace-bob-marker b)))
+     ;; inside bob empty region
+     ((<= limit whitespace-bob-marker)
+      (setq r (looking-at whitespace-empty-at-bob-regexp))
+      (if r
+         (when (< (match-end 1) limit)
+           (set-marker whitespace-bob-marker (match-end 1)))
+       (set-marker whitespace-bob-marker b)))
+     ;; intersection with end of bob empty region
+     ((<= b whitespace-bob-marker)
+      (setq r (looking-at whitespace-empty-at-bob-regexp))
+      (if r
+         (set-marker whitespace-bob-marker (match-end 1))
+       (set-marker whitespace-bob-marker b)))
+     ;; it is not inside bob empty region
+     (t
+      (setq r nil)))
+    ;; move to end of matching
+    (and r (goto-char (match-end 1)))
+    r))
+
+
+(defsubst whitespace-looking-back (regexp limit)
+  (save-excursion
+    (when (/= 0 (skip-chars-backward " \t\n" limit))
+      (unless (bolp)
+       (forward-line 1))
+      (looking-at regexp))))
+
+
+(defun whitespace-empty-at-eob-regexp (limit)
+  "Match spaces at end of buffer which do not contain the point at end of \
+buffer."
+  (let ((b (point))
+       (e (1+ (buffer-size)))
+       r)
+    (cond
+     ;; at eob
+     ((= limit e)
+      (when (/= whitespace-point e)
+       (goto-char limit)
+       (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b)))
+      (if r
+         (set-marker whitespace-eob-marker (match-beginning 1))
+       (set-marker whitespace-eob-marker limit)
+       (goto-char b)))                 ; return back to initial position
+     ;; inside eob empty region
+     ((>= b whitespace-eob-marker)
+      (goto-char limit)
+      (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b))
+      (if r
+         (when (> (match-beginning 1) b)
+           (set-marker whitespace-eob-marker (match-beginning 1)))
+       (set-marker whitespace-eob-marker limit)
+       (goto-char b)))                 ; return back to initial position
+     ;; intersection with beginning of eob empty region
+     ((>= limit whitespace-eob-marker)
+      (goto-char limit)
+      (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b))
+      (if r
+         (set-marker whitespace-eob-marker (match-beginning 1))
+       (set-marker whitespace-eob-marker limit)
+       (goto-char b)))                 ; return back to initial position
+     ;; it is not inside eob empty region
+     (t
+      (setq r nil)))
+    r))
+
+
+(defun whitespace-buffer-changed (beg end)
+  "Set `whitespace-buffer-changed' variable to t."
+  (setq whitespace-buffer-changed t))
+
+
+(defun whitespace-post-command-hook ()
+  "Save current point into `whitespace-point' variable.
+Also refontify when necessary."
+  (setq whitespace-point (point))      ; current point position
+  (let ((refontify
+        (or
+         ;; it is at end of line ...
+         (and (eolp)
+              ;; ... with trailing SPACE or TAB
+              (or (= (preceding-char) ?\ )
+                  (= (preceding-char) ?\t)))
+         ;; it is at beginning of buffer (bob)
+         (= whitespace-point 1)
+         ;; the buffer was modified and ...
+         (and whitespace-buffer-changed
+              (or
+               ;; ... or inside bob whitespace region
+               (<= whitespace-point whitespace-bob-marker)
+               ;; ... or at bob whitespace region border
+               (and (= whitespace-point (1+ whitespace-bob-marker))
+                    (= (preceding-char) ?\n))))
+         ;; it is at end of buffer (eob)
+         (= whitespace-point (1+ (buffer-size)))
+         ;; the buffer was modified and ...
+         (and whitespace-buffer-changed
+              (or
+               ;; ... or inside eob whitespace region
+               (>= whitespace-point whitespace-eob-marker)
+               ;; ... or at eob whitespace region border
+               (and (= whitespace-point (1- whitespace-eob-marker))
+                    (= (following-char) ?\n)))))))
+    (when (or refontify (> whitespace-font-lock-refontify 0))
+      (setq whitespace-buffer-changed nil)
+      ;; adjust refontify counter
+      (setq whitespace-font-lock-refontify
+           (if refontify
+               1
+             (1- whitespace-font-lock-refontify)))
+      ;; refontify
+      (jit-lock-refontify))))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;; Hacked from visws.el (Miles Bader <miles@gnu.org>)
@@ -2329,6 +2576,10 @@ resultant list will be returned."
       (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.
+       (setq buffer-display-table
              (copy-sequence buffer-display-table)))
       (unless buffer-display-table
        (setq buffer-display-table (make-display-table)))
@@ -2417,5 +2668,4 @@ It should be added buffer-locally to `write-file-functions'."
 (run-hooks 'whitespace-load-hook)
 
 
-;; arch-tag: 1b1e2500-dbd4-4a26-8f7a-5a5edfd3c97e
 ;;; whitespace.el ends here