Subject: bug#13646: Whitespace support for file/mode-specific styles and actions

From: Didier Verna <[email-masked]>
Date: Thu, 07 Feb 2013 13:43:26 +0100

Hello,

the following patch extends whitespace.el with the ability to specify
styles and actions on a file or mode specific basis. The rationale is
that the current unique style and action settings are not
sufficient. You may not want to see the exact same whitespace problems
in all files or major modes, and you also may not want the same actions
to be undertaken everywhere.

To make this work, some new user options are introduced (which see):
whitespace-file-style, whitespace-mode-style and their action
counterpart. When computing the style to use for a specific file,
whitespace now looks for a match on the file name, then on the major
mode, and then falls back to the global setting. Same thing for actions.

2013-02-07  Didier Verna  <[email-masked]>

	Support for file/mode-specific styles and actions in whitespace.el.
	* whitespace.el: Update comments throughout the file for this new
	feature.
	(whitespace-style-custom-type): New constant.
	(whitespace-style): Use it. Update and improve docstring format.
	(whitespace-file-style)
	(whitespace-mode-style): New user options.
	(whitespace-style): New function. Handles file and mode-specific
	style settings introduced by the above new user options. Used
	throughout the file instead of the just the eponym variable.
	(whitespace-action-custom-type): New constant.
	(whitespace-action): Use it. Update and improve docstring format.
	(whitespace-file-action)
	(whitespace-mode-action): New user options.
	(whitespace-action): New function. Handles file and mode-specific
	style settings introduced by the above new user options. Used
	throughout the file instead of the just the eponym variable.
	(whitespace-cleanup)
	(whitespace-cleanup-region)
	(whitespace-report-region): Update docstring. Use the
	`whitespace-style' function instead of the eponym variable.
	(whitespace-interactive-char)
	(whitespace-toggle-list)
	(whitespace-turn-on): Handle file/mode-specific styles.
	(whitespace-action-when-on)
	(whitespace-write-file-hook)
	(whitespace-warn-when-read-only): Handle file-mode-specific
	actions by using the function `whitespace-action' instead of the
	eponym variable.
	(whitespace-space)
	(whitespace-hspace)
	(whitespace-tab)
	(whitespace-newline)
	(whitespace-trailing)
	(whitespace-line)
	(whitespace-space-before-tab)
	(whitespace-indentation)
	(whitespace-empty)
	(whitespace-space-after-tab)
	(whitespace-hspace-regexp)
	(whitespace-tab-regexp)
	(whitespace-trailing-regexp)
	(whitespace-space-before-tab-regexp)
	(whitespace-indentation-regexp)
	(whitespace-empty-at-bob-regexp)
	(whitespace-empty-at-eob-regexp)
	(whitespace-space-after-tab-regexp)
	(whitespace-line-column)
	(whitespace-display-mappings)
	(whitespace-style-value-list)
	(whitespace-active-style)
	(whitespace-toggle-options)
	(global-whitespace-toggle-options)
	(whitespace-report): Update docstrings.
*** whitespace.el.orig	Thu Feb  7 12:57:24 2013
--- whitespace.el	Sat Jan 19 19:00:26 2013
***************
*** 43,49 ****
  ;;   it provides a visual mark for characters, for example, at the end
  ;;   of line (?\xB6), at SPACEs (?\xB7) and at TABs (?\xBB).
  ;;
! ;; The `whitespace-style' variable selects which way blanks are
  ;; visualized.
  ;;
  ;; Note that when whitespace is turned on, whitespace saves the
--- 43,50 ----
  ;;   it provides a visual mark for characters, for example, at the end
  ;;   of line (?\xB6), at SPACEs (?\xB7) and at TABs (?\xBB).
  ;;
! ;; The `whitespace-file-style', `whitespace-mode-style' and
! ;; `whitespace-style' variables select which way blanks are
  ;; visualized.
  ;;
  ;; Note that when whitespace is turned on, whitespace saves the
***************
*** 186,224 ****
  ;;
  ;; 1. empty lines at beginning of buffer.
  ;; 2. empty lines at end of buffer.
! ;;    If `whitespace-style' includes the value `empty', remove all
  ;;    empty lines at beginning and/or end of buffer.
  ;;
  ;; 3. 8 or more SPACEs at beginning of line.
! ;;    If `whitespace-style' includes the value `indentation':
  ;;    replace 8 or more SPACEs at beginning of line by TABs, if
  ;;    `indent-tabs-mode' is non-nil; otherwise, replace TABs by
  ;;    SPACEs.
! ;;    If `whitespace-style' includes the value `indentation::tab',
  ;;    replace 8 or more SPACEs at beginning of line by TABs.
! ;;    If `whitespace-style' includes the value `indentation::space',
  ;;    replace TABs by SPACEs.
  ;;
  ;; 4. SPACEs before TAB.
! ;;    If `whitespace-style' includes the value `space-before-tab':
  ;;    replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
  ;;    otherwise, replace TABs by SPACEs.
! ;;    If `whitespace-style' includes the value
  ;;    `space-before-tab::tab', replace SPACEs by TABs.
! ;;    If `whitespace-style' includes the value
  ;;    `space-before-tab::space', replace TABs by SPACEs.
  ;;
  ;; 5. SPACEs or TABs at end of line.
! ;;    If `whitespace-style' includes the value `trailing', remove all
  ;;    SPACEs or TABs at end of line.
  ;;
  ;; 6. 8 or more SPACEs after TAB.
! ;;    If `whitespace-style' includes the value `space-after-tab':
  ;;    replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
  ;;    otherwise, replace TABs by SPACEs.
! ;;    If `whitespace-style' includes the value `space-after-tab::tab',
  ;;    replace SPACEs by TABs.
! ;;    If `whitespace-style' includes the value
  ;;    `space-after-tab::space', replace TABs by SPACEs.
  ;;
  ;;
--- 187,225 ----
  ;;
  ;; 1. empty lines at beginning of buffer.
  ;; 2. empty lines at end of buffer.
! ;;    If whitespace style includes the value `empty', remove all
  ;;    empty lines at beginning and/or end of buffer.
  ;;
  ;; 3. 8 or more SPACEs at beginning of line.
! ;;    If whitespace style includes the value `indentation':
  ;;    replace 8 or more SPACEs at beginning of line by TABs, if
  ;;    `indent-tabs-mode' is non-nil; otherwise, replace TABs by
  ;;    SPACEs.
! ;;    If whitespace style includes the value `indentation::tab',
  ;;    replace 8 or more SPACEs at beginning of line by TABs.
! ;;    If whitespace style includes the value `indentation::space',
  ;;    replace TABs by SPACEs.
  ;;
  ;; 4. SPACEs before TAB.
! ;;    If whitespace style includes the value `space-before-tab':
  ;;    replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
  ;;    otherwise, replace TABs by SPACEs.
! ;;    If whitespace style includes the value
  ;;    `space-before-tab::tab', replace SPACEs by TABs.
! ;;    If whitespace style includes the value
  ;;    `space-before-tab::space', replace TABs by SPACEs.
  ;;
  ;; 5. SPACEs or TABs at end of line.
! ;;    If whitespace style includes the value `trailing', remove all
  ;;    SPACEs or TABs at end of line.
  ;;
  ;; 6. 8 or more SPACEs after TAB.
! ;;    If whitespace style includes the value `space-after-tab':
  ;;    replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
  ;;    otherwise, replace TABs by SPACEs.
! ;;    If whitespace style includes the value `space-after-tab::tab',
  ;;    replace SPACEs by TABs.
! ;;    If whitespace style includes the value
  ;;    `space-after-tab::space', replace TABs by SPACEs.
  ;;
  ;;
***************
*** 243,248 ****
--- 244,251 ----
  ;; Below it's shown a brief description of whitespace options, please,
  ;; see the options declaration in the code for a long documentation.
  ;;
+ ;; `whitespace-file-style'
+ ;; `whitespace-mode-style'
  ;; `whitespace-style'		Specify which kind of blank is
  ;;				visualized.
  ;;
***************
*** 305,310 ****
--- 308,315 ----
  ;;				`whitespace-mode' is automagically
  ;;				turned on.
  ;;
+ ;; `whitespace-file-action'
+ ;; `whitespace-mode-action'
  ;; `whitespace-action'		Specify which action is taken when a
  ;;				buffer is visited or written.
  ;;
***************
*** 383,388 ****
--- 388,448 ----
    :group 'convenience)

+ (defconst whitespace-style-custom-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" spaces)
+ 		   (const :tag "(Face) TABs" tabs)
+ 		   (const :tag "(Face) Lines" lines)
+ 		   (const :tag "(Face) SPACEs before TAB" space-before-tab)
+ 		   (const :tag "(Face) NEWLINEs" newline)
+ 		   (const :tag "(Face) Indentation SPACEs" indentation)
+ 		   (const :tag "(Face) Empty Lines At BOB And/Or EOB" empty)
+ 		   (const :tag "(Face) SPACEs after TAB" space-after-tab)
+ 		   (const :tag "(Mark) SPACEs and HARD SPACEs" space-mark)
+ 		   (const :tag "(Mark) TABs" tab-mark)
+ 		   (const :tag "(Mark) NEWLINEs" newline-mark)))
+   ;; Custom type specification for Whitespace styles. Used in
+   ;; WHITESPACE-FILE-STYLE, WHITESPACE-MODE-STYLE and
+   ;; WHITESPACE-STYLE.
+   )
+ 
+ (defcustom whitespace-file-style nil
+   "Specify which kind of blank is visualized for specific files.
+ 
+ This is a list of elements of the form (REGEXP STYLE...) where
+ REGEXP is matched against file names.  For a list of possible
+ STYLEs, see `whitespace-style'.
+ 
+ Whitespace determines which style to use on a specific buffer by
+ trying a match from this variable, then from
+ `whitespace-mode-style' and then by falling back to
+ `whitespace-style'."
+   :type `(repeat (cons :value ("")
+ 		       (regexp :tag "File Name Matching")
+ 		       ,whitespace-style-custom-type))
+   :version "24.3"
+   :group 'whitespace)
+ 
+ (defcustom whitespace-mode-style nil
+   "Specify which kind of blank is visualized for specific major modes.
+ 
+ This is a list of elements of the form (MODE STYLE...) where MODE
+ is a major mode name.  For a list of possible STYLEs, see
+ `whitespace-style'.
+ 
+ Whitespace determines which style to use on a specific buffer by
+ trying a match from `whitespace-file-style', then from this
+ variable and then by falling back to `whitespace-style'."
+   :type `(repeat (cons :value (fundamental-mode)
+ 		       (symbol :tag "Major Mode")
+ 		       ,whitespace-style-custom-type))
+   :version "24.3"
+   :group 'whitespace)
+ 
  (defcustom whitespace-style
    '(face
      tabs spaces trailing lines space-before-tab newline
***************
*** 392,411 ****
  
  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 which have columns beyond
  			`whitespace-line-column' are highlighted via
--- 452,471 ----
  
  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 which have columns beyond
  			`whitespace-line-column' are highlighted via
*************** It's a list containing some or all of th
*** 414,420 ****
  			It has precedence over `lines-tail' (see
  			below).
  			It has effect only if `face' (see above)
! 			is present in `whitespace-style'.
  
     lines-tail		lines which have columns beyond
  			`whitespace-line-column' are highlighted via
--- 474,480 ----
  			It has precedence over `lines-tail' (see
  			below).
  			It has effect only if `face' (see above)
! 			is present in whitespace style.
  
     lines-tail		lines which have columns beyond
  			`whitespace-line-column' are highlighted via
*************** It's a list containing some or all of th
*** 422,497 ****
  			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'
  			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.
  
     tab-mark		TABs are visualized via display table.
  
!    newline-mark		NEWLINEs are visualized via display table.
  
  Any other value is ignored.
  
--- 482,557 ----
  			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
  			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.
  
     tab-mark		TABs are visualized via display table.
  
!    newline-mark	NEWLINEs are visualized via display table.
  
  Any other value is ignored.
  
*************** If nil, don't visualize TABs, (HARD) SPA
*** 499,508 ****
  via display table.
  
  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
! these values is:
  
   * For indentation:
     1. indentation
--- 559,567 ----
  via display table.
  
  There is an evaluation order for some values, if they are
! present, for example if indentation, indentation::tab and/or
! indentation::space are included.  The evaluation order for these
! values is:
  
   * For indentation:
     1. indentation
*************** these values is:
*** 520,564 ****
     3. space-before-tab::space
  
  So, for example, if indentation and indentation::space are
! included in `whitespace-style' list, the indentation value is
! evaluated instead of indentation::space value.
  
  One reason for not visualize spaces via faces (if `face' is not
! included in `whitespace-style') is to use exclusively for
  cleaning 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"
! 				spaces)
! 			 (const :tag "(Face) TABs" tabs)
! 			 (const :tag "(Face) Lines" lines)
! 			 (const :tag "(Face) SPACEs before TAB"
! 				space-before-tab)
! 			 (const :tag "(Face) NEWLINEs" newline)
! 			 (const :tag "(Face) Indentation SPACEs"
! 				indentation)
! 			 (const :tag "(Face) Empty Lines At BOB And/Or EOB"
! 				empty)
! 			 (const :tag "(Face) SPACEs after TAB"
! 				space-after-tab)
! 			 (const :tag "(Mark) SPACEs and HARD SPACEs"
! 				space-mark)
! 			 (const :tag "(Mark) TABs" tab-mark)
! 			 (const :tag "(Mark) NEWLINEs" newline-mark)))
    :group 'whitespace)

  (defcustom whitespace-space 'whitespace-space
    "Symbol face used to visualize SPACE.
  
! Used when `whitespace-style' includes the value `spaces'."
    :type 'face
    :group 'whitespace)
  
--- 579,621 ----
     3. space-before-tab::space
  
  So, for example, if indentation and indentation::space are
! included, 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
  cleaning up a buffer.  See `whitespace-cleanup' and
  `whitespace-cleanup-region' for documentation.
  
+ Whitespace determines which style to use on a specific buffer by
+ trying a match from `whitespace-file-style', then from
+ `whitespace-mode-style' and then by falling back to this
+ variable.
+ 
  See also `whitespace-display-mappings' for documentation."
!   :type whitespace-style-custom-type
    :group 'whitespace)
  
+ (defun whitespace-style ()
+   "Determine which style to use on current buffer."
+   (let (match)
+     (when buffer-file-name
+       (let ((styles whitespace-file-style)
+ 	    style)
+ 	(while (and (not match) (setq style (pop styles)))
+ 	  (when (string-match (car style) buffer-file-name)
+ 	    (setq match style)))))
+     (unless match
+       (setq match (assoc major-mode whitespace-mode-style)))
+     (if match
+ 	(cdr match)
+       whitespace-style)))
+ 
  
  (defcustom 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 th
*** 576,582 ****
  (defcustom whitespace-hspace 'whitespace-hspace
    "Symbol face used to visualize HARD SPACE.
  
! Used when `whitespace-style' includes the value `spaces'."
    :type 'face
    :group 'whitespace)
  
--- 633,639 ----
  (defcustom 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 th
*** 594,600 ****
  (defcustom whitespace-tab 'whitespace-tab
    "Symbol face used to visualize TAB.
  
! Used when `whitespace-style' includes the value `tabs'."
    :type 'face
    :group 'whitespace)
  
--- 651,657 ----
  (defcustom 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 th
*** 614,620 ****
  
  See `whitespace-display-mappings'.
  
! Used when `whitespace-style' includes the values `newline-mark'
  and `newline'."
    :type 'face
    :group 'whitespace)
--- 671,677 ----
  
  See `whitespace-display-mappings'.
  
! Used when whitespace style includes the values `newline-mark'
  and `newline'."
    :type 'face
    :group 'whitespace)
*************** See `whitespace-display-mappings'."
*** 637,643 ****
  (defcustom whitespace-trailing 'whitespace-trailing
    "Symbol face used to visualize trailing blanks.
  
! Used when `whitespace-style' includes the value `trailing'."
    :type 'face
    :group 'whitespace)
  
--- 694,700 ----
  (defcustom 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 th
*** 655,661 ****
  
  See `whitespace-line-column'.
  
! Used when `whitespace-style' includes the value `line'."
    :type 'face
    :group 'whitespace)
  
--- 712,718 ----
  
  See `whitespace-line-column'.
  
! Used when whitespace style includes the value `line'."
    :type 'face
    :group 'whitespace)
  
*************** See `whitespace-line-column'."
*** 672,678 ****
  (defcustom 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)
  
--- 729,735 ----
  (defcustom 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 th
*** 687,693 ****
  (defcustom 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)
  
--- 744,750 ----
  (defcustom 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 th
*** 702,708 ****
  (defcustom 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)
  
--- 759,765 ----
  (defcustom 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 th
*** 717,723 ****
  (defcustom 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)
  
--- 774,780 ----
  (defcustom 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)
  
*************** visualize only HARD SPACEs between TABs.
*** 753,759 ****
  NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
        Use exactly one pair of enclosing \\\\( and \\\\).
  
! Used when `whitespace-style' includes `spaces'."
    :type '(regexp :tag "HARD SPACE Chars")
    :group 'whitespace)
  
--- 810,816 ----
  NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
        Use exactly one pair of enclosing \\\\( and \\\\).
  
! Used when whitespace style includes `spaces'."
    :type '(regexp :tag "HARD SPACE Chars")
    :group 'whitespace)
  
*************** visualize leading and/or trailing SPACEs
*** 775,781 ****
  NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
        Use exactly one pair of enclosing \\\\( and \\\\).
  
! Used when `whitespace-style' includes `spaces'."
    :type '(regexp :tag "SPACE Chars")
    :group 'whitespace)
  
--- 832,838 ----
  NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
        Use exactly one pair of enclosing \\\\( and \\\\).
  
! Used when whitespace style includes `spaces'."
    :type '(regexp :tag "SPACE Chars")
    :group 'whitespace)
  
*************** visualize leading and/or trailing TABs.
*** 797,803 ****
  NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
        Use exactly one pair of enclosing \\\\( and \\\\).
  
! Used when `whitespace-style' includes `tabs'."
    :type '(regexp :tag "TAB Chars")
    :group 'whitespace)
  
--- 854,860 ----
  NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
        Use exactly one pair of enclosing \\\\( and \\\\).
  
! Used when whitespace style includes `tabs'."
    :type '(regexp :tag "TAB Chars")
    :group 'whitespace)
  
*************** that should be considered blank.
*** 815,821 ****
  NOTE: Enclose always by \"\\\\(\" and \"\\\\)$\" the elements to highlight.
        Use exactly one pair of enclosing elements above.
  
! Used when `whitespace-style' includes `trailing'."
    :type '(regexp :tag "Trailing Chars")
    :group 'whitespace)
  
--- 872,878 ----
  NOTE: Enclose always by \"\\\\(\" and \"\\\\)$\" the elements to highlight.
        Use exactly one pair of enclosing elements above.
  
! Used when whitespace style includes `trailing'."
    :type '(regexp :tag "Trailing Chars")
    :group 'whitespace)
  
*************** If you're using `mule' package, there ma
*** 830,836 ****
  
  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")
    :group 'whitespace)
--- 887,893 ----
  
  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")
    :group 'whitespace)
*************** If you're using `mule' package, there ma
*** 851,857 ****
  
  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"))
--- 908,914 ----
  
  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"))
*************** If you're using `mule' package, there ma
*** 868,874 ****
  
  that should be considered blank.
  
! Used when `whitespace-style' includes `empty'."
    :type '(regexp :tag "Empty Lines At Beginning Of Buffer")
    :group 'whitespace)
  
--- 925,931 ----
  
  that should be considered blank.
  
! Used when whitespace style includes `empty'."
    :type '(regexp :tag "Empty Lines At Beginning Of Buffer")
    :group 'whitespace)
  
*************** If you're using `mule' package, there ma
*** 883,889 ****
  
  that should be considered blank.
  
! Used when `whitespace-style' includes `empty'."
    :type '(regexp :tag "Empty Lines At End Of Buffer")
    :group 'whitespace)
  
--- 940,946 ----
  
  that should be considered blank.
  
! Used when whitespace style includes `empty'."
    :type '(regexp :tag "Empty Lines At End Of Buffer")
    :group 'whitespace)
  
*************** If you're using `mule' package, there ma
*** 903,909 ****
  
  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")
    :group 'whitespace)
--- 960,966 ----
  
  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")
    :group 'whitespace)
*************** Used when `whitespace-style' includes `s
*** 915,921 ****
  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 '(choice :tag "Line Length Limit"
  		 (integer :tag "Line Length")
  		 (const :tag "Use fill-column" nil))
--- 972,978 ----
  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 '(choice :tag "Line Length Limit"
  		 (integer :tag "Line Length")
  		 (const :tag "Use fill-column" nil))
*************** VECTOR	is a vector of characters to be d
*** 969,975 ****
  The NEWLINE character is displayed using the face given by
  `whitespace-newline' variable.
  
! Used when `whitespace-style' includes `tab-mark', `space-mark' or
  `newline-mark'."
    :type '(repeat
  	  (list :tag "Character Mapping"
--- 1026,1032 ----
  The NEWLINE character is displayed using the face given by
  `whitespace-newline' variable.
  
! Used when whitespace style includes `tab-mark', `space-mark' or
  `newline-mark'."
    :type '(repeat
  	  (list :tag "Character Mapping"
*************** C++ modes only."
*** 1016,1026 ****
  			      (symbol :tag "Mode"))))
    :group 'whitespace)

  (defcustom whitespace-action nil
!   "Specify which action is taken when a buffer is visited or written.
  
! It's a list containing some or all of the following values:
  
     nil			no action is taken.
  
--- 1073,1137 ----
  			      (symbol :tag "Mode"))))
    :group 'whitespace)
  
+ (defconst whitespace-action-custom-type
+   '(choice :tag "Actions"
+ 	   (const :tag "None" nil)
+ 	   (repeat :tag "Action List"
+ 		   (choice :tag "Action"
+ 			   (const :tag "Cleanup When On" cleanup)
+ 			   (const :tag "Report On Bogus" report-on-bogus)
+ 			   (const :tag "Auto Cleanup" auto-cleanup)
+ 			   (const :tag "Abort On Bogus" abort-on-bogus)
+ 			   (const :tag "Warn If Read-Only"
+ 				  warn-if-read-only))))
+   ;; Custom type specification for Whitespace actions. Used in
+   ;; WHITESPACE-FILE-ACTION, WHITESPACE-MODE-ACTION and
+   ;; WHITESPACE-ACTION.
+   )
+ 
+ (defcustom whitespace-file-action nil
+   "File-specific actions to take when a buffer is visited or written.
+ 
+ This is a list of elements of the form (REGEXP ACTION...) where
+ REGEXP is matched against file names.  For a list of possible
+ ACTIONs, see `whitespace-action'.
+ 
+ Whitespace determines which actions need to be taken on a
+ specific buffer by trying a match from this variable, then from
+ `whitespace-mode-action' and then by falling back to
+ `whitespace-action'."
+   :type `(repeat (cons :value ("")
+ 		       (regexp :tag "File Name Matching")
+ 		       ,whitespace-action-custom-type))
+   :version "24.3"
+   :group 'whitespace)
+ 
+ (defcustom whitespace-mode-action nil
+   "Mode-specific actions to take when a buffer is visited or written.
+ 
+ This is a list of elements of the form (MODE ACTION...) where
+ MODE is a major mode name.  For a list of possible ACTIONs, see
+ `whitespace-action'.
+ 
+ Whitespace determines which actions need to be taken on a
+ specific buffer by trying a match from `whitespace-file-action',
+ then from this variable and then by falling back to
+ `whitespace-action'."
+   :type `(repeat (cons :value (fundamental-mode)
+ 		       (symbol :tag "Major Mode")
+ 		       ,whitespace-action-custom-type))
+   :version "24.3"
+   :group 'whitespace)
  
  (defcustom whitespace-action nil
!   "Default actions to take when a buffer is visited or written.
  
! Whitespace determines which actions need to be taken on a
! specific buffer by trying a match from `whitespace-file-action',
! then from `whitespace-mode-action' and then by falling back to
! this variable.
! 
! Its value is a list containing some or all of the following symbols:
  
     nil			no action is taken.
  
*************** It's a list containing some or all of th
*** 1032,1038 ****
     report-on-bogus	report if there is any bogus whitespace always
  			when local whitespace is turned on.
  
!    auto-cleanup		cleanup any bogus whitespace when buffer is
  			written.
  			See `whitespace-cleanup' and
  			`whitespace-cleanup-region'.
--- 1143,1149 ----
     report-on-bogus	report if there is any bogus whitespace always
  			when local whitespace is turned on.
  
!    auto-cleanup	cleanup any bogus whitespace when buffer is
  			written.
  			See `whitespace-cleanup' and
  			`whitespace-cleanup-region'.
*************** It's a list containing some or all of th
*** 1041,1061 ****
  			buffer is written.
  
     warn-if-read-only	give a warning if `cleanup' or `auto-cleanup'
! 			is included in `whitespace-action' and the
! 			buffer is read-only.
  
  Any other value is treated as nil."
!   :type '(choice :tag "Actions"
! 		 (const :tag "None" nil)
! 		 (repeat :tag "Action List"
! 		  (choice :tag "Action"
! 			  (const :tag "Cleanup When On" cleanup)
! 			  (const :tag "Report On Bogus" report-on-bogus)
! 			  (const :tag "Auto Cleanup" auto-cleanup)
! 			  (const :tag "Abort On Bogus" abort-on-bogus)
! 			  (const :tag "Warn If Read-Only" warn-if-read-only))))
    :group 'whitespace)
  
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;;; User commands - Local mode
--- 1152,1179 ----
  			buffer is written.
  
     warn-if-read-only	give a warning if `cleanup' or `auto-cleanup'
! 			is present and the buffer is read-only.
  
  Any other value is treated as nil."
!   :type whitespace-action-custom-type
    :group 'whitespace)
  
+ (defun whitespace-action ()
+   "Determine which actions to take on current buffer."
+   (let (match)
+     (when buffer-file-name
+       (let ((actions whitespace-file-action)
+ 	    action)
+ 	(while (and (not match) (setq action (pop actions)))
+ 	  (when (string-match (car action) buffer-file-name)
+ 	    (setq match action)))))
+     (unless match
+       (setq match (assoc major-mode whitespace-mode-action)))
+     (if match
+ 	(cdr match)
+       whitespace-action)))
+ 
+ 
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;;; User commands - Local mode
*************** See also `whitespace-newline' and `white
*** 1188,1194 ****
    :group      'whitespace
    (let ((whitespace-style '(newline-mark newline)))
      (global-whitespace-mode (if global-whitespace-newline-mode
!                                 1 -1))
      ;; sync states (running a batch job)
      (setq global-whitespace-newline-mode global-whitespace-mode)))
  
--- 1306,1312 ----
    :group      'whitespace
    (let ((whitespace-style '(newline-mark newline)))
      (global-whitespace-mode (if global-whitespace-newline-mode
! 				1 -1))
      ;; sync states (running a batch job)
      (setq global-whitespace-newline-mode global-whitespace-mode)))
  
*************** See also `whitespace-newline' and `white
*** 1220,1226 ****
      space-mark
      newline-mark
      )
!   "List of valid `whitespace-style' values.")

  (defconst whitespace-toggle-option-alist
--- 1338,1344 ----
      space-mark
      newline-mark
      )
!   "List of valid whitespace style values.")

  (defconst whitespace-toggle-option-alist
*************** SYMBOL	is a valid symbol associated with
*** 1261,1267 ****

  (defvar whitespace-active-style nil
!   "Used to save locally `whitespace-style' value.")
  
  (defvar whitespace-indent-tabs-mode indent-tabs-mode
    "Used to save locally `indent-tabs-mode' value.")
--- 1379,1385 ----

  (defvar whitespace-active-style nil
!   "Used to save locally whitespace style value.")
  
  (defvar whitespace-indent-tabs-mode indent-tabs-mode
    "Used to save locally `indent-tabs-mode' value.")
*************** Interactively, it reads one of the follo
*** 1328,1334 ****
     S	toggle SPACEs before TAB visualization
     N	toggle NEWLINE visualization
  
!    x	restore `whitespace-style' value
     ?	display brief help
  
  Non-interactively, ARG should be a symbol or a list of symbols.
--- 1446,1452 ----
     S	toggle SPACEs before TAB visualization
     N	toggle NEWLINE visualization
  
!    x	restore original whitespace style
     ?	display brief help
  
  Non-interactively, ARG should be a symbol or a list of symbols.
*************** The valid symbols are:
*** 1346,1352 ****
     indentation::tab	toggle indentation SPACEs visualization
     indentation::space	toggle indentation TABs visualization
     space-after-tab		toggle SPACEs after TAB visualization
!    space-after-tab::tab		toggle SPACEs after TAB: SPACEs visualization
     space-after-tab::space	toggle SPACEs after TAB: TABs visualization
     space-before-tab		toggle SPACEs before TAB visualization
     space-before-tab::tab	toggle SPACEs before TAB: SPACEs visualization
--- 1464,1470 ----
     indentation::tab	toggle indentation SPACEs visualization
     indentation::space	toggle indentation TABs visualization
     space-after-tab		toggle SPACEs after TAB visualization
!    space-after-tab::tab	toggle SPACEs after TAB: SPACEs visualization
     space-after-tab::space	toggle SPACEs after TAB: TABs visualization
     space-before-tab		toggle SPACEs before TAB visualization
     space-before-tab::tab	toggle SPACEs before TAB: SPACEs visualization
*************** The valid symbols are:
*** 1356,1362 ****
     space-mark		toggle SPACEs before TAB visualization
     newline-mark		toggle NEWLINE visualization
  
!    whitespace-style	restore `whitespace-style' value
  
  See `whitespace-style' and `indent-tabs-mode' for documentation."
    (interactive (whitespace-interactive-char t))
--- 1474,1480 ----
     space-mark		toggle SPACEs before TAB visualization
     newline-mark		toggle NEWLINE visualization
  
!    whitespace-style	restore original whitespace style
  
  See `whitespace-style' and `indent-tabs-mode' for documentation."
    (interactive (whitespace-interactive-char t))
*************** Interactively, it accepts one of the fol
*** 1407,1413 ****
     S	toggle SPACEs before TAB visualization
     N	toggle NEWLINE visualization
  
!    x	restore `whitespace-style' value
     ?	display brief help
  
  Non-interactively, ARG should be a symbol or a list of symbols.
--- 1525,1531 ----
     S	toggle SPACEs before TAB visualization
     N	toggle NEWLINE visualization
  
!    x	restore original whitespace style
     ?	display brief help
  
  Non-interactively, ARG should be a symbol or a list of symbols.
*************** The valid symbols are:
*** 1435,1441 ****
     space-mark		toggle SPACEs before TAB visualization
     newline-mark		toggle NEWLINE visualization
  
!    whitespace-style	restore `whitespace-style' value
  
  See `whitespace-style' and `indent-tabs-mode' for documentation."
    (interactive (whitespace-interactive-char nil))
--- 1553,1559 ----
     space-mark		toggle SPACEs before TAB visualization
     newline-mark		toggle NEWLINE visualization
  
!    whitespace-style	restore original whitespace style
  
  See `whitespace-style' and `indent-tabs-mode' for documentation."
    (interactive (whitespace-interactive-char nil))
*************** The problems cleaned up are:
*** 1466,1504 ****
  
  1. empty lines at beginning of buffer.
  2. empty lines at end of buffer.
!    If `whitespace-style' includes the value `empty', remove all
     empty lines at beginning and/or end of buffer.
  
  3. 8 or more SPACEs at beginning of line.
!    If `whitespace-style' includes the value `indentation':
     replace 8 or more SPACEs at beginning of line by TABs, if
     `indent-tabs-mode' is non-nil; otherwise, replace TABs by
     SPACEs.
!    If `whitespace-style' includes the value `indentation::tab',
     replace 8 or more SPACEs at beginning of line by TABs.
!    If `whitespace-style' includes the value `indentation::space',
     replace TABs by SPACEs.
  
  4. SPACEs before TAB.
!    If `whitespace-style' includes the value `space-before-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If `whitespace-style' includes the value
     `space-before-tab::tab', replace SPACEs by TABs.
!    If `whitespace-style' includes the value
     `space-before-tab::space', replace TABs by SPACEs.
  
  5. SPACEs or TABs at end of line.
!    If `whitespace-style' includes the value `trailing', remove
     all SPACEs or TABs at end of line.
  
  6. 8 or more SPACEs after TAB.
!    If `whitespace-style' includes the value `space-after-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If `whitespace-style' includes the value
     `space-after-tab::tab', replace SPACEs by TABs.
!    If `whitespace-style' includes the value
     `space-after-tab::space', replace TABs by SPACEs.
  
  See `whitespace-style', `indent-tabs-mode' and `tab-width' for
--- 1584,1622 ----
  
  1. empty lines at beginning of buffer.
  2. empty lines at end of buffer.
!    If whitespace style includes the value `empty', remove all
     empty lines at beginning and/or end of buffer.
  
  3. 8 or more SPACEs at beginning of line.
!    If whitespace style includes the value `indentation':
     replace 8 or more SPACEs at beginning of line by TABs, if
     `indent-tabs-mode' is non-nil; otherwise, replace TABs by
     SPACEs.
!    If whitespace style includes the value `indentation::tab',
     replace 8 or more SPACEs at beginning of line by TABs.
!    If whitespace style includes the value `indentation::space',
     replace TABs by SPACEs.
  
  4. SPACEs before TAB.
!    If whitespace style includes the value `space-before-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If whitespace style includes the value
     `space-before-tab::tab', replace SPACEs by TABs.
!    If whitespace style includes the value
     `space-before-tab::space', replace TABs by SPACEs.
  
  5. SPACEs or TABs at end of line.
!    If whitespace style includes the value `trailing', remove
     all SPACEs or TABs at end of line.
  
  6. 8 or more SPACEs after TAB.
!    If whitespace style includes the value `space-after-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If whitespace style includes the value
     `space-after-tab::tab', replace SPACEs by TABs.
!    If whitespace style includes the value
     `space-after-tab::space', replace TABs by SPACEs.
  
  See `whitespace-style', `indent-tabs-mode' and `tab-width' for
*************** documentation."
*** 1525,1531 ****
  	;; PROBLEM 1: empty lines at bob
  	;; PROBLEM 2: empty lines at eob
  	;; ACTION: remove all empty lines at bob and/or eob
! 	(when (memq 'empty whitespace-style)
  	  (let (overwrite-mode)		; enforce no overwrite
  	    (goto-char (point-min))
  	    (when (looking-at whitespace-empty-at-bob-regexp)
--- 1643,1649 ----
  	;; PROBLEM 1: empty lines at bob
  	;; PROBLEM 2: empty lines at eob
  	;; ACTION: remove all empty lines at bob and/or eob
! 	(when (memq 'empty (whitespace-style))
  	  (let (overwrite-mode)		; enforce no overwrite
  	    (goto-char (point-min))
  	    (when (looking-at whitespace-empty-at-bob-regexp)
*************** documentation."
*** 1547,1584 ****
  The problems cleaned up are:
  
  1. 8 or more SPACEs at beginning of line.
!    If `whitespace-style' includes the value `indentation':
     replace 8 or more SPACEs at beginning of line by TABs, if
     `indent-tabs-mode' is non-nil; otherwise, replace TABs by
     SPACEs.
!    If `whitespace-style' includes the value `indentation::tab',
     replace 8 or more SPACEs at beginning of line by TABs.
!    If `whitespace-style' includes the value `indentation::space',
     replace TABs by SPACEs.
  
  2. SPACEs before TAB.
!    If `whitespace-style' includes the value `space-before-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If `whitespace-style' includes the value
     `space-before-tab::tab', replace SPACEs by TABs.
!    If `whitespace-style' includes the value
     `space-before-tab::space', replace TABs by SPACEs.
  
  3. SPACEs or TABs at end of line.
!    If `whitespace-style' includes the value `trailing', remove
     all SPACEs or TABs at end of line.
  
  4. 8 or more SPACEs after TAB.
!    If `whitespace-style' includes the value `space-after-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If `whitespace-style' includes the value
     `space-after-tab::tab', replace SPACEs by TABs.
!    If `whitespace-style' includes the value
     `space-after-tab::space', replace TABs by SPACEs.
  
! See `whitespace-style', `indent-tabs-mode' and `tab-width' for
  documentation."
    (interactive "@r")
    (if buffer-read-only
--- 1665,1702 ----
  The problems cleaned up are:
  
  1. 8 or more SPACEs at beginning of line.
!    If whitespace style includes the value `indentation':
     replace 8 or more SPACEs at beginning of line by TABs, if
     `indent-tabs-mode' is non-nil; otherwise, replace TABs by
     SPACEs.
!    If whitespace style includes the value `indentation::tab',
     replace 8 or more SPACEs at beginning of line by TABs.
!    If whitespace style includes the value `indentation::space',
     replace TABs by SPACEs.
  
  2. SPACEs before TAB.
!    If whitespace style includes the value `space-before-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If whitespace style includes the value
     `space-before-tab::tab', replace SPACEs by TABs.
!    If whitespace style includes the value
     `space-before-tab::space', replace TABs by SPACEs.
  
  3. SPACEs or TABs at end of line.
!    If whitespace style includes the value `trailing', remove
     all SPACEs or TABs at end of line.
  
  4. 8 or more SPACEs after TAB.
!    If whitespace style includes the value `space-after-tab':
     replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
     otherwise, replace TABs by SPACEs.
!    If whitespace style includes the value
     `space-after-tab::tab', replace SPACEs by TABs.
!    If whitespace style includes the value
     `space-after-tab::space', replace TABs by SPACEs.
  
! See whitespace style, `indent-tabs-mode' and `tab-width' for
  documentation."
    (interactive "@r")
    (if buffer-read-only
*************** documentation."
*** 1598,1604 ****
  	   ;; 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)
--- 1716,1722 ----
  	   ;; 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)
*************** documentation."
*** 1608,1625 ****
  		(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))
--- 1726,1743 ----
  		(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))
*************** documentation."
*** 1628,1644 ****
  	   ;; 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)))
--- 1746,1762 ----
  	   ;; 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)))
*************** documentation."
*** 1647,1664 ****
  	   ;; 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 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 0))
  	   ;; ACTION: replace TABs by SPACEs.
! 	   ((memq 'space-before-tab::space whitespace-style)
  	    (whitespace-replace-action
  	     'untabify rstart rend
  	     whitespace-space-before-tab-regexp 2)))))
--- 1765,1782 ----
  	   ;; 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 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 0))
  	   ;; ACTION: replace TABs by SPACEs.
! 	   ((memq 'space-before-tab::space (whitespace-style))
  	    (whitespace-replace-action
  	     'untabify rstart rend
  	     whitespace-space-before-tab-regexp 2)))))
*************** non-nil.
*** 1783,1789 ****
  
  If FORCE is non-nil or \\[universal-argument] was pressed just
  before calling `whitespace-report' interactively, it forces
! `whitespace-style' to have:
  
     empty
     trailing
--- 1901,1907 ----
  
  If FORCE is non-nil or \\[universal-argument] was pressed just
  before calling `whitespace-report' interactively, it forces
! whitespace style to have:
  
     empty
     trailing
*************** non-nil.
*** 1829,1835 ****
  
  If FORCE is non-nil or \\[universal-argument] was pressed just
  before calling `whitespace-report-region' interactively, it
! forces `whitespace-style' to have:
  
     empty
     indentation
--- 1947,1953 ----
  
  If FORCE is non-nil or \\[universal-argument] was pressed just
  before calling `whitespace-report-region' interactively, it
! forces whitespace style to have:
  
     empty
     indentation
*************** cleaning up these problems."
*** 1865,1878 ****
    (setq force (or current-prefix-arg force))
    (save-excursion
      (save-match-data                ;FIXME: Why?
!       (let* ((has-bogus nil)
  	     (rstart    (min start end))
  	     (rend      (max start end))
  	     (bogus-list
  	      (mapcar
  	       #'(lambda (option)
  		   (when force
! 		     (add-to-list 'whitespace-style (car option)))
  		   (goto-char rstart)
  		   (let ((regexp
  			  (cond
--- 1983,1997 ----
    (setq force (or current-prefix-arg force))
    (save-excursion
      (save-match-data                ;FIXME: Why?
!       (let* ((style (whitespace-style))
! 	     (has-bogus nil)
  	     (rstart    (min start end))
  	     (rend      (max start end))
  	     (bogus-list
  	      (mapcar
  	       #'(lambda (option)
  		   (when force
! 		     (add-to-list 'style (car option)))
  		   (goto-char rstart)
  		   (let ((regexp
  			  (cond
*************** cleaning up these problems."
*** 1909,1916 ****
  	      (forward-line 3)
  	      (dolist (option whitespace-report-list)
  		(forward-line 1)
! 		(whitespace-mark-x
! 		 27 (memq (car option) whitespace-style))
  		(whitespace-mark-x 7 (car bogus-list))
  		(setq bogus-list (cdr bogus-list)))
  	      (forward-line 1)
--- 2028,2034 ----
  	      (forward-line 3)
  	      (dolist (option whitespace-report-list)
  		(forward-line 1)
! 		(whitespace-mark-x 27 (memq (car option) style))
  		(whitespace-mark-x 7 (car bogus-list))
  		(setq bogus-list (cdr bogus-list)))
  	      (forward-line 1)
*************** cleaning up these problems."
*** 1943,1949 ****
  (defconst whitespace-help-text
    "\
   Whitespace Toggle Options                  | scroll up  :  SPC   or > |
!                                             | scroll down:  M-SPC or < |
   FACES                                      \\__________________________/
   []  f   - toggle face visualization
   []  t   - toggle TAB visualization
--- 2061,2067 ----
  (defconst whitespace-help-text
    "\
   Whitespace Toggle Options                  | scroll up  :  SPC   or > |
! 					    | scroll down:  M-SPC or < |
   FACES                                      \\__________________________/
   []  f   - toggle face visualization
   []  t   - toggle TAB visualization
*************** cleaning up these problems."
*** 1968,1974 ****
   []  S - toggle SPACE and HARD SPACE visualization
   []  N - toggle NEWLINE visualization
  
!       x - restore `whitespace-style' value
  
        ? - display this text\n\n"
    "Text for whitespace toggle options.")
--- 2086,2092 ----
   []  S - toggle SPACE and HARD SPACE visualization
   []  N - toggle NEWLINE visualization
  
!       x - restore original whitespace style
  
        ? - display this text\n\n"
    "Text for whitespace toggle options.")
*************** It accepts one of the following chars:
*** 2092,2105 ****
     S	toggle SPACE and HARD SPACE visualization
     N	toggle NEWLINE visualization
  
!    x	restore `whitespace-style' value
     ?	display brief help
  
  See also `whitespace-toggle-option-alist'."
!   (let* ((is-off (not (if local-p
! 			  whitespace-mode
! 			global-whitespace-mode)))
! 	 (style  (cond (is-off  whitespace-style) ; use default value
  		       (local-p whitespace-active-style)
  		       (t       whitespace-toggle-style)))
  	 (prompt
--- 2210,2223 ----
     S	toggle SPACE and HARD SPACE visualization
     N	toggle NEWLINE visualization
  
!    x	restore original whitespace style
     ?	display brief help
  
  See also `whitespace-toggle-option-alist'."
!   (let* ((is-off (not (if local-p whitespace-mode global-whitespace-mode)))
! 	 (style  (cond (is-off (if local-p
! 				   (whitespace-style)
! 				 whitespace-style))
  		       (local-p whitespace-active-style)
  		       (t       whitespace-toggle-style)))
  	 (prompt
*************** ARG is a list of options to be toggled.
*** 2146,2152 ****
  THE-LIST is a list of options.  This list will be toggled and the
  resultant list will be returned."
    (unless (if local-p whitespace-mode global-whitespace-mode)
!     (setq the-list whitespace-style))
    (setq the-list (copy-sequence the-list)) ; keep original list
    (dolist (sym (if (listp arg) arg (list arg)))
      (cond
--- 2264,2270 ----
  THE-LIST is a list of options.  This list will be toggled and the
  resultant list will be returned."
    (unless (if local-p whitespace-mode global-whitespace-mode)
!     (setq the-list (if local-p (whitespace-style) whitespace-style)))
    (setq the-list (copy-sequence the-list)) ; keep original list
    (dolist (sym (if (listp arg) arg (list arg)))
      (cond
*************** resultant list will be returned."
*** 2154,2160 ****
       ((eq sym 'help-newline))
       ;; restore default values
       ((eq sym 'whitespace-style)
!       (setq the-list whitespace-style))
       ;; toggle valid values
       ((memq sym whitespace-style-value-list)
        (setq the-list (if (memq sym the-list)
--- 2272,2278 ----
       ((eq sym 'help-newline))
       ;; restore default values
       ((eq sym 'whitespace-style)
!       (setq the-list (if local-p (whitespace-style) whitespace-style)))
       ;; toggle valid values
       ((memq sym whitespace-style-value-list)
        (setq the-list (if (memq sym the-list)
*************** resultant list will be returned."
*** 2181,2189 ****
    (set (make-local-variable 'whitespace-display-table) nil)
    (set (make-local-variable 'whitespace-display-table-was-local) nil)
    (set (make-local-variable 'whitespace-active-style)
!        (if (listp whitespace-style)
! 	   whitespace-style
! 	 (list whitespace-style)))
    (set (make-local-variable 'whitespace-indent-tabs-mode)
         indent-tabs-mode)
    (set (make-local-variable 'whitespace-tab-width)
--- 2299,2307 ----
    (set (make-local-variable 'whitespace-display-table) nil)
    (set (make-local-variable 'whitespace-display-table-was-local) nil)
    (set (make-local-variable 'whitespace-active-style)
!        (if (listp (whitespace-style))
! 	   (whitespace-style)
! 	 (list (whitespace-style))))
    (set (make-local-variable 'whitespace-indent-tabs-mode)
         indent-tabs-mode)
    (set (make-local-variable 'whitespace-tab-width)
*************** Also refontify when necessary."
*** 2520,2526 ****
  	  (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)))))))
--- 2638,2644 ----
  	  (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)))))))
*************** Also refontify when necessary."
*** 2579,2585 ****
  	(setq buffer-display-table (make-display-table)))
        (dolist (entry whitespace-display-mappings)
  	;; check if it is to display this mark
! 	(when (memq (car entry) whitespace-style)
  	  ;; Get a displayable mapping.
  	  (setq vecs (cddr entry))
  	  (while (and vecs
--- 2697,2703 ----
  	(setq buffer-display-table (make-display-table)))
        (dolist (entry whitespace-display-mappings)
  	;; check if it is to display this mark
! 	(when (memq (car entry) (whitespace-style))
  	  ;; Get a displayable mapping.
  	  (setq vecs (cddr entry))
  	  (while (and vecs
*************** Also refontify when necessary."
*** 2618,2635 ****
  
  (defun whitespace-action-when-on ()
    "Action to be taken always when local whitespace is turned on."
!   (cond ((memq 'cleanup whitespace-action)
  	 (whitespace-cleanup))
! 	((memq 'report-on-bogus whitespace-action)
  	 (whitespace-report nil t))))

  (defun whitespace-write-file-hook ()
    "Action to be taken when buffer is written.
  It should be added buffer-locally to `write-file-functions'."
!   (cond ((memq 'auto-cleanup whitespace-action)
  	 (whitespace-cleanup))
! 	((memq 'abort-on-bogus whitespace-action)
  	 (when (whitespace-report nil t)
  	   (error "Abort write due to whitespace problems in %s"
  		  (buffer-name)))))
--- 2736,2753 ----
  
  (defun whitespace-action-when-on ()
    "Action to be taken always when local whitespace is turned on."
!   (cond ((memq 'cleanup (whitespace-action))
  	 (whitespace-cleanup))
! 	((memq 'report-on-bogus (whitespace-action))
  	 (whitespace-report nil t))))

  (defun whitespace-write-file-hook ()
    "Action to be taken when buffer is written.
  It should be added buffer-locally to `write-file-functions'."
!   (cond ((memq 'auto-cleanup (whitespace-action))
  	 (whitespace-cleanup))
! 	((memq 'abort-on-bogus (whitespace-action))
  	 (when (whitespace-report nil t)
  	   (error "Abort write due to whitespace problems in %s"
  		  (buffer-name)))))
*************** It should be added buffer-locally to `wr
*** 2638,2644 ****
  
  (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))))
  
  
--- 2756,2762 ----
  
  (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))))
  
  

-- 
ELS 2013, June 3/4, Madrid, Spain:  http://els2013.european-lisp-symposium.org

Scientific site:   http://www.lrde.epita.fr/~didier
Music (Jazz) site: http://www.didierverna.com