don't require grep in vc-git
[bpt/emacs.git] / lisp / whitespace.el
index e2a726f..917f043 100644 (file)
@@ -1,6 +1,6 @@
 ;;; whitespace.el --- minor mode to visualize TAB, (HARD) SPACE, NEWLINE
 
-;; Copyright (C) 2000-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2000-2014 Free Software Foundation, Inc.
 
 ;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
 ;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
 ;; Thanks to Andreas Roehler <andreas.roehler@easy-emacs.de> for
 ;; indicating defface byte-compilation warnings.
 ;;
-;; Thanks to TimOCallaghan (EmacsWiki) for the idea about highlight
+;; Thanks to Tim O'Callaghan (EmacsWiki) for the idea about highlight
 ;; "long" lines.  See EightyColumnRule (EmacsWiki).
 ;;
 ;; Thanks to Yanghui Bian <yanghuibian@gmail.com> for indicating a new
@@ -554,13 +554,10 @@ See also `whitespace-display-mappings' for documentation."
                         (const :tag "(Mark) NEWLINEs" newline-mark)))
   :group 'whitespace)
 
-
-(defcustom whitespace-space 'whitespace-space
+(defvar whitespace-space 'whitespace-space
   "Symbol face used to visualize SPACE.
-
-Used when `whitespace-style' includes the value `spaces'."
-  :type 'face
-  :group 'whitespace)
+Used when `whitespace-style' includes the value `spaces'.")
+(make-obsolete-variable 'whitespace-space "use the face instead." "24.4")
 
 
 (defface whitespace-space
@@ -573,13 +570,10 @@ Used when `whitespace-style' includes the value `spaces'."
   :group 'whitespace)
 
 
-(defcustom whitespace-hspace 'whitespace-hspace
+(defvar whitespace-hspace 'whitespace-hspace
   "Symbol face used to visualize HARD SPACE.
-
-Used when `whitespace-style' includes the value `spaces'."
-  :type 'face
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `spaces'.")
+(make-obsolete-variable 'whitespace-hspace "use the face instead." "24.4")
 
 (defface whitespace-hspace             ; 'nobreak-space
   '((((class color) (background dark))
@@ -591,13 +585,10 @@ Used when `whitespace-style' includes the value `spaces'."
   :group 'whitespace)
 
 
-(defcustom whitespace-tab 'whitespace-tab
+(defvar whitespace-tab 'whitespace-tab
   "Symbol face used to visualize TAB.
-
-Used when `whitespace-style' includes the value `tabs'."
-  :type 'face
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `tabs'.")
+(make-obsolete-variable 'whitespace-tab "use the face instead." "24.4")
 
 (defface whitespace-tab
   '((((class color) (background dark))
@@ -609,16 +600,12 @@ Used when `whitespace-style' includes the value `tabs'."
   :group 'whitespace)
 
 
-(defcustom whitespace-newline 'whitespace-newline
+(defvar whitespace-newline 'whitespace-newline
   "Symbol face used to visualize NEWLINE char mapping.
-
 See `whitespace-display-mappings'.
-
 Used when `whitespace-style' includes the values `newline-mark'
-and `newline'."
-  :type 'face
-  :group 'whitespace)
-
+and `newline'.")
+(make-obsolete-variable 'whitespace-newline "use the face instead." "24.4")
 
 (defface whitespace-newline
   '((default :weight normal)
@@ -634,13 +621,10 @@ See `whitespace-display-mappings'."
   :group 'whitespace)
 
 
-(defcustom whitespace-trailing 'whitespace-trailing
+(defvar whitespace-trailing 'whitespace-trailing
   "Symbol face used to visualize trailing blanks.
-
-Used when `whitespace-style' includes the value `trailing'."
-  :type 'face
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `trailing'.")
+(make-obsolete-variable 'whitespace-trailing "use the face instead." "24.4")
 
 (defface whitespace-trailing           ; 'trailing-whitespace
   '((default :weight bold)
@@ -650,15 +634,11 @@ Used when `whitespace-style' includes the value `trailing'."
   :group 'whitespace)
 
 
-(defcustom whitespace-line 'whitespace-line
+(defvar whitespace-line 'whitespace-line
   "Symbol face used to visualize \"long\" lines.
-
 See `whitespace-line-column'.
-
-Used when `whitespace-style' includes the value `line'."
-  :type 'face
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `line'.")
+(make-obsolete-variable 'whitespace-line "use the face instead." "24.4")
 
 (defface whitespace-line
   '((((class mono)) :inverse-video t :weight bold :underline t)
@@ -669,13 +649,11 @@ See `whitespace-line-column'."
   :group 'whitespace)
 
 
-(defcustom whitespace-space-before-tab 'whitespace-space-before-tab
+(defvar whitespace-space-before-tab 'whitespace-space-before-tab
   "Symbol face used to visualize SPACEs before TAB.
-
-Used when `whitespace-style' includes the value `space-before-tab'."
-  :type 'face
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `space-before-tab'.")
+(make-obsolete-variable 'whitespace-space-before-tab
+                        "use the face instead." "24.4")
 
 (defface whitespace-space-before-tab
   '((((class mono)) :inverse-video t :weight bold :underline t)
@@ -684,13 +662,10 @@ Used when `whitespace-style' includes the value `space-before-tab'."
   :group 'whitespace)
 
 
-(defcustom whitespace-indentation 'whitespace-indentation
+(defvar whitespace-indentation 'whitespace-indentation
   "Symbol face used to visualize 8 or more SPACEs at beginning of line.
-
-Used when `whitespace-style' includes the value `indentation'."
-  :type 'face
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `indentation'.")
+(make-obsolete-variable 'whitespace-indentation "use the face instead." "24.4")
 
 (defface whitespace-indentation
   '((((class mono)) :inverse-video t :weight bold :underline t)
@@ -699,13 +674,10 @@ Used when `whitespace-style' includes the value `indentation'."
   :group 'whitespace)
 
 
-(defcustom whitespace-empty 'whitespace-empty
+(defvar whitespace-empty 'whitespace-empty
   "Symbol face used to visualize empty lines at beginning and/or end of buffer.
-
-Used when `whitespace-style' includes the value `empty'."
-  :type 'face
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `empty'.")
+(make-obsolete-variable 'whitespace-empty "use the face instead." "24.4")
 
 (defface whitespace-empty
   '((((class mono)) :inverse-video t :weight bold :underline t)
@@ -714,13 +686,11 @@ Used when `whitespace-style' includes the value `empty'."
   :group 'whitespace)
 
 
-(defcustom whitespace-space-after-tab 'whitespace-space-after-tab
+(defvar whitespace-space-after-tab 'whitespace-space-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
-  :group 'whitespace)
-
+Used when `whitespace-style' includes the value `space-after-tab'.")
+(make-obsolete-variable 'whitespace-space-after-tab
+                        "use the face instead." "24.4")
 
 (defface whitespace-space-after-tab
   '((((class mono)) :inverse-video t :weight bold :underline t)
@@ -730,15 +700,9 @@ Used when `whitespace-style' includes the value `space-after-tab'."
 
 
 (defcustom whitespace-hspace-regexp
-  "\\(\\(\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)"
+  "\\(\u00A0+\\)"
   "Specify HARD SPACE characters regexp.
 
-If you're using `mule' package, there may be other characters besides:
-
-   \"\\xA0\"   \"\\x8A0\"   \"\\x920\"   \"\\xE20\"   \"\\xF20\"
-
-that should be considered HARD SPACE.
-
 Here are some examples:
 
    \"\\\\(^\\xA0+\\\\)\"               \
@@ -806,7 +770,7 @@ Used when `whitespace-style' includes `tabs'."
   "\\([\t \u00A0]+\\)$"
   "Specify trailing characters regexp.
 
-If you're using `mule' package, there may be other characters besides:
+There may be other characters besides:
 
    \" \"  \"\\t\"  \"\\u00A0\"
 
@@ -823,13 +787,6 @@ Used when `whitespace-style' includes `trailing'."
 (defcustom whitespace-space-before-tab-regexp "\\( +\\)\\(\t+\\)"
   "Specify SPACEs before TAB regexp.
 
-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' includes `space-before-tab',
 `space-before-tab::tab' or  `space-before-tab::space'."
   :type '(regexp :tag "SPACEs Before TAB")
@@ -844,30 +801,16 @@ Used when `whitespace-style' includes `space-before-tab',
 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' includes `indentation',
 `indentation::tab' or  `indentation::space'."
-  :type '(cons (regexp :tag "Indentation SPACEs")
-              (regexp :tag "Indentation TABs"))
+  :type '(cons (string :tag "Indentation SPACEs")
+              (string :tag "Indentation TABs"))
   :group 'whitespace)
 
 
 (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:
-
-   \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
-\"\\xF20\"
-
-that should be considered blank.
-
 Used when `whitespace-style' includes `empty'."
   :type '(regexp :tag "Empty Lines At Beginning Of Buffer")
   :group 'whitespace)
@@ -876,13 +819,6 @@ Used when `whitespace-style' includes `empty'."
 (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:
-
-   \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
-\"\\xF20\"
-
-that should be considered blank.
-
 Used when `whitespace-style' includes `empty'."
   :type '(regexp :tag "Empty Lines At End Of Buffer")
   :group 'whitespace)
@@ -896,16 +832,10 @@ Used when `whitespace-style' includes `empty'."
 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' includes `space-after-tab',
 `space-after-tab::tab' or `space-after-tab::space'."
-  :type '(regexp :tag "SPACEs After TAB")
+  :type '(cons (string :tag "SPACEs After TAB")
+              string)
   :group 'whitespace)
 
 
@@ -1145,29 +1075,31 @@ See also `whitespace-style', `whitespace-newline' and
        (unless whitespace-mode
          (whitespace-turn-off)))))))
 
+(defvar whitespace-enable-predicate
+  (lambda ()
+    (and (cond
+          ((eq whitespace-global-modes t))
+          ((listp whitespace-global-modes)
+           (if (eq (car-safe whitespace-global-modes) 'not)
+               (not (memq major-mode (cdr whitespace-global-modes)))
+             (memq major-mode whitespace-global-modes)))
+          (t nil))
+         ;; ...we have a display (not running a batch job)
+         (not noninteractive)
+         ;; ...the buffer is not internal (name starts with a space)
+         (not (eq (aref (buffer-name) 0) ?\ ))
+         ;; ...the buffer is not special (name starts with *)
+         (or (not (eq (aref (buffer-name) 0) ?*))
+             ;; except the scratch buffer.
+             (string= (buffer-name) "*scratch*"))))
+  "Predicate to decide which buffers obey `global-whitespace-mode'.
+This function is called with no argument and should return non-nil
+if the current buffer should obey `global-whitespace-mode'.
+This variable is normally modified via `add-function'.")
 
 (defun whitespace-turn-on-if-enabled ()
-  (when (cond
-        ((eq whitespace-global-modes t))
-        ((listp whitespace-global-modes)
-         (if (eq (car-safe whitespace-global-modes) 'not)
-             (not (memq major-mode (cdr whitespace-global-modes)))
-           (memq major-mode whitespace-global-modes)))
-        (t nil))
-    (let (inhibit-quit)
-      ;; Don't turn on whitespace mode if...
-      (or
-       ;; ...we don't have a display (we're running a batch job)
-       noninteractive
-       ;; ...or if the buffer is invisible (name starts with a space)
-       (eq (aref (buffer-name) 0) ?\ )
-       ;; ...or if the buffer is temporary (name starts with *)
-       (and (eq (aref (buffer-name) 0) ?*)
-           ;; except the scratch buffer.
-           (not (string= (buffer-name) "*scratch*")))
-       ;; Otherwise, turn on whitespace mode.
-       (whitespace-turn-on)))))
-
+  (when (funcall whitespace-enable-predicate)
+    (whitespace-turn-on)))
 
 ;;;###autoload
 (define-minor-mode global-whitespace-newline-mode
@@ -1271,19 +1203,21 @@ SYMBOL  is a valid symbol associated with CHAR.
 
 (defvar whitespace-point (point)
   "Used to save locally current point value.
-Used by `whitespace-trailing-regexp' function (which see).")
+Used by function `whitespace-trailing-regexp' (which see).")
+(defvar-local whitespace-point--used nil
+  "Region whose highlighting depends on `whitespace-point'.")
 
 (defvar whitespace-font-lock-refontify nil
   "Used to save locally the font-lock refontify state.
-Used by `whitespace-post-command-hook' function (which see).")
+Used by function `whitespace-post-command-hook' (which see).")
 
 (defvar whitespace-bob-marker nil
   "Used to save locally the bob marker value.
-Used by `whitespace-post-command-hook' function (which see).")
+Used by function `whitespace-post-command-hook' (which see).")
 
 (defvar whitespace-eob-marker nil
   "Used to save locally the eob marker value.
-Used by `whitespace-post-command-hook' function (which see).")
+Used by function `whitespace-post-command-hook' (which see).")
 
 (defvar whitespace-buffer-changed nil
   "Used to indicate locally if buffer changed.
@@ -1539,6 +1473,12 @@ documentation."
     ;; PROBLEM 6: 8 or more SPACEs after TAB
     (whitespace-cleanup-region (point-min) (point-max)))))
 
+(defun whitespace-ensure-local-variables ()
+  "Set `whitespace-indent-tabs-mode' and `whitespace-tab-width' locally."
+  (set (make-local-variable 'whitespace-indent-tabs-mode)
+       indent-tabs-mode)
+  (set (make-local-variable 'whitespace-tab-width)
+       tab-width))
 
 ;;;###autoload
 (defun whitespace-cleanup-region (start end)
@@ -1585,6 +1525,7 @@ documentation."
       ;; read-only buffer
       (whitespace-warn-read-only "cleanup region")
     ;; non-read-only buffer
+    (whitespace-ensure-local-variables)
     (let ((rstart           (min start end))
          (rend             (copy-marker (max start end)))
          (indent-tabs-mode whitespace-indent-tabs-mode)
@@ -1778,43 +1719,7 @@ It is a cons of strings, where the car part is used when
 (defun whitespace-report (&optional force report-if-bogus)
   "Report some whitespace problems in buffer.
 
-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' 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."
+Perform `whitespace-report-region' on the current buffer."
   (interactive (list current-prefix-arg))
   (whitespace-report-region (point-min) (point-max)
                            force report-if-bogus))
@@ -1832,13 +1737,14 @@ before calling `whitespace-report-region' interactively, it
 forces `whitespace-style' to have:
 
    empty
+   trailing
    indentation
    space-before-tab
-   trailing
    space-after-tab
 
-If REPORT-IF-BOGUS is non-nil, it reports only when there are any
-whitespace problems in buffer.
+If REPORT-IF-BOGUS is t, it reports only when there are any
+whitespace problems in buffer; if it is `never', it does not
+report problems.
 
 Report if some of the following whitespace problems exist:
 
@@ -1893,7 +1799,7 @@ cleaning up these problems."
                     (and (re-search-forward regexp rend t)
                          (setq has-bogus t))))
               whitespace-report-list)))
-       (when (if report-if-bogus has-bogus t)
+       (when (pcase report-if-bogus (`nil t) (`never nil) (_ has-bogus))
          (whitespace-kill-buffer whitespace-report-buffer-name)
          ;; `whitespace-indent-tabs-mode' is local to current buffer
          ;; `whitespace-tab-width' is local to current buffer
@@ -1930,14 +1836,8 @@ cleaning up these problems."
 ;;;; Internal functions
 
 
-(defvar whitespace-font-lock-mode nil
-  "Used to remember whether a buffer had font lock mode on or not.")
-
-(defvar whitespace-font-lock nil
-  "Used to remember whether a buffer initially had font lock on or not.")
-
 (defvar whitespace-font-lock-keywords nil
-  "Used to save locally `font-lock-keywords' value.")
+  "Used to save the value `whitespace-color-on' adds to `font-lock-keywords'.")
 
 
 (defconst whitespace-help-text
@@ -2169,14 +2069,11 @@ resultant list will be returned."
 (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."
   ;; 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)
@@ -2184,10 +2081,7 @@ resultant list will be returned."
        (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)
+  (whitespace-ensure-local-variables)
   ;; turn on whitespace
   (when whitespace-active-style
     (whitespace-color-on)
@@ -2226,13 +2120,12 @@ resultant list will be returned."
 (defun whitespace-color-on ()
   "Turn on color visualization."
   (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))
+         (point))
+    (setq whitespace-point--used
+          (let ((ol (make-overlay (point) (point) nil nil t)))
+            (delete-overlay ol) ol))
     (set (make-local-variable 'whitespace-font-lock-refontify)
         0)
     (set (make-local-variable 'whitespace-bob-marker)
@@ -2243,170 +2136,129 @@ resultant list will be returned."
         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)
-    (font-lock-mode 0)
-    ;; add whitespace-mode color into font lock
-    (when (memq 'spaces whitespace-active-style)
-      (font-lock-add-keywords
-       nil
-       (list
-       ;; Show SPACEs
-       (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-style)
-      (font-lock-add-keywords
-       nil
-       (list
-       ;; Show TABs
-       (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))
-       t))
-    (when (or (memq 'lines      whitespace-active-style)
-             (memq 'lines-tail whitespace-active-style))
-      (font-lock-add-keywords
-       nil
-       (list
-       ;; Show "long" lines
-       (list
-        (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
-        whitespace-line t))
-       t))
-    (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 (SPACEs)
-       (list whitespace-space-before-tab-regexp
-             1 whitespace-space-before-tab t))
-       t))
-     ((memq 'space-before-tab::space whitespace-active-style)
-      (font-lock-add-keywords
-       nil
-       (list
-       ;; 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))
-     ((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
-             1 whitespace-empty t))
-       t)
-      (font-lock-add-keywords
-       nil
-       (list
-       ;; Show empty lines at end of buffer
-       (list #'whitespace-empty-at-eob-regexp
-             1 whitespace-empty t))
-       t))
-    (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 (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)))
+    ;; Add whitespace-mode color into font lock.
+    (setq
+     whitespace-font-lock-keywords
+     `(
+       (whitespace-point--flush-used)
+       ,@(when (memq 'spaces whitespace-active-style)
+           ;; Show SPACEs.
+           `((,whitespace-space-regexp 1 whitespace-space t)
+             ;; Show HARD SPACEs.
+             (,whitespace-hspace-regexp 1 whitespace-hspace t)))
+       ,@(when (memq 'tabs whitespace-active-style)
+           ;; Show TABs.
+           `((,whitespace-tab-regexp 1 whitespace-tab t)))
+       ,@(when (memq 'trailing whitespace-active-style)
+           ;; Show trailing blanks.
+           `((,#'whitespace-trailing-regexp 1 whitespace-trailing t)))
+       ,@(when (or (memq 'lines      whitespace-active-style)
+                   (memq 'lines-tail whitespace-active-style))
+           ;; Show "long" lines.
+           `((,(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
+              whitespace-line prepend)))
+       ,@(when (or (memq 'space-before-tab whitespace-active-style)
+                   (memq 'space-before-tab::tab whitespace-active-style)
+                   (memq 'space-before-tab::space whitespace-active-style))
+           `((,whitespace-space-before-tab-regexp
+              ,(cond
+                ((memq 'space-before-tab whitespace-active-style)
+                 ;; Show SPACEs before TAB (indent-tabs-mode).
+                 (if whitespace-indent-tabs-mode 1 2))
+                ((memq 'space-before-tab::tab whitespace-active-style)
+                 1)
+                ((memq 'space-before-tab::space whitespace-active-style)
+                 2))
+              whitespace-space-before-tab t)))
+       ,@(when (or (memq 'indentation whitespace-active-style)
+                   (memq 'indentation::tab whitespace-active-style)
+                   (memq 'indentation::space whitespace-active-style))
+           `((,(cond
+                ((memq 'indentation whitespace-active-style)
+                 ;; Show indentation SPACEs (indent-tabs-mode).
+                 (whitespace-indentation-regexp))
+                ((memq 'indentation::tab whitespace-active-style)
+                 ;; Show indentation SPACEs (SPACEs).
+                 (whitespace-indentation-regexp 'tab))
+                ((memq 'indentation::space whitespace-active-style)
+                 ;; Show indentation SPACEs (TABs).
+                 (whitespace-indentation-regexp 'space)))
+              1 whitespace-indentation t)))
+       ,@(when (memq 'empty whitespace-active-style)
+           ;; Show empty lines at beginning of buffer.
+           `((,#'whitespace-empty-at-bob-regexp
+              1 whitespace-empty t)
+             ;; Show empty lines at end of buffer.
+             (,#'whitespace-empty-at-eob-regexp
+              1 whitespace-empty t)))
+       ,@(when (or (memq 'space-after-tab whitespace-active-style)
+                   (memq 'space-after-tab::tab whitespace-active-style)
+                   (memq 'space-after-tab::space whitespace-active-style))
+           `((,(cond
+                ((memq 'space-after-tab whitespace-active-style)
+                 ;; Show SPACEs after TAB (indent-tabs-mode).
+                 (whitespace-space-after-tab-regexp))
+                ((memq 'space-after-tab::tab whitespace-active-style)
+                 ;; Show SPACEs after TAB (SPACEs).
+                 (whitespace-space-after-tab-regexp 'tab))
+                ((memq 'space-after-tab::space whitespace-active-style)
+                 ;; Show SPACEs after TAB (TABs).
+                 (whitespace-space-after-tab-regexp 'space)))
+              1 whitespace-space-after-tab t)))))
+    (font-lock-add-keywords nil whitespace-font-lock-keywords t)
+    (font-lock-flush)))
 
 
 (defun whitespace-color-off ()
   "Turn off color visualization."
   ;; turn off font lock
+  (kill-local-variable 'whitespace-point--used)
   (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)))
-
+    (font-lock-remove-keywords nil whitespace-font-lock-keywords)
+    (font-lock-flush)))
+
+(defun whitespace-point--used (start end)
+  (let ((ostart (overlay-start whitespace-point--used)))
+    (if ostart
+        (move-overlay whitespace-point--used
+                      (min start ostart)
+                      (max end (overlay-end whitespace-point--used)))
+      (move-overlay whitespace-point--used start end))))
+
+(defun whitespace-point--flush-used (limit)
+  (let ((ostart (overlay-start whitespace-point--used)))
+    ;; Strip parts of whitespace-point--used we're about to refresh.
+    (when ostart
+      (let ((oend (overlay-end whitespace-point--used)))
+        (if (<= (point) ostart)
+            (if (<= oend limit)
+                (delete-overlay whitespace-point--used)
+              (move-overlay whitespace-point--used limit oend)))
+        (if (<= oend limit)
+            (move-overlay whitespace-point--used ostart (point))))))
+  nil)
 
 (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)
-              (= whitespace-point (match-end 1)) ;; loop if point at eol
+              (when (= whitespace-point (match-end 1)) ; Loop if point at eol.
+                 (whitespace-point--used (match-beginning 0) (match-end 0))
+                 t)
             (setq status nil)))                  ;; end of buffer
     status))
 
@@ -2419,8 +2271,11 @@ beginning of buffer."
     (cond
      ;; at bob
      ((= b 1)
-      (setq r (and (/= whitespace-point 1)
-                  (looking-at whitespace-empty-at-bob-regexp)))
+      (setq r (and (looking-at whitespace-empty-at-bob-regexp)
+                   (or (/= whitespace-point 1)
+                       (progn (whitespace-point--used (match-beginning 0)
+                                                      (match-end 0))
+                              nil))))
       (set-marker whitespace-bob-marker (if r (match-end 1) b)))
      ;; inside bob empty region
      ((<= limit whitespace-bob-marker)
@@ -2458,9 +2313,11 @@ buffer."
     (cond
      ;; at eob
      ((= limit e)
-      (when (/= whitespace-point e)
-       (goto-char limit)
-       (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b)))
+      (goto-char limit)
+      (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b))
+      (when (and r (= whitespace-point e))
+        (setq r nil)
+        (whitespace-point--used (match-beginning 0) (match-end 0)))
       (if r
          (set-marker whitespace-eob-marker (match-beginning 1))
        (set-marker whitespace-eob-marker limit)
@@ -2496,43 +2353,57 @@ buffer."
 (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))))
+  (unless (and (eq whitespace-point (point))
+               (not whitespace-buffer-changed))
+    (setq whitespace-point (point))    ; current point position
+    (let ((refontify
+           (cond
+            ;; It is at end of buffer (eob).
+            ((= whitespace-point (1+ (buffer-size)))
+             (when (whitespace-looking-back whitespace-empty-at-eob-regexp
+                                            nil)
+               (match-beginning 0)))
+            ;; It is at end of line ...
+            ((and (eolp)
+                  ;; ... with trailing SPACE or TAB
+                  (or (memq (preceding-char) '(?\s ?\t))))
+             (line-beginning-position))
+            ;; It is at beginning of buffer (bob).
+            ((and (= whitespace-point 1)
+                  (looking-at whitespace-empty-at-bob-regexp))
+             (match-end 0))))
+          (ostart (overlay-start whitespace-point--used)))
+      (cond
+       ((not refontify)
+        ;; New point does not affect highlighting: just refresh the
+        ;; highlighting of old point, if needed.
+        (when ostart
+          (font-lock-flush ostart
+                           (overlay-end whitespace-point--used))
+          (delete-overlay whitespace-point--used)))
+       ((not ostart)
+        ;; Old point did not affect highlighting, but new one does: refresh the
+        ;; highlighting of new point.
+        (font-lock-flush (min refontify (point)) (max refontify (point))))
+       ((save-excursion
+          (goto-char ostart)
+          (setq ostart (line-beginning-position))
+          (and (<= ostart (max refontify (point)))
+               (progn
+                 (goto-char (overlay-end whitespace-point--used))
+                 (let ((oend (line-beginning-position 2)))
+                   (<= (min refontify (point)) oend)))))
+        ;; The old point highlighting and the new point highlighting
+        ;; cover a contiguous region: do a single refresh.
+        (font-lock-flush (min refontify (point) ostart)
+                         (max refontify (point)
+                              (overlay-end whitespace-point--used)))
+        (delete-overlay whitespace-point--used))
+       (t
+        (font-lock-flush (min refontify (point))
+                         (max refontify (point)))
+        (font-lock-flush ostart (overlay-end whitespace-point--used))
+        (delete-overlay whitespace-point--used))))))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;