X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/d02fe47dd3be7310d1bfd6e802d1fac2ea5f5e9d..b336bfcdf39f1e4d35bff4a7bd01d3b4bca8f516:/lisp/whitespace.el diff --git a/lisp/whitespace.el b/lisp/whitespace.el index 6a29eb258e..4b8b9a6117 100644 --- a/lisp/whitespace.el +++ b/lisp/whitespace.el @@ -1,30 +1,28 @@ ;;; whitespace.el --- minor mode to visualize TAB, (HARD) SPACE, NEWLINE -;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 ;; Free Software Foundation, Inc. ;; Author: Vinicius Jose Latorre ;; Maintainer: Vinicius Jose Latorre ;; Keywords: data, wp -;; Version: 10.0 +;; Version: 13.1 ;; X-URL: http://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre ;; This file is part of GNU Emacs. -;; GNU Emacs is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published -;; by the Free Software Foundation; either version 3, or (at your -;; option) any later version. +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. -;; GNU Emacs is distributed in the hope that it will be useful, but -;; WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;; General Public License for more details. +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -46,8 +44,8 @@ ;; it provides a visual mark for characters, for example, at the end ;; of line (?\xB6), at SPACEs (?\xB7) and at TABs (?\xBB). ;; -;; The `whitespace-style-mark' and `whitespace-style-color' variables -;; are used to select which way should be used to visualize blanks. +;; The `whitespace-style' variable selects which way blanks are +;; visualized. ;; ;; Note that when whitespace is turned on, whitespace saves the ;; font-lock state, that is, if font-lock is on or off. And @@ -62,6 +60,11 @@ ;; characters over the default mechanism of `nobreak-char-display' ;; (which see) and `show-trailing-whitespace' (which see). ;; +;; The trailing spaces are not highlighted while point is at end of line. +;; Also the spaces at beginning of buffer are not highlighted while point is at +;; beginning of buffer; and the spaces at end of buffer are not highlighted +;; while point is at end of buffer. +;; ;; There are two ways of using whitespace: local and global. ;; ;; * Local whitespace affects only the current buffer. @@ -87,7 +90,7 @@ ;; ;; To use whitespace, insert in your ~/.emacs: ;; -;; (require 'whitespace-mode) +;; (require 'whitespace) ;; ;; Or autoload at least one of the commands`whitespace-mode', ;; `whitespace-toggle-options', `global-whitespace-mode' or @@ -162,6 +165,12 @@ ;; ;; There are also the following useful commands: ;; +;; `whitespace-newline-mode' +;; Toggle NEWLINE minor mode visualization ("nl" on modeline). +;; +;; `global-whitespace-newline-mode' +;; Toggle NEWLINE global minor mode visualization ("NL" on modeline). +;; ;; `whitespace-report' ;; Report some blank problems in buffer. ;; @@ -178,41 +187,39 @@ ;; ;; 1. empty lines at beginning of buffer. ;; 2. empty lines at end of buffer. -;; If `whitespace-style-color' includes the value `empty', remove -;; all empty lines at beginning and/or 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-color' includes the value `indentation': +;; 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-color' includes the value -;; `indentation::tab', replace 8 or more SPACEs at beginning of line -;; by TABs. -;; If `whitespace-style-color' includes the value -;; `indentation::space', 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-color' 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-color' includes the value +;; 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-color' includes the value +;; 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-color' includes the value `trailing', -;; remove all SPACEs or TABs at end of line. +;; If `whitespace-style' includes the value `trailing', remove all +;; SPACEs or TABs at end of line. ;; ;; 6. 8 or more SPACEs after TAB. -;; If `whitespace-style-color' 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-color' includes the value -;; `space-after-tab::tab', replace SPACEs by TABs. -;; If `whitespace-style-color' includes the value +;; 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. ;; ;; @@ -237,11 +244,8 @@ ;; Below it's shown a brief description of whitespace options, please, ;; see the options declaration in the code for a long documentation. ;; -;; `whitespace-style-mark' Specify which kind of blank is -;; visualized via display table. -;; -;; `whitespace-style-color' Specify which kind of blank is -;; visualized via faces. +;; `whitespace-style' Specify which kind of blank is +;; visualized. ;; ;; `whitespace-space' Face used to visualize SPACE. ;; @@ -303,18 +307,22 @@ ;; turned on. ;; ;; `whitespace-action' Specify which action is taken when a -;; buffer is visited, killed or written. +;; buffer is visited or written. ;; ;; ;; Acknowledgements ;; ---------------- ;; +;; Thanks to David Reitter for suggesting a +;; `whitespace-newline' initialization with low contrast relative to +;; the background color. +;; ;; Thanks to Stephen Deasey for the ;; `indent-tabs-mode' usage suggestion. ;; ;; Thanks to Eric Cooper for the suggestion to have hook -;; actions when buffer is written or killed as the original whitespace -;; package had. +;; actions when buffer is written as the original whitespace package +;; had. ;; ;; Thanks to nschum (EmacsWiki) for the idea about highlight "long" ;; lines tail. See EightyColumnRule (EmacsWiki). @@ -338,7 +346,7 @@ ;; "long" lines. See EightyColumnRule (EmacsWiki). ;; ;; Thanks to Yanghui Bian for indicating a new -;; newline character mapping. +;; NEWLINE character mapping. ;; ;; Thanks to Pete Forman for indicating ;; whitespace-mode.el on XEmacs. @@ -370,107 +378,129 @@ "Visualize blanks (TAB, (HARD) SPACE and NEWLINE)." :link '(emacs-library-link :tag "Source Lisp File" "whitespace.el") :version "23.1" - :group 'wp - :group 'data) + :group 'convenience) -(defcustom whitespace-style-mark '(space-mark tab-mark newline-mark) - "*Specify which kind of blank is visualized via display table. +(defcustom whitespace-style + '(face + tabs spaces trailing lines space-before-tab newline + indentation empty space-after-tab + space-mark tab-mark newline-mark) + "Specify which kind of blank is visualized. It's a list containing some or all of the following values: - space-mark SPACEs and HARD SPACEs are visualized. - - tab-mark TABs are visualized. - - newline-mark NEWLINEs are visualized. - -Any other value is ignored. - -If nil, don't visualize TABs, (HARD) SPACEs and NEWLINEs via display -table. - -See also `whitespace-display-mappings' for documentation." - :type '(repeat :tag "Kind of Blank Mark" - (choice :tag "Kind of Blank Mark" - (const :tag "SPACEs and HARD SPACEs" - space-mark) - (const :tag "TABs" tab-mark) - (const :tag "NEWLINEs" newline-mark))) - :group 'whitespace) - - -(defcustom whitespace-style-color - '(tabs spaces trailing lines space-before-tab newline - indentation empty space-after-tab) - "*Specify which kind of blank is visualized via faces. - -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. + trailing trailing blanks are visualized via faces. + It has effect only if `face' (see above) + is present in `whitespace-style'. - tabs TABs are visualized. + 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. + spaces SPACEs and HARD SPACEs are visualized via + faces. + It has effect only if `face' (see above) + is present in `whitespace-style'. - lines lines whose have columns beyond - `whitespace-line-column' are highlighted. + lines lines which have columns beyond + `whitespace-line-column' are highlighted via + faces. Whole line is highlighted. - It has precedence over - `lines-tail' (see below). - - lines-tail lines whose have columns beyond - `whitespace-line-column' are highlighted. + It has precedence over `lines-tail' (see + below). + It has effect only if `face' (see above) + is present in `whitespace-style'. + + lines-tail lines which have columns beyond + `whitespace-line-column' are highlighted via + faces. But only the part of line which goes beyond `whitespace-line-column' column. It has effect only if `lines' (see above) - is not present in `whitespace-style-color'. + is not present in `whitespace-style' + and if `face' (see above) is present in + `whitespace-style'. - newline NEWLINEs are visualized. + 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. + 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. + 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. + 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. + 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. + visualized via faces. + It has effect only if `face' (see above) + is present in `whitespace-style'. - space-after-tab::space TABs are visualized when occurs 8 or - more SPACEs after a TAB. + 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. + 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. + 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 occurs SPACEs - before TAB. + 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. + 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) SPACEs and NEWLINEs via faces. +If nil, don't visualize TABs, (HARD) SPACEs and NEWLINEs via faces and +via display table. -There is an evaluation order for some values, if some values are -included in `whitespace-style-color' list. For example, if +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-color' list. The evaluation order -for these values is: +included in `whitespace-style' list. The evaluation order for +these values is: * For indentation: 1. indentation @@ -488,97 +518,112 @@ for these values is: 3. space-before-tab::space So, for example, if indentation and indentation::space are -included in `whitespace-style-color' list, the indentation value -is evaluated instead of indentation::space value." - :type '(repeat :tag "Kind of Blank Face" +included in `whitespace-style' list, the indentation value is +evaluated instead of indentation::space value. + +One reason for not visualize spaces via faces (if `face' is not +included in `whitespace-style') is to use exclusively for +cleanning up a buffer. See `whitespace-cleanup' and +`whitespace-cleanup-region' for documentation. + +See also `whitespace-display-mappings' for documentation." + :type '(repeat :tag "Kind of Blank" (choice :tag "Kind of Blank Face" - (const :tag "Trailing TABs, SPACEs and HARD SPACEs" + (const :tag "(Face) Face visualization" + face) + (const :tag "(Face) Trailing TABs, SPACEs and HARD SPACEs" trailing) - (const :tag "SPACEs and HARD SPACEs" spaces) - (const :tag "TABs" tabs) - (const :tag "Lines" lines) - (const :tag "SPACEs before TAB" + (const :tag "(Face) SPACEs and HARD SPACEs" + spaces) + (const :tag "(Face) TABs" tabs) + (const :tag "(Face) Lines" lines) + (const :tag "(Face) SPACEs before TAB" space-before-tab) - (const :tag "NEWLINEs" newline) - (const :tag "Indentation SPACEs" indentation) - (const :tag "Empty Lines At BOB And/Or EOB" + (const :tag "(Face) NEWLINEs" newline) + (const :tag "(Face) Indentation SPACEs" + indentation) + (const :tag "(Face) Empty Lines At BOB And/Or EOB" empty) - (const :tag "SPACEs after TAB" - space-after-tab))) + (const :tag "(Face) SPACEs after TAB" + space-after-tab) + (const :tag "(Mark) SPACEs and HARD SPACEs" + space-mark) + (const :tag "(Mark) TABs" tab-mark) + (const :tag "(Mark) NEWLINEs" newline-mark))) :group 'whitespace) (defcustom whitespace-space 'whitespace-space - "*Symbol face used to visualize SPACE. + "Symbol face used to visualize SPACE. -Used when `whitespace-style-color' includes the value `spaces'." +Used when `whitespace-style' includes the value `spaces'." :type 'face :group 'whitespace) (defface whitespace-space '((((class color) (background dark)) - (:background "grey20" :foreground "aquamarine3")) + (:background "grey20" :foreground "darkgray")) (((class color) (background light)) - (:background "LightYellow" :foreground "aquamarine3")) + (:background "LightYellow" :foreground "lightgray")) (t (:inverse-video t))) "Face used to visualize SPACE." :group 'whitespace) (defcustom whitespace-hspace 'whitespace-hspace - "*Symbol face used to visualize HARD SPACE. + "Symbol face used to visualize HARD SPACE. -Used when `whitespace-style-color' includes the value `spaces'." +Used when `whitespace-style' includes the value `spaces'." :type 'face :group 'whitespace) (defface whitespace-hspace ; 'nobreak-space '((((class color) (background dark)) - (:background "grey24" :foreground "aquamarine3")) + (:background "grey24" :foreground "darkgray")) (((class color) (background light)) - (:background "LemonChiffon3" :foreground "aquamarine3")) + (:background "LemonChiffon3" :foreground "lightgray")) (t (:inverse-video t))) "Face used to visualize HARD SPACE." :group 'whitespace) (defcustom whitespace-tab 'whitespace-tab - "*Symbol face used to visualize TAB. + "Symbol face used to visualize TAB. -Used when `whitespace-style-color' includes the value `tabs'." +Used when `whitespace-style' includes the value `tabs'." :type 'face :group 'whitespace) (defface whitespace-tab '((((class color) (background dark)) - (:background "grey22" :foreground "aquamarine3")) + (:background "grey22" :foreground "darkgray")) (((class color) (background light)) - (:background "beige" :foreground "aquamarine3")) + (:background "beige" :foreground "lightgray")) (t (:inverse-video t))) "Face used to visualize TAB." :group 'whitespace) (defcustom whitespace-newline 'whitespace-newline - "*Symbol face used to visualize NEWLINE char mapping. + "Symbol face used to visualize NEWLINE char mapping. See `whitespace-display-mappings'. -Used when `whitespace-style-mark' includes the values `newline-mark' -and `whitespace-style-color' includes `newline'." +Used when `whitespace-style' includes the values `newline-mark' +and `newline'." :type 'face :group 'whitespace) (defface whitespace-newline '((((class color) (background dark)) - (:background "grey26" :foreground "aquamarine3" :bold t)) + (:foreground "darkgray" :bold nil)) (((class color) (background light)) - (:background "linen" :foreground "aquamarine3" :bold t)) - (t (:bold t :underline t))) + (:foreground "lightgray" :bold nil)) + (t (:underline t :bold nil))) "Face used to visualize NEWLINE char mapping. See `whitespace-display-mappings'." @@ -586,9 +631,9 @@ See `whitespace-display-mappings'." (defcustom whitespace-trailing 'whitespace-trailing - "*Symbol face used to visualize traling blanks. + "Symbol face used to visualize trailing blanks. -Used when `whitespace-style-color' includes the value `trailing'." +Used when `whitespace-style' includes the value `trailing'." :type 'face :group 'whitespace) @@ -601,11 +646,11 @@ Used when `whitespace-style-color' includes the value `trailing'." (defcustom whitespace-line 'whitespace-line - "*Symbol face used to visualize \"long\" lines. + "Symbol face used to visualize \"long\" lines. See `whitespace-line-column'. -Used when `whitespace-style-color' includes the value `line'." +Used when `whitespace-style' includes the value `line'." :type 'face :group 'whitespace) @@ -620,9 +665,9 @@ See `whitespace-line-column'." (defcustom whitespace-space-before-tab 'whitespace-space-before-tab - "*Symbol face used to visualize SPACEs before TAB. + "Symbol face used to visualize SPACEs before TAB. -Used when `whitespace-style-color' includes the value `space-before-tab'." +Used when `whitespace-style' includes the value `space-before-tab'." :type 'face :group 'whitespace) @@ -635,9 +680,9 @@ Used when `whitespace-style-color' includes the value `space-before-tab'." (defcustom whitespace-indentation 'whitespace-indentation - "*Symbol face used to visualize 8 or more SPACEs at beginning of line. + "Symbol face used to visualize 8 or more SPACEs at beginning of line. -Used when `whitespace-style-color' includes the value `indentation'." +Used when `whitespace-style' includes the value `indentation'." :type 'face :group 'whitespace) @@ -650,9 +695,9 @@ Used when `whitespace-style-color' includes the value `indentation'." (defcustom whitespace-empty 'whitespace-empty - "*Symbol face used to visualize empty lines at beginning and/or end of buffer. + "Symbol face used to visualize empty lines at beginning and/or end of buffer. -Used when `whitespace-style-color' includes the value `empty'." +Used when `whitespace-style' includes the value `empty'." :type 'face :group 'whitespace) @@ -665,9 +710,9 @@ Used when `whitespace-style-color' includes the value `empty'." (defcustom whitespace-space-after-tab 'whitespace-space-after-tab - "*Symbol face used to visualize 8 or more SPACEs after TAB. + "Symbol face used to visualize 8 or more SPACEs after TAB. -Used when `whitespace-style-color' includes the value `space-after-tab'." +Used when `whitespace-style' includes the value `space-after-tab'." :type 'face :group 'whitespace) @@ -681,7 +726,7 @@ Used when `whitespace-style-color' includes the value `space-after-tab'." (defcustom whitespace-hspace-regexp "\\(\\(\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)" - "*Specify HARD SPACE characters regexp. + "Specify HARD SPACE characters regexp. If you're using `mule' package, there may be other characters besides: @@ -703,13 +748,13 @@ visualize only HARD SPACEs between TABs. NOTE: Enclose always by \\\\( and \\\\) the elements to highlight. Use exactly one pair of enclosing \\\\( and \\\\). -Used when `whitespace-style-color' includes `spaces'." +Used when `whitespace-style' includes `spaces'." :type '(regexp :tag "HARD SPACE Chars") :group 'whitespace) (defcustom whitespace-space-regexp "\\( +\\)" - "*Specify SPACE characters regexp. + "Specify SPACE characters regexp. If you're using `mule' package, there may be other characters besides \" \" that should be considered SPACE. @@ -725,13 +770,13 @@ visualize leading and/or trailing SPACEs. NOTE: Enclose always by \\\\( and \\\\) the elements to highlight. Use exactly one pair of enclosing \\\\( and \\\\). -Used when `whitespace-style-color' includes `spaces'." +Used when `whitespace-style' includes `spaces'." :type '(regexp :tag "SPACE Chars") :group 'whitespace) (defcustom whitespace-tab-regexp "\\(\t+\\)" - "*Specify TAB characters regexp. + "Specify TAB characters regexp. If you're using `mule' package, there may be other characters besides \"\\t\" that should be considered TAB. @@ -747,14 +792,14 @@ visualize leading and/or trailing TABs. NOTE: Enclose always by \\\\( and \\\\) the elements to highlight. Use exactly one pair of enclosing \\\\( and \\\\). -Used when `whitespace-style-color' includes `tabs'." +Used when `whitespace-style' includes `tabs'." :type '(regexp :tag "TAB Chars") :group 'whitespace) (defcustom whitespace-trailing-regexp - "\t\\| \\|\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20" - "*Specify trailing characters regexp. + "\\(\\(\t\\| \\|\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)$" + "Specify trailing characters regexp. If you're using `mule' package, there may be other characters besides: @@ -763,17 +808,16 @@ If you're using `mule' package, there may be other characters besides: that should be considered blank. -NOTE: DO NOT enclose by \\\\( and \\\\) the elements to highlight. - `whitespace-mode' surrounds this regexp by \"\\\\(\\\\(\" and - \"\\\\)+\\\\)$\". +NOTE: Enclose always by \"\\\\(\" and \"\\\\)$\" the elements to highlight. + Use exactly one pair of enclosing elements above. -Used when `whitespace-style-color' includes `trailing'." +Used when `whitespace-style' includes `trailing'." :type '(regexp :tag "Trailing Chars") :group 'whitespace) (defcustom whitespace-space-before-tab-regexp "\\( +\\)\\(\t+\\)" - "*Specify SPACEs before TAB regexp. + "Specify SPACEs before TAB regexp. If you're using `mule' package, there may be other characters besides: @@ -782,7 +826,7 @@ If you're using `mule' package, there may be other characters besides: that should be considered blank. -Used when `whitespace-style-color' includes `space-before-tab', +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) @@ -791,7 +835,7 @@ Used when `whitespace-style-color' includes `space-before-tab', (defcustom whitespace-indentation-regexp '("^\t*\\(\\( \\{%d\\}\\)+\\)[^\n\t]" . "^ *\\(\t+\\)[^\n]") - "*Specify regexp for 8 or more SPACEs at beginning of line. + "Specify regexp for 8 or more SPACEs at beginning of line. It is a cons where the cons car is used for SPACEs visualization and the cons cdr is used for TABs visualization. @@ -803,15 +847,15 @@ If you're using `mule' package, there may be other characters besides: that should be considered blank. -Used when `whitespace-style-color' includes `indentation', +Used when `whitespace-style' includes `indentation', `indentation::tab' or `indentation::space'." :type '(cons (regexp :tag "Indentation SPACEs") (regexp :tag "Indentation TABs")) :group 'whitespace) -(defcustom whitespace-empty-at-bob-regexp "\\`\\(\\([ \t]*\n\\)+\\)" - "*Specify regexp for empty lines at beginning of buffer. +(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: @@ -820,13 +864,13 @@ If you're using `mule' package, there may be other characters besides: that should be considered blank. -Used when `whitespace-style-color' includes `empty'." +Used when `whitespace-style' includes `empty'." :type '(regexp :tag "Empty Lines At Beginning Of Buffer") :group 'whitespace) -(defcustom whitespace-empty-at-eob-regexp "^\\([ \t\n]+\\)\\'" - "*Specify regexp for empty lines at end of buffer. +(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: @@ -835,7 +879,7 @@ If you're using `mule' package, there may be other characters besides: that should be considered blank. -Used when `whitespace-style-color' includes `empty'." +Used when `whitespace-style' includes `empty'." :type '(regexp :tag "Empty Lines At End Of Buffer") :group 'whitespace) @@ -843,7 +887,7 @@ Used when `whitespace-style-color' includes `empty'." (defcustom whitespace-space-after-tab-regexp '("\t+\\(\\( \\{%d\\}\\)+\\)" . "\\(\t+\\) +") - "*Specify regexp for 8 or more SPACEs after TAB. + "Specify regexp for 8 or more SPACEs after TAB. It is a cons where the cons car is used for SPACEs visualization and the cons cdr is used for TABs visualization. @@ -855,25 +899,30 @@ If you're using `mule' package, there may be other characters besides: that should be considered blank. -Used when `whitespace-style-color' includes `space-after-tab', +Used when `whitespace-style' includes `space-after-tab', `space-after-tab::tab' or `space-after-tab::space'." :type '(regexp :tag "SPACEs After TAB") :group 'whitespace) (defcustom whitespace-line-column 80 - "*Specify column beyond which the line is highlighted. + "Specify column beyond which the line is highlighted. -Used when `whitespace-style-color' includes `lines' or `lines-tail'." - :type '(integer :tag "Line Length") +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)) :group 'whitespace) ;; Hacked from `visible-whitespace-mappings' in visws.el (defcustom whitespace-display-mappings '( - (space-mark ?\ [?\xB7] [?.]) ; space - centered dot - (space-mark ?\xA0 [?\xA4] [?_]) ; hard space - currency + (space-mark ?\ [?\u00B7] [?.]) ; space - centered dot + (space-mark ?\xA0 [?\u00A4] [?_]) ; hard space - currency (space-mark ?\x8A0 [?\x8A4] [?_]) ; hard space - currency (space-mark ?\x920 [?\x924] [?_]) ; hard space - currency (space-mark ?\xE20 [?\xE24] [?_]) ; hard space - currency @@ -881,7 +930,7 @@ Used when `whitespace-style-color' includes `lines' or `lines-tail'." ;; NEWLINE is displayed using the face `whitespace-newline' (newline-mark ?\n [?$ ?\n]) ; eol - dollar sign ;; (newline-mark ?\n [?\u21B5 ?\n] [?$ ?\n]) ; eol - downwards arrow - ;; (newline-mark ?\n [?\xB6 ?\n] [?$ ?\n]) ; eol - pilcrow + ;; (newline-mark ?\n [?\u00B6 ?\n] [?$ ?\n]) ; eol - pilcrow ;; (newline-mark ?\n [?\x8AF ?\n] [?$ ?\n]) ; eol - overscore ;; (newline-mark ?\n [?\x8AC ?\n] [?$ ?\n]) ; eol - negation ;; (newline-mark ?\n [?\x8B0 ?\n] [?$ ?\n]) ; eol - grade @@ -891,9 +940,9 @@ Used when `whitespace-style-color' includes `lines' or `lines-tail'." ;; character ?\xBB at that column followed by a TAB which goes to ;; the next TAB column. ;; If this is a problem for you, please, comment the line below. - (tab-mark ?\t [?\xBB ?\t] [?\\ ?\t]) ; tab - left quote mark + (tab-mark ?\t [?\u00BB ?\t] [?\\ ?\t]) ; tab - left quote mark ) - "*Specify an alist of mappings for displaying characters. + "Specify an alist of mappings for displaying characters. Each element has the following form: @@ -920,7 +969,8 @@ VECTOR is a vector of characters to be displayed in place of CHAR. The NEWLINE character is displayed using the face given by `whitespace-newline' variable. -Used when `whitespace-style-mark' is non-nil." +Used when `whitespace-style' includes `tab-mark', `space-mark' or +`newline-mark'." :type '(repeat (list :tag "Character Mapping" (choice :tag "Char Kind" @@ -937,7 +987,7 @@ Used when `whitespace-style-mark' is non-nil." (defcustom whitespace-global-modes t - "*Modes for which global `whitespace-mode' is automagically turned on. + "Modes for which global `whitespace-mode' is automagically turned on. Global `whitespace-mode' is controlled by the command `global-whitespace-mode'. @@ -968,7 +1018,7 @@ C++ modes only." (defcustom whitespace-action nil - "*Specify which action is taken when a buffer is visited, killed or written. + "Specify which action is taken when a buffer is visited or written. It's a list containing some or all of the following values: @@ -983,12 +1033,16 @@ It's a list containing some or all of the following values: when local whitespace is turned on. auto-cleanup cleanup any bogus whitespace when buffer is - written or killed. + written. See `whitespace-cleanup' and `whitespace-cleanup-region'. abort-on-bogus abort if there is any bogus whitespace and the - buffer is written or killed. + buffer is written. + + warn-if-read-only give a warning if `cleanup' or `auto-cleanup' + is included in `whitespace-action' and the + buffer is read-only. Any other value is treated as nil." :type '(choice :tag "Actions" @@ -998,7 +1052,8 @@ Any other value is treated as nil." (const :tag "Cleanup When On" cleanup) (const :tag "Report On Bogus" report-on-bogus) (const :tag "Auto Cleanup" auto-cleanup) - (const :tag "Abort On Bogus" abort-on-bogus)))) + (const :tag "Abort On Bogus" abort-on-bogus) + (const :tag "Warn If Read-Only" warn-if-read-only)))) :group 'whitespace) @@ -1013,7 +1068,9 @@ Any other value is treated as nil." If ARG is null, toggle whitespace visualization. If ARG is a number greater than zero, turn on visualization; otherwise, turn off visualization. -Only useful with a windowing system." + +See also `whitespace-style', `whitespace-newline' and +`whitespace-display-mappings'." :lighter " ws" :init-value nil :global nil @@ -1027,6 +1084,30 @@ Only useful with a windowing system." (t ; whitespace-mode off (whitespace-turn-off)))) + +;;;###autoload +(define-minor-mode whitespace-newline-mode + "Toggle NEWLINE minor mode visualization (\"nl\" on modeline). + +If ARG is null, toggle NEWLINE visualization. +If ARG is a number greater than zero, turn on visualization; +otherwise, turn off visualization. + +Use `whitespace-newline-mode' only for NEWLINE visualization +exclusively. For other visualizations, including NEWLINE +visualization together with (HARD) SPACEs and/or TABs, please, +use `whitespace-mode'. + +See also `whitespace-newline' and `whitespace-display-mappings'." + :lighter " nl" + :init-value nil + :global nil + :group 'whitespace + (let ((whitespace-style '(newline-mark newline))) + (whitespace-mode whitespace-newline-mode) + ;; sync states (running a batch job) + (setq whitespace-newline-mode whitespace-mode))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; User commands - Global mode @@ -1039,7 +1120,9 @@ Only useful with a windowing system." If ARG is null, toggle whitespace visualization. If ARG is a number greater than zero, turn on visualization; otherwise, turn off visualization. -Only useful with a windowing system." + +See also `whitespace-style', `whitespace-newline' and +`whitespace-display-mappings'." :lighter " WS" :init-value nil :global t @@ -1085,13 +1168,38 @@ Only useful with a windowing system." ;; Otherwise, turn on whitespace mode. (whitespace-turn-on))))) + +;;;###autoload +(define-minor-mode global-whitespace-newline-mode + "Toggle NEWLINE global minor mode visualization (\"NL\" on modeline). + +If ARG is null, toggle NEWLINE visualization. +If ARG is a number greater than zero, turn on visualization; +otherwise, turn off visualization. + +Use `global-whitespace-newline-mode' only for NEWLINE +visualization exclusively. For other visualizations, including +NEWLINE visualization together with (HARD) SPACEs and/or TABs, +please use `global-whitespace-mode'. + +See also `whitespace-newline' and `whitespace-display-mappings'." + :lighter " NL" + :init-value nil + :global t + :group 'whitespace + (let ((whitespace-style '(newline-mark newline))) + (global-whitespace-mode global-whitespace-newline-mode) + ;; sync states (running a batch job) + (setq global-whitespace-newline-mode global-whitespace-mode))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; User commands - Toggle -(defconst whitespace-color-value-list - '(tabs +(defconst whitespace-style-value-list + '(face + tabs spaces trailing lines @@ -1107,20 +1215,16 @@ Only useful with a windowing system." space-before-tab space-before-tab::tab space-before-tab::space - ) - "List of valid `whitespace-style-color' values.") - - -(defconst whitespace-mark-value-list - '(tab-mark + help-newline ; value used by `whitespace-insert-option-mark' + tab-mark space-mark newline-mark ) - "List of valid `whitespace-style-mark' values.") + "List of valid `whitespace-style' values.") (defconst whitespace-toggle-option-alist - '( ;; `whitespace-color-value-list' values + '((?f . face) (?t . tabs) (?s . spaces) (?r . trailing) @@ -1137,13 +1241,10 @@ Only useful with a windowing system." (?\C-b . space-before-tab) (?B . space-before-tab::tab) (?b . space-before-tab::space) - ;; `whitespace-mark-value-list' values (?T . tab-mark) (?S . space-mark) (?N . newline-mark) - ;; restore values - (?x . whitespace-style-color) - (?z . whitespace-style-mark) + (?x . whitespace-style) ) "Alist of toggle options. @@ -1156,15 +1257,11 @@ Where: CHAR is a char which the user will have to type. SYMBOL is a valid symbol associated with CHAR. - See `whitespace-color-value-list' and - `whitespace-mark-value-list'.") - + See `whitespace-style-value-list'.") -(defvar whitespace-active-color nil - "Used to save locally `whitespace-style-color' value.") -(defvar whitespace-active-mark nil - "Used to save locally `whitespace-style-mark' value.") +(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.") @@ -1172,6 +1269,27 @@ SYMBOL is a valid symbol associated with CHAR. (defvar whitespace-tab-width tab-width "Used to save locally `tab-width' value.") +(defvar whitespace-point (point) + "Used to save locally current point value. +Used by `whitespace-trailing-regexp' function (which see).") + +(defvar whitespace-font-lock-refontify nil + "Used to save locally the font-lock refontify state. +Used by `whitespace-post-command-hook' function (which see).") + +(defvar whitespace-bob-marker nil + "Used to save locally the bob marker value. +Used by `whitespace-post-command-hook' function (which see).") + +(defvar whitespace-eob-marker nil + "Used to save locally the eob marker value. +Used by `whitespace-post-command-hook' function (which see).") + +(defvar whitespace-buffer-changed nil + "Used to indicate locally if buffer changed. +Used by `whitespace-post-command-hook' and `whitespace-buffer-changed' +functions (which see).") + ;;;###autoload (defun whitespace-toggle-options (arg) @@ -1187,6 +1305,7 @@ Interactively, it reads one of the following chars: CHAR MEANING (VIA FACES) + f toggle face visualization t toggle TAB visualization s toggle SPACE and HARD SPACE visualization r toggle trailing blanks visualization @@ -1209,13 +1328,13 @@ Interactively, it reads one of the following chars: S toggle SPACEs before TAB visualization N toggle NEWLINE visualization - x restore `whitespace-style-color' value - z restore `whitespace-style-mark' value + x restore `whitespace-style' value ? display brief help Non-interactively, ARG should be a symbol or a list of symbols. The valid symbols are: + face toggle face visualization tabs toggle TAB visualization spaces toggle SPACE and HARD SPACE visualization trailing toggle trailing blanks visualization @@ -1237,30 +1356,18 @@ The valid symbols are: space-mark toggle SPACEs before TAB visualization newline-mark toggle NEWLINE visualization - whitespace-style-color restore `whitespace-style-color' value - whitespace-style-mark restore `whitespace-style-mark' value + whitespace-style restore `whitespace-style' value -Only useful with a windowing system. - -See `whitespace-style-color', `whitespace-style-mark' and -`indent-tabs-mode' for documentation." +See `whitespace-style' and `indent-tabs-mode' for documentation." (interactive (whitespace-interactive-char t)) - (let ((whitespace-style-color - (whitespace-toggle-list - t arg whitespace-active-color whitespace-style-color - 'whitespace-style-color whitespace-color-value-list)) - (whitespace-style-mark - (whitespace-toggle-list - t arg whitespace-active-mark whitespace-style-mark - 'whitespace-style-mark whitespace-mark-value-list))) + (let ((whitespace-style + (whitespace-toggle-list t arg whitespace-active-style))) (whitespace-mode 0) (whitespace-mode 1))) -(defvar whitespace-toggle-color nil - "Used to toggle the global `whitespace-style-color' value.") -(defvar whitespace-toggle-mark nil - "Used to toggle the global `whitespace-style-mark' value.") +(defvar whitespace-toggle-style nil + "Used to toggle the global `whitespace-style' value.") ;;;###autoload @@ -1277,6 +1384,7 @@ Interactively, it accepts one of the following chars: CHAR MEANING (VIA FACES) + f toggle face visualization t toggle TAB visualization s toggle SPACE and HARD SPACE visualization r toggle trailing blanks visualization @@ -1299,13 +1407,13 @@ Interactively, it accepts one of the following chars: S toggle SPACEs before TAB visualization N toggle NEWLINE visualization - x restore `whitespace-style-color' value - z restore `whitespace-style-mark' value + x restore `whitespace-style' value ? display brief help Non-interactively, ARG should be a symbol or a list of symbols. The valid symbols are: + face toggle face visualization tabs toggle TAB visualization spaces toggle SPACE and HARD SPACE visualization trailing toggle trailing blanks visualization @@ -1327,24 +1435,13 @@ The valid symbols are: space-mark toggle SPACEs before TAB visualization newline-mark toggle NEWLINE visualization - whitespace-style-color restore `whitespace-style-color' value - whitespace-style-mark restore `whitespace-style-mark' value - -Only useful with a windowing system. + whitespace-style restore `whitespace-style' value -See `whitespace-style-color', `whitespace-style-mark' and -`indent-tabs-mode' for documentation." +See `whitespace-style' and `indent-tabs-mode' for documentation." (interactive (whitespace-interactive-char nil)) - (let ((whitespace-style-color - (whitespace-toggle-list - nil arg whitespace-toggle-color whitespace-style-color - 'whitespace-style-color whitespace-color-value-list)) - (whitespace-style-mark - (whitespace-toggle-list - nil arg whitespace-toggle-mark whitespace-style-mark - 'whitespace-style-mark whitespace-mark-value-list))) - (setq whitespace-toggle-color whitespace-style-color - whitespace-toggle-mark whitespace-style-mark) + (let ((whitespace-style + (whitespace-toggle-list nil arg whitespace-toggle-style))) + (setq whitespace-toggle-style whitespace-style) (global-whitespace-mode 0) (global-whitespace-mode 1))) @@ -1359,7 +1456,7 @@ See `whitespace-style-color', `whitespace-style-mark' and It usually applies to the whole buffer, but in transient mark mode when the mark is active, it applies to the region. It also -applies to the region when it is not in transiente mark mode, the +applies to the region when it is not in transient mark mode, the mark is active and \\[universal-argument] was pressed just before calling `whitespace-cleanup' interactively. @@ -1369,75 +1466,79 @@ The problems cleaned up are: 1. empty lines at beginning of buffer. 2. empty lines at end of buffer. - If `whitespace-style-color' includes the value `empty', remove all + If `whitespace-style' includes the value `empty', remove all empty lines at beginning and/or end of buffer. 3. 8 or more SPACEs at beginning of line. - If `whitespace-style-color' includes the value `indentation': + 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-color' includes the value - `indentation::tab', replace 8 or more SPACEs at beginning of - line by TABs. - If `whitespace-style-color' includes the value - `indentation::space', 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-color' includes the value `space-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-color' includes the value + If `whitespace-style' includes the value `space-before-tab::tab', replace SPACEs by TABs. - If `whitespace-style-color' includes the value + 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-color' includes the value `trailing', remove + 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-color' includes the value `space-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-color' includes the value + If `whitespace-style' includes the value `space-after-tab::tab', replace SPACEs by TABs. - If `whitespace-style-color' includes the value + If `whitespace-style' includes the value `space-after-tab::space', replace TABs by SPACEs. -See `whitespace-style-color', `indent-tabs-mode' and `tab-width' -for documentation." - (interactive "@*") - (if (and (or transient-mark-mode - current-prefix-arg) - mark-active) - ;; region active - ;; PROBLEMs 1 and 2 are not handled in region - ;; PROBLEM 3: 8 or more SPACEs at bol - ;; PROBLEM 4: SPACEs before TAB - ;; PROBLEM 5: SPACEs or TABs at eol - ;; PROBLEM 6: 8 or more SPACEs after TAB - (whitespace-cleanup-region (region-beginning) (region-end)) - ;; whole buffer +See `whitespace-style', `indent-tabs-mode' and `tab-width' for +documentation." + (interactive "@") + (cond + ;; read-only buffer + (buffer-read-only + (whitespace-warn-read-only "cleanup")) + ;; region active + ((and (or transient-mark-mode + current-prefix-arg) + mark-active) + ;; PROBLEMs 1 and 2 are not handled in region + ;; PROBLEM 3: 8 or more SPACEs at bol + ;; PROBLEM 4: SPACEs before TAB + ;; PROBLEM 5: SPACEs or TABs at eol + ;; PROBLEM 6: 8 or more SPACEs after TAB + (whitespace-cleanup-region (region-beginning) (region-end))) + ;; whole buffer + (t (save-excursion (save-match-data ;; PROBLEM 1: empty lines at bob ;; PROBLEM 2: empty lines at eob ;; ACTION: remove all empty lines at bob and/or eob - (when (memq 'empty whitespace-style-color) + (when (memq 'empty whitespace-style) (let (overwrite-mode) ; enforce no overwrite (goto-char (point-min)) (when (re-search-forward - whitespace-empty-at-bob-regexp nil t) + (concat "\\`" whitespace-empty-at-bob-regexp) nil t) (delete-region (match-beginning 1) (match-end 1))) (when (re-search-forward - whitespace-empty-at-eob-regexp nil t) + (concat whitespace-empty-at-eob-regexp "\\'") nil t) (delete-region (match-beginning 1) (match-end 1))))))) ;; PROBLEM 3: 8 or more SPACEs at bol ;; PROBLEM 4: SPACEs before TAB ;; PROBLEM 5: SPACEs or TABs at eol ;; PROBLEM 6: 8 or more SPACEs after TAB - (whitespace-cleanup-region (point-min) (point-max)))) + (whitespace-cleanup-region (point-min) (point-max))))) ;;;###autoload @@ -1447,119 +1548,122 @@ for documentation." The problems cleaned up are: 1. 8 or more SPACEs at beginning of line. - If `whitespace-style-color' includes the value `indentation': + 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-color' includes the value - `indentation::tab', replace 8 or more SPACEs at beginning of - line by TABs. - If `whitespace-style-color' includes the value - `indentation::space', 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-color' includes the value `space-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-color' includes the value + If `whitespace-style' includes the value `space-before-tab::tab', replace SPACEs by TABs. - If `whitespace-style-color' includes the value + 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-color' includes the value `trailing', remove + 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-color' includes the value `space-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-color' includes the value + If `whitespace-style' includes the value `space-after-tab::tab', replace SPACEs by TABs. - If `whitespace-style-color' includes the value + If `whitespace-style' includes the value `space-after-tab::space', replace TABs by SPACEs. -See `whitespace-style-color', `indent-tabs-mode' and `tab-width' -for documentation." - (interactive "@*r") - (let ((rstart (min start end)) - (rend (copy-marker (max start end))) - (indent-tabs-mode whitespace-indent-tabs-mode) - (tab-width whitespace-tab-width) - overwrite-mode ; enforce no overwrite - tmp) - (save-excursion - (save-match-data - ;; PROBLEM 1: 8 or more SPACEs at bol - (cond - ;; ACTION: replace 8 or more SPACEs at bol by TABs, if - ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs by - ;; SPACEs. - ((memq 'indentation whitespace-style-color) - (let ((regexp (whitespace-indentation-regexp))) - (goto-char rstart) - (while (re-search-forward regexp rend t) - (setq tmp (current-indentation)) - (goto-char (match-beginning 0)) - (delete-horizontal-space) - (unless (eolp) - (indent-to tmp))))) - ;; ACTION: replace 8 or more SPACEs at bol by TABs. - ((memq 'indentation::tab whitespace-style-color) - (whitespace-replace-action - 'tabify rstart rend - (whitespace-indentation-regexp 'tab) 0)) - ;; ACTION: replace TABs by SPACEs. - ((memq 'indentation::space whitespace-style-color) - (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-color) - (whitespace-replace-action - 'delete-region rstart rend - (whitespace-trailing-regexp) 1)) - ;; PROBLEM 4: 8 or more SPACEs after TAB - (cond - ;; ACTION: replace 8 or more SPACEs by TABs, if - ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs by - ;; SPACEs. - ((memq 'space-after-tab whitespace-style-color) - (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-color) - (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-color) - (whitespace-replace-action - 'untabify rstart rend - (whitespace-space-after-tab-regexp 'space) 1))) - ;; PROBLEM 2: SPACEs before TAB - (cond - ;; ACTION: replace SPACEs before TAB by TABs, if - ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs by - ;; SPACEs. - ((memq 'space-before-tab whitespace-style-color) - (whitespace-replace-action - (if whitespace-indent-tabs-mode 'tabify 'untabify) - rstart rend whitespace-space-before-tab-regexp - (if whitespace-indent-tabs-mode 1 2))) - ;; ACTION: replace SPACEs before TAB by TABs. - ((memq 'space-before-tab::tab whitespace-style-color) - (whitespace-replace-action - 'tabify rstart rend - whitespace-space-before-tab-regexp 1)) - ;; ACTION: replace TABs by SPACEs. - ((memq 'space-before-tab::space whitespace-style-color) - (whitespace-replace-action - 'untabify rstart rend - whitespace-space-before-tab-regexp 2))))) - (set-marker rend nil))) ; point marker to nowhere +See `whitespace-style', `indent-tabs-mode' and `tab-width' for +documentation." + (interactive "@r") + (if buffer-read-only + ;; read-only buffer + (whitespace-warn-read-only "cleanup region") + ;; non-read-only buffer + (let ((rstart (min start end)) + (rend (copy-marker (max start end))) + (indent-tabs-mode whitespace-indent-tabs-mode) + (tab-width whitespace-tab-width) + overwrite-mode ; enforce no overwrite + tmp) + (save-excursion + (save-match-data + ;; PROBLEM 1: 8 or more SPACEs at bol + (cond + ;; ACTION: replace 8 or more SPACEs at bol by TABs, if + ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs + ;; by SPACEs. + ((memq 'indentation whitespace-style) + (let ((regexp (whitespace-indentation-regexp))) + (goto-char rstart) + (while (re-search-forward regexp rend t) + (setq tmp (current-indentation)) + (goto-char (match-beginning 0)) + (delete-horizontal-space) + (unless (eolp) + (indent-to tmp))))) + ;; ACTION: replace 8 or more SPACEs at bol by TABs. + ((memq 'indentation::tab whitespace-style) + (whitespace-replace-action + 'tabify rstart rend + (whitespace-indentation-regexp 'tab) 0)) + ;; ACTION: replace TABs by SPACEs. + ((memq 'indentation::space whitespace-style) + (whitespace-replace-action + 'untabify rstart rend + (whitespace-indentation-regexp 'space) 0))) + ;; PROBLEM 3: SPACEs or TABs at eol + ;; ACTION: remove all SPACEs or TABs at eol + (when (memq 'trailing whitespace-style) + (whitespace-replace-action + 'delete-region rstart rend + whitespace-trailing-regexp 1)) + ;; PROBLEM 4: 8 or more SPACEs after TAB + (cond + ;; ACTION: replace 8 or more SPACEs by TABs, if + ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs + ;; by SPACEs. + ((memq 'space-after-tab whitespace-style) + (whitespace-replace-action + (if whitespace-indent-tabs-mode 'tabify 'untabify) + rstart rend (whitespace-space-after-tab-regexp) 1)) + ;; ACTION: replace 8 or more SPACEs by TABs. + ((memq 'space-after-tab::tab whitespace-style) + (whitespace-replace-action + 'tabify rstart rend + (whitespace-space-after-tab-regexp 'tab) 1)) + ;; ACTION: replace TABs by SPACEs. + ((memq 'space-after-tab::space whitespace-style) + (whitespace-replace-action + 'untabify rstart rend + (whitespace-space-after-tab-regexp 'space) 1))) + ;; PROBLEM 2: SPACEs before TAB + (cond + ;; ACTION: replace SPACEs before TAB by TABs, if + ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs + ;; by SPACEs. + ((memq 'space-before-tab whitespace-style) + (whitespace-replace-action + (if whitespace-indent-tabs-mode 'tabify 'untabify) + rstart rend whitespace-space-before-tab-regexp + (if whitespace-indent-tabs-mode 1 2))) + ;; ACTION: replace SPACEs before TAB by TABs. + ((memq 'space-before-tab::tab whitespace-style) + (whitespace-replace-action + 'tabify rstart rend + whitespace-space-before-tab-regexp 1)) + ;; ACTION: replace TABs by SPACEs. + ((memq 'space-before-tab::space whitespace-style) + (whitespace-replace-action + 'untabify rstart rend + whitespace-space-before-tab-regexp 2))))) + (set-marker rend nil)))) ; point marker to nowhere (defun whitespace-replace-action (action rstart rend regexp index) @@ -1578,11 +1682,6 @@ See also `tab-width'." ;;;; User command - report -(defun whitespace-trailing-regexp () - "Make the `whitespace-trailing-regexp' regexp." - (concat "\\(\\(" whitespace-trailing-regexp "\\)+\\)$")) - - (defun whitespace-regexp (regexp &optional kind) "Return REGEXP depending on `whitespace-indent-tabs-mode'." (cond @@ -1608,7 +1707,7 @@ See also `tab-width'." (list (cons 'empty whitespace-empty-at-bob-regexp) (cons 'empty whitespace-empty-at-eob-regexp) - (cons 'trailing (whitespace-trailing-regexp)) + (cons 'trailing whitespace-trailing-regexp) (cons 'indentation nil) (cons 'indentation::tab nil) (cons 'indentation::space nil) @@ -1685,7 +1784,7 @@ non-nil. If FORCE is non-nil or \\[universal-argument] was pressed just before calling `whitespace-report' interactively, it forces -`whitespace-style-color' to have: +`whitespace-style' to have: empty trailing @@ -1714,8 +1813,7 @@ Report if some of the following whitespace problems exist: space-before-tab 5. SPACEs before TAB. space-after-tab 6. 8 or more SPACEs after TAB. -See `whitespace-style-color' and `whitespace-style-mark' for -documentation. +See `whitespace-style' for documentation. See also `whitespace-cleanup' and `whitespace-cleanup-region' for cleaning up these problems." (interactive (list current-prefix-arg)) @@ -1732,7 +1830,7 @@ non-nil. If FORCE is non-nil or \\[universal-argument] was pressed just before calling `whitespace-report-region' interactively, it -forces `whitespace-style-color' to have: +forces `whitespace-style' to have: empty indentation @@ -1761,8 +1859,7 @@ Report if some of the following whitespace problems exist: space-before-tab 5. SPACEs before TAB. space-after-tab 6. 8 or more SPACEs after TAB. -See `whitespace-style-color' and `whitespace-style-mark' for -documentation. +See `whitespace-style' for documentation. See also `whitespace-cleanup' and `whitespace-cleanup-region' for cleaning up these problems." (interactive "r") @@ -1776,8 +1873,7 @@ cleaning up these problems." (mapcar #'(lambda (option) (when force - (add-to-list 'whitespace-style-color - (car option))) + (add-to-list 'whitespace-style (car option))) (goto-char rstart) (let ((regexp (cond @@ -1815,7 +1911,7 @@ cleaning up these problems." (dolist (option whitespace-report-list) (forward-line 1) (whitespace-mark-x - 27 (memq (car option) whitespace-style-color)) + 27 (memq (car option) whitespace-style)) (whitespace-mark-x 7 (car bogus-list)) (setq bogus-list (cdr bogus-list))) (forward-line 1) @@ -1847,9 +1943,10 @@ cleaning up these problems." (defconst whitespace-help-text "\ - Whitespace Toggle Options - - FACES + Whitespace Toggle Options | scroll up : SPC or > | + | scroll down: M-SPC or < | + FACES \\__________________________/ + [] f - toggle face visualization [] t - toggle TAB visualization [] s - toggle SPACE and HARD SPACE visualization [] r - toggle trailing blanks visualization @@ -1872,8 +1969,7 @@ cleaning up these problems." [] S - toggle SPACE and HARD SPACE visualization [] N - toggle NEWLINE visualization - x - restore `whitespace-style-color' value - z - restore `whitespace-style-mark' value + x - restore `whitespace-style' value ? - display this text\n\n" "Text for whitespace toggle options.") @@ -1898,26 +1994,25 @@ cleaning up these problems." (defun whitespace-insert-option-mark (the-list the-value) "Insert the option mark ('X' or ' ') in toggle options buffer." + (goto-char (point-min)) (forward-line 2) (dolist (sym the-list) - (forward-line 1) - (whitespace-mark-x 2 (memq sym the-value)))) + (if (eq sym 'help-newline) + (forward-line 2) + (forward-line 1) + (whitespace-mark-x 2 (memq sym the-value))))) -(defun whitespace-help-on (chars style) +(defun whitespace-help-on (style) "Display the whitespace toggle options." (unless (get-buffer whitespace-help-buffer-name) (delete-other-windows) (let ((buffer (get-buffer-create whitespace-help-buffer-name))) - (save-excursion - (set-buffer buffer) + (with-current-buffer buffer (erase-buffer) (insert whitespace-help-text) - (goto-char (point-min)) (whitespace-insert-option-mark - whitespace-color-value-list chars) - (whitespace-insert-option-mark - whitespace-mark-value-list style) + whitespace-style-value-list style) (whitespace-display-window buffer))))) @@ -1925,15 +2020,13 @@ cleaning up these problems." "Display BUFFER in a new window." (goto-char (point-min)) (set-buffer-modified-p nil) - (let ((size (- (window-height) - (max window-min-height - (1+ (count-lines (point-min) - (point-max))))))) - (when (<= size 0) - (kill-buffer buffer) - (error "Frame height is too small; \ + (when (< (window-height) (* 2 window-min-height)) + (kill-buffer buffer) + (error "Window height is too small; \ can't split window to display whitespace toggle options")) - (set-window-buffer (split-window nil size) buffer))) + (let ((win (split-window))) + (set-window-buffer win buffer) + (shrink-window-if-larger-than-buffer win))) (defun whitespace-kill-buffer (buffer-name) @@ -1949,6 +2042,24 @@ can't split window to display whitespace toggle options")) (whitespace-kill-buffer whitespace-help-buffer-name)) +(defun whitespace-help-scroll (&optional up) + "Scroll help window, if it exists. + +If UP is non-nil, scroll up; otherwise, scroll down." + (condition-case data-help + (let ((buffer (get-buffer whitespace-help-buffer-name))) + (if buffer + (with-selected-window (get-buffer-window buffer) + (if up + (scroll-up 3) + (scroll-down 3))) + (ding))) + ;; handler + ((error) + ;; just ignore error + ))) + + (defun whitespace-interactive-char (local-p) "Interactive function to read a char and return a symbol. @@ -1959,6 +2070,7 @@ It accepts one of the following chars: CHAR MEANING (VIA FACES) + f toggle face visualization t toggle TAB visualization s toggle SPACE and HARD SPACE visualization r toggle trailing blanks visualization @@ -1981,20 +2093,16 @@ It accepts one of the following chars: S toggle SPACE and HARD SPACE visualization N toggle NEWLINE visualization - x restore `whitespace-style-color' value - z restore `whitespace-style-mark' value + x restore `whitespace-style' value ? display brief help See also `whitespace-toggle-option-alist'." (let* ((is-off (not (if local-p whitespace-mode global-whitespace-mode))) - (chars (cond (is-off whitespace-style-color) ; use default value - (local-p whitespace-active-color) - (t whitespace-toggle-color))) - (style (cond (is-off whitespace-style-mark) ; use default value - (local-p whitespace-active-mark) - (t whitespace-toggle-mark))) + (style (cond (is-off whitespace-style) ; use default value + (local-p whitespace-active-style) + (t whitespace-toggle-style))) (prompt (format "Whitespace Toggle %s (type ? for further options)-" (if local-p "Local" "Global"))) @@ -2012,20 +2120,23 @@ See also `whitespace-toggle-option-alist'." (cdr (assq ch whitespace-toggle-option-alist))))) ;; while body - (if (eq ch ?\?) - (whitespace-help-on chars style) - (ding))) + (cond + ((eq ch ?\?) (whitespace-help-on style)) + ((eq ch ?\ ) (whitespace-help-scroll t)) + ((eq ch ?\M- ) (whitespace-help-scroll)) + ((eq ch ?>) (whitespace-help-scroll t)) + ((eq ch ?<) (whitespace-help-scroll)) + (t (ding)))) (whitespace-help-off) (message " ")) ; clean echo area ;; handler ((quit error) (whitespace-help-off) (error (error-message-string data))))) - (list sym))) ; return the apropriate symbol + (list sym))) ; return the appropriate symbol -(defun whitespace-toggle-list (local-p arg the-list default-list - sym-restore sym-list) +(defun whitespace-toggle-list (local-p arg the-list) "Toggle options in THE-LIST based on list ARG. If LOCAL-P is non-nil, it uses a local context; otherwise, it @@ -2034,83 +2145,111 @@ uses a global context. ARG is a list of options to be toggled. THE-LIST is a list of options. This list will be toggled and the -resultant list will be returned. - -DEFAULT-LIST is the default list of options. It is used to -restore the options in THE-LIST. - -SYM-RESTORE is the symbol which indicates to restore the options -in THE-LIST. - -SYM-LIST is a list of valid options, used to check if the ARG's -options are valid." +resultant list will be returned." (unless (if local-p whitespace-mode global-whitespace-mode) - (setq the-list default-list)) + (setq the-list whitespace-style)) (setq the-list (copy-sequence the-list)) ; keep original list (dolist (sym (if (listp arg) arg (list arg))) (cond + ;; ignore help value + ((eq sym 'help-newline)) ;; restore default values - ((eq sym sym-restore) - (setq the-list default-list)) + ((eq sym 'whitespace-style) + (setq the-list whitespace-style)) ;; toggle valid values - ((memq sym sym-list) + ((memq sym whitespace-style-value-list) (setq the-list (if (memq sym the-list) (delq sym the-list) (cons sym the-list)))))) the-list) +(defvar whitespace-display-table nil + "Used to save a local display table.") + +(defvar whitespace-display-table-was-local nil + "Used to remember whether a buffer initially had a local display table.") + + (defun whitespace-turn-on () "Turn on whitespace visualization." ;; prepare local hooks - (whitespace-add-local-hook) + (add-hook 'write-file-functions 'whitespace-write-file-hook nil t) ;; create whitespace local buffer environment (set (make-local-variable 'whitespace-font-lock-mode) nil) (set (make-local-variable 'whitespace-font-lock) nil) (set (make-local-variable 'whitespace-font-lock-keywords) nil) (set (make-local-variable 'whitespace-display-table) nil) (set (make-local-variable 'whitespace-display-table-was-local) nil) - (set (make-local-variable 'whitespace-active-mark) - (if (listp whitespace-style-mark) - whitespace-style-mark - (list whitespace-style-mark))) - (set (make-local-variable 'whitespace-active-color) - (if (listp whitespace-style-color) - whitespace-style-color - (list whitespace-style-color))) + (set (make-local-variable 'whitespace-active-style) + (if (listp whitespace-style) + whitespace-style + (list whitespace-style))) (set (make-local-variable 'whitespace-indent-tabs-mode) indent-tabs-mode) (set (make-local-variable 'whitespace-tab-width) tab-width) ;; turn on whitespace - (when whitespace-active-color - (whitespace-color-on)) - (when whitespace-active-mark + (when whitespace-active-style + (whitespace-color-on) (whitespace-display-char-on))) (defun whitespace-turn-off () "Turn off whitespace visualization." - (whitespace-remove-local-hook) - (when whitespace-active-color - (whitespace-color-off)) - (when whitespace-active-mark + (remove-hook 'write-file-functions 'whitespace-write-file-hook t) + (when whitespace-active-style + (whitespace-color-off) (whitespace-display-char-off))) +(defun whitespace-style-face-p () + "Return t if there is some visualization via face." + (and (memq 'face whitespace-active-style) + (or (memq 'tabs whitespace-active-style) + (memq 'spaces whitespace-active-style) + (memq 'trailing whitespace-active-style) + (memq 'lines whitespace-active-style) + (memq 'lines-tail whitespace-active-style) + (memq 'newline whitespace-active-style) + (memq 'empty whitespace-active-style) + (memq 'indentation whitespace-active-style) + (memq 'indentation::tab whitespace-active-style) + (memq 'indentation::space whitespace-active-style) + (memq 'space-after-tab whitespace-active-style) + (memq 'space-after-tab::tab whitespace-active-style) + (memq 'space-after-tab::space whitespace-active-style) + (memq 'space-before-tab whitespace-active-style) + (memq 'space-before-tab::tab whitespace-active-style) + (memq 'space-before-tab::space whitespace-active-style)))) + + (defun whitespace-color-on () "Turn on color visualization." - (when whitespace-active-color + (when (whitespace-style-face-p) (unless whitespace-font-lock (setq whitespace-font-lock t whitespace-font-lock-keywords (copy-sequence font-lock-keywords))) + ;; save current point and refontify when necessary + (set (make-local-variable 'whitespace-point) + (point)) + (set (make-local-variable 'whitespace-font-lock-refontify) + 0) + (set (make-local-variable 'whitespace-bob-marker) + (point-min-marker)) + (set (make-local-variable 'whitespace-eob-marker) + (point-max-marker)) + (set (make-local-variable 'whitespace-buffer-changed) + nil) + (add-hook 'post-command-hook #'whitespace-post-command-hook nil t) + (add-hook 'before-change-functions #'whitespace-buffer-changed nil t) ;; turn off font lock (set (make-local-variable 'whitespace-font-lock-mode) font-lock-mode) (font-lock-mode 0) ;; add whitespace-mode color into font lock - (when (memq 'spaces whitespace-active-color) + (when (memq 'spaces whitespace-active-style) (font-lock-add-keywords nil (list @@ -2119,42 +2258,44 @@ options are valid." ;; Show HARD SPACEs (list whitespace-hspace-regexp 1 whitespace-hspace t)) t)) - (when (memq 'tabs whitespace-active-color) + (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-color) + (when (memq 'trailing whitespace-active-style) (font-lock-add-keywords nil (list ;; Show trailing blanks - (list (whitespace-trailing-regexp) 1 whitespace-trailing t)) + (list #'whitespace-trailing-regexp 1 whitespace-trailing t)) t)) - (when (or (memq 'lines whitespace-active-color) - (memq 'lines-tail whitespace-active-color)) + (when (or (memq 'lines whitespace-active-style) + (memq 'lines-tail whitespace-active-style)) (font-lock-add-keywords nil (list ;; Show "long" lines (list - (format - "^\\([^\t\n]\\{%s\\}\\|[^\t\n]\\{0,%s\\}\t\\)\\{%d\\}%s\\(.+\\)$" - whitespace-tab-width (1- whitespace-tab-width) - (/ whitespace-line-column tab-width) - (let ((rem (% whitespace-line-column whitespace-tab-width))) - (if (zerop rem) - "" - (format ".\\{%d\\}" rem)))) - (if (memq 'lines whitespace-active-color) + (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-color) + ((memq 'space-before-tab whitespace-active-style) (font-lock-add-keywords nil (list @@ -2163,7 +2304,7 @@ options are valid." (if whitespace-indent-tabs-mode 1 2) whitespace-space-before-tab t)) t)) - ((memq 'space-before-tab::tab whitespace-active-color) + ((memq 'space-before-tab::tab whitespace-active-style) (font-lock-add-keywords nil (list @@ -2171,7 +2312,7 @@ options are valid." (list whitespace-space-before-tab-regexp 1 whitespace-space-before-tab t)) t)) - ((memq 'space-before-tab::space whitespace-active-color) + ((memq 'space-before-tab::space whitespace-active-style) (font-lock-add-keywords nil (list @@ -2180,7 +2321,7 @@ options are valid." 2 whitespace-space-before-tab t)) t))) (cond - ((memq 'indentation whitespace-active-color) + ((memq 'indentation whitespace-active-style) (font-lock-add-keywords nil (list @@ -2188,7 +2329,7 @@ options are valid." (list (whitespace-indentation-regexp) 1 whitespace-indentation t)) t)) - ((memq 'indentation::tab whitespace-active-color) + ((memq 'indentation::tab whitespace-active-style) (font-lock-add-keywords nil (list @@ -2196,7 +2337,7 @@ options are valid." (list (whitespace-indentation-regexp 'tab) 1 whitespace-indentation t)) t)) - ((memq 'indentation::space whitespace-active-color) + ((memq 'indentation::space whitespace-active-style) (font-lock-add-keywords nil (list @@ -2204,23 +2345,23 @@ options are valid." (list (whitespace-indentation-regexp 'space) 1 whitespace-indentation t)) t))) - (when (memq 'empty whitespace-active-color) + (when (memq 'empty whitespace-active-style) (font-lock-add-keywords nil (list ;; Show empty lines at beginning of buffer - (list whitespace-empty-at-bob-regexp + (list #'whitespace-empty-at-bob-regexp 1 whitespace-empty t)) t) (font-lock-add-keywords nil (list ;; Show empty lines at end of buffer - (list whitespace-empty-at-eob-regexp + (list #'whitespace-empty-at-eob-regexp 1 whitespace-empty t)) t)) (cond - ((memq 'space-after-tab whitespace-active-color) + ((memq 'space-after-tab whitespace-active-style) (font-lock-add-keywords nil (list @@ -2228,7 +2369,7 @@ options are valid." (list (whitespace-space-after-tab-regexp) 1 whitespace-space-after-tab t)) t)) - ((memq 'space-after-tab::tab whitespace-active-color) + ((memq 'space-after-tab::tab whitespace-active-style) (font-lock-add-keywords nil (list @@ -2236,7 +2377,7 @@ options are valid." (list (whitespace-space-after-tab-regexp 'tab) 1 whitespace-space-after-tab t)) t)) - ((memq 'space-after-tab::space whitespace-active-color) + ((memq 'space-after-tab::space whitespace-active-style) (font-lock-add-keywords nil (list @@ -2250,25 +2391,165 @@ options are valid." (defun whitespace-color-off () "Turn off color visualization." - (when whitespace-active-color - ;; turn off font lock + ;; turn off font lock + (when (whitespace-style-face-p) (font-lock-mode 0) + (remove-hook 'post-command-hook #'whitespace-post-command-hook t) + (remove-hook 'before-change-functions #'whitespace-buffer-changed t) (when whitespace-font-lock (setq whitespace-font-lock nil font-lock-keywords whitespace-font-lock-keywords)) ;; restore original font lock state (font-lock-mode whitespace-font-lock-mode))) + +(defun whitespace-trailing-regexp (limit) + "Match trailing spaces which do not contain the point at end of line." + (let ((status t)) + (while (if (re-search-forward whitespace-trailing-regexp limit t) + (save-match-data + (= whitespace-point (match-end 1))) ;; loop if point at eol + (setq status nil))) ;; end of buffer + status)) + + +(defun whitespace-empty-at-bob-regexp (limit) + "Match spaces at beginning of buffer which do not contain the point at \ +beginning of buffer." + (let ((b (point)) + r) + (cond + ;; at bob + ((= b 1) + (setq r (and (/= whitespace-point 1) + (looking-at whitespace-empty-at-bob-regexp))) + (if r + (set-marker whitespace-bob-marker (match-end 1)) + (set-marker whitespace-bob-marker b))) + ;; inside bob empty region + ((<= limit whitespace-bob-marker) + (setq r (looking-at whitespace-empty-at-bob-regexp)) + (if r + (when (< (match-end 1) limit) + (set-marker whitespace-bob-marker (match-end 1))) + (set-marker whitespace-bob-marker b))) + ;; intersection with end of bob empty region + ((<= b whitespace-bob-marker) + (setq r (looking-at whitespace-empty-at-bob-regexp)) + (if r + (set-marker whitespace-bob-marker (match-end 1)) + (set-marker whitespace-bob-marker b))) + ;; it is not inside bob empty region + (t + (setq r nil))) + ;; move to end of matching + (and r (goto-char (match-end 1))) + r)) + + +(defsubst whitespace-looking-back (regexp limit) + (save-excursion + (when (/= 0 (skip-chars-backward " \t\n" limit)) + (unless (bolp) + (forward-line 1)) + (looking-at regexp)))) + + +(defun whitespace-empty-at-eob-regexp (limit) + "Match spaces at end of buffer which do not contain the point at end of \ +buffer." + (let ((b (point)) + (e (1+ (buffer-size))) + r) + (cond + ;; at eob + ((= limit e) + (when (/= whitespace-point e) + (goto-char limit) + (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b))) + (if r + (set-marker whitespace-eob-marker (match-beginning 1)) + (set-marker whitespace-eob-marker limit) + (goto-char b))) ; return back to initial position + ;; inside eob empty region + ((>= b whitespace-eob-marker) + (goto-char limit) + (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b)) + (if r + (when (> (match-beginning 1) b) + (set-marker whitespace-eob-marker (match-beginning 1))) + (set-marker whitespace-eob-marker limit) + (goto-char b))) ; return back to initial position + ;; intersection with beginning of eob empty region + ((>= limit whitespace-eob-marker) + (goto-char limit) + (setq r (whitespace-looking-back whitespace-empty-at-eob-regexp b)) + (if r + (set-marker whitespace-eob-marker (match-beginning 1)) + (set-marker whitespace-eob-marker limit) + (goto-char b))) ; return back to initial position + ;; it is not inside eob empty region + (t + (setq r nil))) + r)) + + +(defun whitespace-buffer-changed (beg end) + "Set `whitespace-buffer-changed' variable to t." + (setq whitespace-buffer-changed t)) + + +(defun whitespace-post-command-hook () + "Save current point into `whitespace-point' variable. +Also refontify when necessary." + (setq whitespace-point (point)) ; current point position + (let ((refontify + (or + ;; it is at end of line ... + (and (eolp) + ;; ... with trailing SPACE or TAB + (or (= (preceding-char) ?\ ) + (= (preceding-char) ?\t))) + ;; it is at beginning of buffer (bob) + (= whitespace-point 1) + ;; the buffer was modified and ... + (and whitespace-buffer-changed + (or + ;; ... or inside bob whitespace region + (<= whitespace-point whitespace-bob-marker) + ;; ... or at bob whitespace region border + (and (= whitespace-point (1+ whitespace-bob-marker)) + (= (preceding-char) ?\n)))) + ;; it is at end of buffer (eob) + (= whitespace-point (1+ (buffer-size))) + ;; the buffer was modified and ... + (and whitespace-buffer-changed + (or + ;; ... or inside eob whitespace region + (>= whitespace-point whitespace-eob-marker) + ;; ... or at eob whitespace region border + (and (= whitespace-point (1- whitespace-eob-marker)) + (= (following-char) ?\n))))))) + (when (or refontify (> whitespace-font-lock-refontify 0)) + (setq whitespace-buffer-changed nil) + ;; adjust refontify counter + (setq whitespace-font-lock-refontify + (if refontify + 1 + (1- whitespace-font-lock-refontify))) + ;; refontify + (jit-lock-refontify)))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; Hacked from visws.el (Miles Bader ) -(defvar whitespace-display-table nil - "Used to save a local display table.") - -(defvar whitespace-display-table-was-local nil - "Used to remember whether a buffer initially had a local display table.") +(defun whitespace-style-mark-p () + "Return t if there is some visualization via display table." + (or (memq 'tab-mark whitespace-active-style) + (memq 'space-mark whitespace-active-style) + (memq 'newline-mark whitespace-active-style))) (defsubst whitespace-char-valid-p (char) @@ -2288,18 +2569,23 @@ options are valid." (defun whitespace-display-char-on () "Turn on character display mapping." - (when whitespace-display-mappings + (when (and whitespace-display-mappings + (whitespace-style-mark-p)) (let (vecs vec) ;; Remember whether a buffer has a local display table. (unless whitespace-display-table-was-local (setq whitespace-display-table-was-local t whitespace-display-table + (copy-sequence buffer-display-table)) + ;; asure `buffer-display-table' is unique + ;; when two or more windows are visible. + (setq buffer-display-table (copy-sequence buffer-display-table))) (unless buffer-display-table (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-mark) + (when (memq (car entry) whitespace-style) ;; Get a displayable mapping. (setq vecs (cddr entry)) (while (and vecs @@ -2310,7 +2596,7 @@ options are valid." (setq vec (copy-sequence (car vecs))) ;; NEWLINE char (when (and (eq (cadr entry) ?\n) - (memq 'newline whitespace-active-color)) + (memq 'newline whitespace-active-style)) ;; Only insert face bits on NEWLINE char mapping to avoid ;; obstruction of other faces like TABs and (HARD) SPACEs ;; faces, font-lock faces, etc. @@ -2326,6 +2612,7 @@ options are valid." (defun whitespace-display-char-off () "Turn off character display mapping." (and whitespace-display-mappings + (whitespace-style-mark-p) whitespace-display-table-was-local (setq whitespace-display-table-was-local nil buffer-display-table whitespace-display-table))) @@ -2343,44 +2630,22 @@ options are valid." (whitespace-report nil t)))) -(defun whitespace-add-local-hook () - "Add some whitespace hooks locally." - (add-hook 'write-file-functions 'whitespace-write-file-hook nil t) - (add-hook 'kill-buffer-hook 'whitespace-kill-buffer-hook nil t)) - - -(defun whitespace-remove-local-hook () - "Remove some whitespace hooks locally." - (remove-hook 'write-file-functions 'whitespace-write-file-hook t) - (remove-hook 'kill-buffer-hook 'whitespace-kill-buffer-hook t)) - - (defun whitespace-write-file-hook () "Action to be taken when buffer is written. It should be added buffer-locally to `write-file-functions'." - (when (whitespace-action) - (error "Abort write due to whitespace problems in %s" - (buffer-name))) - nil) ; continue hook processing - - -(defun whitespace-kill-buffer-hook () - "Action to be taken when buffer is killed. -It should be added buffer-locally to `kill-buffer-hook'." - (whitespace-action) + (cond ((memq 'auto-cleanup whitespace-action) + (whitespace-cleanup)) + ((memq 'abort-on-bogus whitespace-action) + (when (whitespace-report nil t) + (error "Abort write due to whitespace problems in %s" + (buffer-name))))) nil) ; continue hook processing -(defun whitespace-action () - "Action to be taken when buffer is killed or written. -Return t when the action should be aborted." - (cond ((memq 'auto-cleanup whitespace-action) - (whitespace-cleanup) - nil) - ((memq 'abort-on-bogus whitespace-action) - (whitespace-report nil t)) - (t - nil))) +(defun whitespace-warn-read-only (msg) + "Warn if buffer is read-only." + (when (memq 'warn-if-read-only whitespace-action) + (message "Can't %s: %s is read-only" msg (buffer-name)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;