X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/ecb21060d5c1752d41d7a742be565c59b5fcb855..341dd15a7bd9d0b4adff846e94289b3e1877eed1:/lisp/whitespace.el diff --git a/lisp/whitespace.el b/lisp/whitespace.el dissimilarity index 93% index 6e6aeb5fbb..326621e9c4 100644 --- a/lisp/whitespace.el +++ b/lisp/whitespace.el @@ -1,807 +1,2405 @@ -;;; whitespace.el --- warn about and clean bogus whitespaces in the file - -;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, -;; 2005, 2006, 2007 Free Software Foundation, Inc. - -;; Author: Rajesh Vaidheeswarran -;; Keywords: convenience - -;; 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 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. - -;;; Commentary: -;; -;; URL: http://www.dsmit.com/lisp/ -;; -;; The whitespace library is intended to find and help fix five different types -;; of whitespace problems that commonly exist in source code. -;; -;; 1. Leading space (empty lines at the top of a file). -;; 2. Trailing space (empty lines at the end of a file). -;; 3. Indentation space (8 or more spaces at beginning of line, that should be -;; replaced with TABS). -;; 4. Spaces followed by a TAB. (Almost always, we never want that). -;; 5. Spaces or TABS at the end of a line. -;; -;; Whitespace errors are reported in a buffer, and on the modeline. -;; -;; Modeline will show a W:! to denote a particular type of whitespace, -;; where `x' and `y' can be one (or more) of: -;; -;; e - End-of-Line whitespace. -;; i - Indentation whitespace. -;; l - Leading whitespace. -;; s - Space followed by Tab. -;; t - Trailing whitespace. -;; -;; If any of the whitespace checks is turned off, the modeline will display a -;; !. -;; -;; (since (3) is the most controversial one, here is the rationale: Most -;; terminal drivers and printer drivers have TAB configured or even -;; hardcoded to be 8 spaces. (Some of them allow configuration, but almost -;; always they default to 8.) -;; -;; Changing `tab-width' to other than 8 and editing will cause your code to -;; look different from within Emacs, and say, if you cat it or more it, or -;; even print it. -;; -;; Almost all the popular programming modes let you define an offset (like -;; c-basic-offset or perl-indent-level) to configure the offset, so you -;; should never have to set your `tab-width' to be other than 8 in all -;; these modes. In fact, with an indent level of say, 4, 2 TABS will cause -;; Emacs to replace your 8 spaces with one \t (try it). If vi users in -;; your office complain, tell them to use vim, which distinguishes between -;; tabstop and shiftwidth (vi equivalent of our offsets), and also ask them -;; to set smarttab.) -;; -;; All the above have caused (and will cause) unwanted codeline integration and -;; merge problems. -;; -;; whitespace.el will complain if it detects whitespaces on opening a file, and -;; warn you on closing a file also (in case you had inserted any -;; whitespaces during the process of your editing). -;; -;; Exported functions: -;; -;; `whitespace-buffer' - To check the current buffer for whitespace problems. -;; `whitespace-cleanup' - To cleanup all whitespaces in the current buffer. -;; `whitespace-region' - To check between point and mark for whitespace -;; problems. -;; `whitespace-cleanup-region' - To cleanup all whitespaces between point -;; and mark in the current buffer. - -;;; Code: - -(defvar whitespace-version "3.5" "Version of the whitespace library.") - -(defvar whitespace-all-buffer-files nil - "An associated list of buffers and files checked for whitespace cleanliness. - -This is to enable periodic checking of whitespace cleanliness in the files -visited by the buffers.") - -(defvar whitespace-rescan-timer nil - "Timer object used to rescan the files in buffers that have been modified.") - -;; Tell Emacs about this new kind of minor mode -(defvar whitespace-mode nil - "Non-nil when Whitespace mode (a minor mode) is enabled.") -(make-variable-buffer-local 'whitespace-mode) - -(defvar whitespace-mode-line nil - "String to display in the mode line for Whitespace mode.") -(make-variable-buffer-local 'whitespace-mode-line) - -(defvar whitespace-check-buffer-leading nil - "Test leading whitespace for file in current buffer if t.") -(make-variable-buffer-local 'whitespace-check-buffer-leading) - -(defvar whitespace-check-buffer-trailing nil - "Test trailing whitespace for file in current buffer if t.") -(make-variable-buffer-local 'whitespace-check-buffer-trailing) - -(defvar whitespace-check-buffer-indent nil - "Test indentation whitespace for file in current buffer if t.") -(make-variable-buffer-local 'whitespace-check-buffer-indent) - -(defvar whitespace-check-buffer-spacetab nil - "Test Space-followed-by-TABS whitespace for file in current buffer if t.") -(make-variable-buffer-local 'whitespace-check-buffer-spacetab) - -(defvar whitespace-check-buffer-ateol nil - "Test end-of-line whitespace for file in current buffer if t.") -(make-variable-buffer-local 'whitespace-check-buffer-ateol) - -(defvar whitespace-highlighted-space nil - "The variable to store the extent to highlight.") -(make-variable-buffer-local 'whitespace-highlighted-space) - -;; For flavors of Emacs which don't define `defgroup' and `defcustom'. -(eval-when-compile - (if (not (fboundp 'defgroup)) - (defmacro defgroup (sym memb doc &rest args) - "Null macro for `defgroup' in all versions of Emacs that don't define it." - t)) - (if (not (fboundp 'defcustom)) - (defmacro defcustom (sym val doc &rest args) - "Macro to alias `defcustom' to `defvar' in all versions of Emacs that -don't define it." - `(defvar ,sym ,val ,doc)))) - -(defalias 'whitespace-make-overlay - (if (featurep 'xemacs) 'make-extent 'make-overlay)) -(defalias 'whitespace-overlay-put - (if (featurep 'xemacs) 'set-extent-property 'overlay-put)) -(defalias 'whitespace-delete-overlay - (if (featurep 'xemacs) 'delete-extent 'delete-overlay)) -(defalias 'whitespace-overlay-start - (if (featurep 'xemacs) 'extent-start 'overlay-start)) -(defalias 'whitespace-overlay-end - (if (featurep 'xemacs) 'extent-end 'overlay-end)) -(defalias 'whitespace-mode-line-update - (if (featurep 'xemacs) 'redraw-modeline 'force-mode-line-update)) - -(defgroup whitespace nil - "Check for and fix five different types of whitespaces in source code." - :version "21.1" - :link '(emacs-commentary-link "whitespace.el") - ;; Since XEmacs doesn't have a 'convenience group, use the next best group - ;; which is 'editing? - :group (if (featurep 'xemacs) 'editing 'convenience)) - -(defcustom whitespace-check-leading-whitespace t - "Flag to check leading whitespace. This is the global for the system. -It can be overriden by setting a buffer local variable -`whitespace-check-buffer-leading'." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-check-trailing-whitespace t - "Flag to check trailing whitespace. This is the global for the system. -It can be overriden by setting a buffer local variable -`whitespace-check-buffer-trailing'." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-check-spacetab-whitespace t - "Flag to check space followed by a TAB. This is the global for the system. -It can be overriden by setting a buffer local variable -`whitespace-check-buffer-spacetab'." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-spacetab-regexp "[ ]+\t" - "Regexp to match one or more spaces followed by a TAB." - :type 'regexp - :group 'whitespace) - -(defcustom whitespace-check-indent-whitespace indent-tabs-mode - "Flag to check indentation whitespace. This is the global for the system. -It can be overriden by setting a buffer local variable -`whitespace-check-buffer-indent'." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-indent-regexp "^\t*\\( \\)+" - "Regexp to match multiples of eight spaces near line beginnings. -The default value ignores leading TABs." - :type 'regexp - :group 'whitespace) - -(defcustom whitespace-check-ateol-whitespace t - "Flag to check end-of-line whitespace. This is the global for the system. -It can be overriden by setting a buffer local variable -`whitespace-check-buffer-ateol'." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-ateol-regexp "[ \t]+$" - "Regexp to match one or more TABs or spaces at line ends." - :type 'regexp - :group 'whitespace) - -(defcustom whitespace-errbuf "*Whitespace Errors*" - "The name of the buffer where whitespace related messages will be logged." - :type 'string - :group 'whitespace) - -(defcustom whitespace-clean-msg "clean." - "If non-nil, this message will be displayed after a whitespace check -determines a file to be clean." - :type 'string - :group 'whitespace) - -(defcustom whitespace-abort-on-error nil - "While writing a file, abort if the file is unclean. -If `whitespace-auto-cleanup' is set, that takes precedence over -this variable." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-auto-cleanup nil - "Cleanup a buffer automatically on finding it whitespace unclean." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-silent nil - "All whitespace errors will be shown only in the modeline when t. - -Note that setting this may cause all whitespaces introduced in a file to go -unnoticed when the buffer is killed, unless the user visits the `*Whitespace -Errors*' buffer before opening (or closing) another file." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-modes '(ada-mode asm-mode autoconf-mode awk-mode - c-mode c++-mode cc-mode - change-log-mode cperl-mode - electric-nroff-mode emacs-lisp-mode - f90-mode fortran-mode html-mode - html3-mode java-mode jde-mode - ksh-mode latex-mode LaTeX-mode - lisp-mode m4-mode makefile-mode - modula-2-mode nroff-mode objc-mode - pascal-mode perl-mode prolog-mode - python-mode scheme-mode sgml-mode - sh-mode shell-script-mode simula-mode - tcl-mode tex-mode texinfo-mode - vrml-mode xml-mode) - - "Major modes in which we turn on whitespace checking. - -These are mostly programming and documentation modes. But you may add other -modes that you want whitespaces checked in by adding something like the -following to your `.emacs': - -\(setq whitespace-modes (cons 'my-mode (cons 'my-other-mode - whitespace-modes))\) - -Or, alternately, you can use the Emacs `customize' command to set this." - :type '(repeat symbol) - :group 'whitespace) - -(defcustom whitespace-rescan-timer-time 600 - "Period in seconds to rescan modified buffers for whitespace creep. - -This is the period after which the timer will fire causing -`whitespace-rescan-files-in-buffers' to check for whitespace creep in -modified buffers. - -To disable timer scans, set this to zero." - :type 'integer - :group 'whitespace) - -(defcustom whitespace-display-in-modeline t - "Display whitespace errors on the modeline." - :type 'boolean - :group 'whitespace) - -(defcustom whitespace-display-spaces-in-color t - "Display the bogus whitespaces by coloring them with the face -`whitespace-highlight'." - :type 'boolean - :group 'whitespace) - -(defgroup whitespace-faces nil - "Faces used in whitespace." - :prefix "whitespace-" - :group 'whitespace - :group 'faces) - -(defface whitespace-highlight '((((class color) (background light)) - (:background "green1")) - (((class color) (background dark)) - (:background "sea green")) - (((class grayscale mono) - (background light)) - (:background "black")) - (((class grayscale mono) - (background dark)) - (:background "white"))) - "Face used for highlighting the bogus whitespaces that exist in the buffer." - :group 'whitespace-faces) -;; backward-compatibility alias -(put 'whitespace-highlight-face 'face-alias 'whitespace-highlight) - -(if (not (assoc 'whitespace-mode minor-mode-alist)) - (setq minor-mode-alist (cons '(whitespace-mode whitespace-mode-line) - minor-mode-alist))) - -(set-default 'whitespace-check-buffer-leading - whitespace-check-leading-whitespace) -(set-default 'whitespace-check-buffer-trailing - whitespace-check-trailing-whitespace) -(set-default 'whitespace-check-buffer-indent - whitespace-check-indent-whitespace) -(set-default 'whitespace-check-buffer-spacetab - whitespace-check-spacetab-whitespace) -(set-default 'whitespace-check-buffer-ateol - whitespace-check-ateol-whitespace) - -(defun whitespace-check-whitespace-mode (&optional arg) - "Test and set the whitespace-mode in qualifying buffers." - (if (null whitespace-mode) - (setq whitespace-mode - (if (or arg (member major-mode whitespace-modes)) - t - nil)))) - -;;;###autoload -(defun whitespace-toggle-leading-check () - "Toggle the check for leading space in the local buffer." - (interactive) - (let ((current-val whitespace-check-buffer-leading)) - (setq whitespace-check-buffer-leading (not current-val)) - (message "Will%s check for leading space in buffer." - (if whitespace-check-buffer-leading "" " not")) - (if whitespace-check-buffer-leading (whitespace-buffer-leading)))) - -;;;###autoload -(defun whitespace-toggle-trailing-check () - "Toggle the check for trailing space in the local buffer." - (interactive) - (let ((current-val whitespace-check-buffer-trailing)) - (setq whitespace-check-buffer-trailing (not current-val)) - (message "Will%s check for trailing space in buffer." - (if whitespace-check-buffer-trailing "" " not")) - (if whitespace-check-buffer-trailing (whitespace-buffer-trailing)))) - -;;;###autoload -(defun whitespace-toggle-indent-check () - "Toggle the check for indentation space in the local buffer." - (interactive) - (let ((current-val whitespace-check-buffer-indent)) - (setq whitespace-check-buffer-indent (not current-val)) - (message "Will%s check for indentation space in buffer." - (if whitespace-check-buffer-indent "" " not")) - (if whitespace-check-buffer-indent - (whitespace-buffer-search whitespace-indent-regexp)))) - -;;;###autoload -(defun whitespace-toggle-spacetab-check () - "Toggle the check for space-followed-by-TABs in the local buffer." - (interactive) - (let ((current-val whitespace-check-buffer-spacetab)) - (setq whitespace-check-buffer-spacetab (not current-val)) - (message "Will%s check for space-followed-by-TABs in buffer." - (if whitespace-check-buffer-spacetab "" " not")) - (if whitespace-check-buffer-spacetab - (whitespace-buffer-search whitespace-spacetab-regexp)))) - - -;;;###autoload -(defun whitespace-toggle-ateol-check () - "Toggle the check for end-of-line space in the local buffer." - (interactive) - (let ((current-val whitespace-check-buffer-ateol)) - (setq whitespace-check-buffer-ateol (not current-val)) - (message "Will%s check for end-of-line space in buffer." - (if whitespace-check-buffer-ateol "" " not")) - (if whitespace-check-buffer-ateol - (whitespace-buffer-search whitespace-ateol-regexp)))) - - -;;;###autoload -(defun whitespace-buffer (&optional quiet) - "Find five different types of white spaces in buffer. -These are: -1. Leading space \(empty lines at the top of a file\). -2. Trailing space \(empty lines at the end of a file\). -3. Indentation space \(8 or more spaces, that should be replaced with TABS\). -4. Spaces followed by a TAB. \(Almost always, we never want that\). -5. Spaces or TABS at the end of a line. - -Check for whitespace only if this buffer really contains a non-empty file -and: -1. the major mode is one of the whitespace-modes, or -2. `whitespace-buffer' was explicitly called with a prefix argument." - (interactive) - (let ((whitespace-error nil)) - (whitespace-check-whitespace-mode current-prefix-arg) - (if (and buffer-file-name (> (buffer-size) 0) whitespace-mode) - (progn - (whitespace-check-buffer-list (buffer-name) buffer-file-name) - (whitespace-tickle-timer) - (overlay-recenter (point-max)) - (remove-overlays nil nil 'face 'whitespace-highlight) - (if whitespace-auto-cleanup - (if buffer-read-only - (if (not quiet) - (message "Can't cleanup: %s is read-only" (buffer-name))) - (whitespace-cleanup-internal)) - (let ((whitespace-leading (if whitespace-check-buffer-leading - (whitespace-buffer-leading) - nil)) - (whitespace-trailing (if whitespace-check-buffer-trailing - (whitespace-buffer-trailing) - nil)) - (whitespace-indent (if whitespace-check-buffer-indent - (whitespace-buffer-search - whitespace-indent-regexp) - nil)) - (whitespace-spacetab (if whitespace-check-buffer-spacetab - (whitespace-buffer-search - whitespace-spacetab-regexp) - nil)) - (whitespace-ateol (if whitespace-check-buffer-ateol - (whitespace-buffer-search - whitespace-ateol-regexp) - nil)) - (whitespace-errmsg nil) - (whitespace-filename buffer-file-name) - (whitespace-this-modeline "")) - - ;; Now let's complain if we found any of the above. - (setq whitespace-error (or whitespace-leading whitespace-indent - whitespace-spacetab whitespace-ateol - whitespace-trailing)) - - (if whitespace-error - (progn - (setq whitespace-errmsg - (concat whitespace-filename " contains:\n" - (if whitespace-leading - "Leading whitespace\n") - (if whitespace-indent - (concat "Indentation whitespace" - whitespace-indent "\n")) - (if whitespace-spacetab - (concat "Space followed by Tab" - whitespace-spacetab "\n")) - (if whitespace-ateol - (concat "End-of-line whitespace" - whitespace-ateol "\n")) - (if whitespace-trailing - "Trailing whitespace\n") - "\ntype `M-x whitespace-cleanup' to " - "cleanup the file.")) - (setq whitespace-this-modeline - (concat (if whitespace-ateol "e") - (if whitespace-indent "i") - (if whitespace-leading "l") - (if whitespace-spacetab "s") - (if whitespace-trailing "t"))))) - (whitespace-update-modeline whitespace-this-modeline) - (if (get-buffer whitespace-errbuf) - (kill-buffer whitespace-errbuf)) - (with-current-buffer (get-buffer-create whitespace-errbuf) - (if whitespace-errmsg - (progn - (insert whitespace-errmsg) - (if (not (or quiet whitespace-silent)) - (display-buffer (current-buffer) t)) - (if (not quiet) - (message "Whitespaces: [%s%s] in %s" - whitespace-this-modeline - (let ((whitespace-unchecked - (whitespace-unchecked-whitespaces))) - (if whitespace-unchecked - (concat "!" whitespace-unchecked) - "")) - whitespace-filename))) - (if (and (not quiet) (not (equal whitespace-clean-msg ""))) - (message "%s %s" whitespace-filename - whitespace-clean-msg)))))))) - whitespace-error)) - -;;;###autoload -(defun whitespace-region (s e) - "Check the region for whitespace errors." - (interactive "r") - (save-excursion - (save-restriction - (narrow-to-region s e) - (whitespace-buffer)))) - -;;;###autoload -(defun whitespace-cleanup () - "Cleanup the five different kinds of whitespace problems. -It normally applies to the whole buffer, but in Transient Mark mode -when the mark is active it applies to the region. -See `whitespace-buffer' docstring for a summary of the problems." - (interactive) - (if (and transient-mark-mode mark-active) - (whitespace-cleanup-region (region-beginning) (region-end)) - (whitespace-cleanup-internal))) - -(defun whitespace-cleanup-internal (&optional region-only) - ;; If this buffer really contains a file, then run, else quit. - (whitespace-check-whitespace-mode current-prefix-arg) - (if (and buffer-file-name whitespace-mode) - (let ((whitespace-any nil) - (whitespace-tabwith 8) - (whitespace-tabwith-saved tab-width)) - - ;; since all printable TABS should be 8, irrespective of how - ;; they are displayed. - (setq tab-width whitespace-tabwith) - - (if (and whitespace-check-buffer-leading - (whitespace-buffer-leading)) - (progn - (whitespace-buffer-leading-cleanup) - (setq whitespace-any t))) - - (if (and whitespace-check-buffer-trailing - (whitespace-buffer-trailing)) - (progn - (whitespace-buffer-trailing-cleanup) - (setq whitespace-any t))) - - (if (and whitespace-check-buffer-indent - (whitespace-buffer-search whitespace-indent-regexp)) - (progn - (whitespace-indent-cleanup) - (setq whitespace-any t))) - - (if (and whitespace-check-buffer-spacetab - (whitespace-buffer-search whitespace-spacetab-regexp)) - (progn - (whitespace-buffer-cleanup whitespace-spacetab-regexp "\t") - (setq whitespace-any t))) - - (if (and whitespace-check-buffer-ateol - (whitespace-buffer-search whitespace-ateol-regexp)) - (progn - (whitespace-buffer-cleanup whitespace-ateol-regexp "") - (setq whitespace-any t))) - - ;; Call this recursively till everything is taken care of - (if whitespace-any - (whitespace-cleanup-internal region-only) - ;; if we are done, talk to the user - (progn - (unless whitespace-silent - (if region-only - (message "The region is now clean") - (message "%s is now clean" buffer-file-name))) - (whitespace-update-modeline))) - (setq tab-width whitespace-tabwith-saved)))) - -;;;###autoload -(defun whitespace-cleanup-region (s e) - "Whitespace cleanup on the region." - (interactive "r") - (save-excursion - (save-restriction - (narrow-to-region s e) - (whitespace-cleanup-internal t)) - (whitespace-buffer t))) - -(defun whitespace-buffer-leading () - "Return t if the current buffer has leading newline characters. -If highlighting is enabled, highlight these characters." - (save-excursion - (goto-char (point-min)) - (skip-chars-forward "\n") - (unless (bobp) - (whitespace-highlight-the-space (point-min) (point)) - t))) - -(defun whitespace-buffer-leading-cleanup () - "Remove any leading newline characters from current buffer." - (save-excursion - (goto-char (point-min)) - (skip-chars-forward "\n") - (delete-region (point-min) (point)))) - -(defun whitespace-buffer-trailing () - "Return t if the current buffer has extra trailing newline characters. -If highlighting is enabled, highlight these characters." - (save-excursion - (goto-char (point-max)) - (skip-chars-backward "\n") - (forward-line) - (unless (eobp) - (whitespace-highlight-the-space (point) (point-max)) - t))) - -(defun whitespace-buffer-trailing-cleanup () - "Remove extra trailing newline characters from current buffer." - (save-excursion - (goto-char (point-max)) - (skip-chars-backward "\n") - (unless (eobp) - (forward-line) - (delete-region (point) (point-max))))) - -(defun whitespace-buffer-search (regexp) - "Search for any given whitespace REGEXP." - (with-local-quit - (let (whitespace-retval) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward regexp nil t) - (whitespace-highlight-the-space (match-beginning 0) (match-end 0)) - (push (match-beginning 0) whitespace-retval))) - (when whitespace-retval - (format " %s" (nreverse whitespace-retval)))))) - -(defun whitespace-buffer-cleanup (regexp newregexp) - "Search for any given whitespace REGEXP and replace it with the NEWREGEXP." - (save-excursion - (goto-char (point-min)) - (while (re-search-forward regexp nil t) - (replace-match newregexp)))) - -(defun whitespace-indent-cleanup () - "Search for 8/more spaces at the start of a line and replace it with tabs." - (save-excursion - (goto-char (point-min)) - (while (re-search-forward whitespace-indent-regexp nil t) - (let ((column (current-column)) - (indent-tabs-mode t)) - (delete-region (match-beginning 0) (point)) - (indent-to column))))) - -(defun whitespace-unchecked-whitespaces () - "Return the list of whitespaces whose testing has been suppressed." - (let ((unchecked-spaces - (concat (if (not whitespace-check-buffer-ateol) "e") - (if (not whitespace-check-buffer-indent) "i") - (if (not whitespace-check-buffer-leading) "l") - (if (not whitespace-check-buffer-spacetab) "s") - (if (not whitespace-check-buffer-trailing) "t")))) - (if (not (equal unchecked-spaces "")) - unchecked-spaces - nil))) - -(defun whitespace-update-modeline (&optional whitespace-err) - "Update modeline with whitespace errors. -Also with whitespaces whose testing has been turned off." - (if whitespace-display-in-modeline - (progn - (setq whitespace-mode-line nil) - ;; Whitespace errors - (if (and whitespace-err (not (equal whitespace-err ""))) - (setq whitespace-mode-line whitespace-err)) - ;; Whitespace suppressed errors - (let ((whitespace-unchecked (whitespace-unchecked-whitespaces))) - (if whitespace-unchecked - (setq whitespace-mode-line - (concat whitespace-mode-line "!" whitespace-unchecked)))) - ;; Add the whitespace modeline prefix - (setq whitespace-mode-line (if whitespace-mode-line - (concat " W:" whitespace-mode-line) - nil)) - (whitespace-mode-line-update)))) - -(defun whitespace-highlight-the-space (b e) - "Highlight the current line, unhighlighting a previously jumped to line." - (if whitespace-display-spaces-in-color - (let ((ol (whitespace-make-overlay b e))) - (whitespace-overlay-put ol 'face 'whitespace-highlight)))) - -(defun whitespace-unhighlight-the-space() - "Unhighlight the currently highlight line." - (if (and whitespace-display-spaces-in-color whitespace-highlighted-space) - (progn - (mapc 'whitespace-delete-overlay whitespace-highlighted-space) - (setq whitespace-highlighted-space nil)))) - -(defun whitespace-check-buffer-list (buf-name buf-file) - "Add a buffer and its file to the whitespace monitor list. - -The buffer named BUF-NAME and its associated file BUF-FILE are now monitored -periodically for whitespace." - (if (and whitespace-mode (not (member (list buf-file buf-name) - whitespace-all-buffer-files))) - (add-to-list 'whitespace-all-buffer-files (list buf-file buf-name)))) - -(defun whitespace-tickle-timer () - "Tickle timer to periodically to scan qualifying files for whitespace creep. - -If timer is not set, then set it to scan the files in -`whitespace-all-buffer-files' periodically (defined by -`whitespace-rescan-timer-time') for whitespace creep." - (if (and whitespace-rescan-timer-time - (/= whitespace-rescan-timer-time 0) - (not whitespace-rescan-timer)) - (setq whitespace-rescan-timer - (add-timeout whitespace-rescan-timer-time - 'whitespace-rescan-files-in-buffers nil - whitespace-rescan-timer-time)))) - -(defun whitespace-rescan-files-in-buffers (&optional arg) - "Check monitored files for whitespace creep since last scan." - (let ((whitespace-all-my-files whitespace-all-buffer-files) - buffile bufname thiselt buf) - (if (not whitespace-all-my-files) - (progn - (disable-timeout whitespace-rescan-timer) - (setq whitespace-rescan-timer nil)) - (while whitespace-all-my-files - (setq thiselt (car whitespace-all-my-files)) - (setq whitespace-all-my-files (cdr whitespace-all-my-files)) - (setq buffile (car thiselt)) - (setq bufname (cadr thiselt)) - (setq buf (get-buffer bufname)) - (if (buffer-live-p buf) - (save-excursion - ;;(message "buffer %s live" bufname) - (set-buffer bufname) - (if whitespace-mode - (progn - ;;(message "checking for whitespace in %s" bufname) - (if whitespace-auto-cleanup - (progn - ;;(message "cleaning up whitespace in %s" bufname) - (whitespace-cleanup-internal)) - (progn - ;;(message "whitespace-buffer %s." (buffer-name)) - (whitespace-buffer t)))) - ;;(message "Removing %s from refresh list" bufname) - (whitespace-refresh-rescan-list buffile bufname))) - ;;(message "Removing %s from refresh list" bufname) - (whitespace-refresh-rescan-list buffile bufname)))))) - -(defun whitespace-refresh-rescan-list (buffile bufname) - "Refresh the list of files to be rescanned for whitespace creep." - (if whitespace-all-buffer-files - (setq whitespace-all-buffer-files - (delete (list buffile bufname) whitespace-all-buffer-files)) - (when whitespace-rescan-timer - (disable-timeout whitespace-rescan-timer) - (setq whitespace-rescan-timer nil)))) - -;;;###autoload -(defalias 'global-whitespace-mode 'whitespace-global-mode) - -;;;###autoload -(define-minor-mode whitespace-global-mode - "Toggle using Whitespace mode in new buffers. -With ARG, turn the mode on if ARG is positive, otherwise turn it off. - -When this mode is active, `whitespace-buffer' is added to -`find-file-hook' and `kill-buffer-hook'." - :global t - :group 'whitespace - (if whitespace-global-mode - (progn - (add-hook 'find-file-hook 'whitespace-buffer) - (add-hook 'write-file-functions 'whitespace-write-file-hook nil t) - (add-hook 'kill-buffer-hook 'whitespace-buffer)) - (remove-hook 'find-file-hook 'whitespace-buffer) - (remove-hook 'write-file-functions 'whitespace-write-file-hook t) - (remove-hook 'kill-buffer-hook 'whitespace-buffer))) - -;;;###autoload -(defun whitespace-write-file-hook () - "Hook function to be called on the buffer when whitespace check is enabled. -This is meant to be added buffer-locally to `write-file-functions'." - (interactive) - (let ((werr nil)) - (if whitespace-auto-cleanup - (whitespace-cleanup-internal) - (setq werr (whitespace-buffer))) - (if (and whitespace-abort-on-error werr) - (error (concat "Abort write due to whitespaces in " - buffer-file-name)))) - nil) - -(defun whitespace-unload-hook () - (remove-hook 'find-file-hook 'whitespace-buffer) - (remove-hook 'write-file-functions 'whitespace-write-file-hook t) - (remove-hook 'kill-buffer-hook 'whitespace-buffer)) - -(add-hook 'whitespace-unload-hook 'whitespace-unload-hook) - -(provide 'whitespace) - -;; arch-tag: 4ff44e87-b63c-402d-95a6-15e51e58bd0c -;;; whitespace.el ends here +;;; whitespace.el --- minor mode to visualize TAB, (HARD) SPACE, NEWLINE + +;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +;; Free Software Foundation, Inc. + +;; Author: Vinicius Jose Latorre +;; Maintainer: Vinicius Jose Latorre +;; Keywords: data, wp +;; Version: 10.0 +;; X-URL: http://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3, or (at your +;; option) any later version. + +;; GNU Emacs is 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. + +;;; Commentary: + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Introduction +;; ------------ +;; +;; This package is a minor mode to visualize blanks (TAB, (HARD) SPACE +;; and NEWLINE). +;; +;; whitespace uses two ways to visualize blanks: faces and display +;; table. +;; +;; * Faces are used to highlight the background with a color. +;; whitespace uses font-lock to highlight blank characters. +;; +;; * Display table changes the way a character is displayed, that is, +;; 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. +;; +;; Note that when whitespace is turned on, whitespace saves the +;; font-lock state, that is, if font-lock is on or off. And +;; whitespace restores the font-lock state when it is turned off. So, +;; if whitespace is turned on and font-lock is off, whitespace also +;; turns on the font-lock to highlight blanks, but the font-lock will +;; be turned off when whitespace is turned off. Thus, turn on +;; font-lock before whitespace is on, if you want that font-lock +;; continues on after whitespace is turned off. +;; +;; When whitespace is on, it takes care of highlighting some special +;; characters over the default mechanism of `nobreak-char-display' +;; (which see) and `show-trailing-whitespace' (which see). +;; +;; There are two ways of using whitespace: local and global. +;; +;; * Local whitespace affects only the current buffer. +;; +;; * Global whitespace affects all current and future buffers. That +;; is, if you turn on global whitespace and then create a new +;; buffer, the new buffer will also have whitespace on. The +;; `whitespace-global-modes' variable controls which major-mode will +;; be automagically turned on. +;; +;; You can mix the local and global usage without any conflict. But +;; local whitespace has priority over global whitespace. Whitespace +;; mode is active in a buffer if you have enabled it in that buffer or +;; if you have enabled it globally. +;; +;; When global and local whitespace are on: +;; +;; * if local whitespace is turned off, whitespace is turned off for +;; the current buffer only. +;; +;; * if global whitespace is turned off, whitespace continues on only +;; in the buffers in which local whitespace is on. +;; +;; To use whitespace, insert in your ~/.emacs: +;; +;; (require 'whitespace-mode) +;; +;; Or autoload at least one of the commands`whitespace-mode', +;; `whitespace-toggle-options', `global-whitespace-mode' or +;; `global-whitespace-toggle-options'. For example: +;; +;; (autoload 'whitespace-mode "whitespace" +;; "Toggle whitespace visualization." t) +;; (autoload 'whitespace-toggle-options "whitespace" +;; "Toggle local `whitespace-mode' options." t) +;; +;; whitespace was inspired by: +;; +;; whitespace.el Rajesh Vaidheeswarran +;; Warn about and clean bogus whitespaces in the file +;; (inspired the idea to warn and clean some blanks) +;; This was the original `whitespace.el' which was replaced by +;; `blank-mode.el'. And later `blank-mode.el' was renamed to +;; `whitespace.el'. +;; +;; show-whitespace-mode.el Aurelien Tisne +;; Simple mode to highlight whitespaces +;; (inspired the idea to use font-lock) +;; +;; whitespace-mode.el Lawrence Mitchell +;; Major mode for editing Whitespace +;; (inspired the idea to use display table) +;; +;; visws.el Miles Bader +;; Make whitespace visible +;; (handle display table, his code was modified, but the main +;; idea was kept) +;; +;; +;; Using whitespace +;; ---------------- +;; +;; There is no problem if you mix local and global minor mode usage. +;; +;; * LOCAL whitespace: +;; + To toggle whitespace options locally, type: +;; +;; M-x whitespace-toggle-options RET +;; +;; + To activate whitespace locally, type: +;; +;; C-u 1 M-x whitespace-mode RET +;; +;; + To deactivate whitespace locally, type: +;; +;; C-u 0 M-x whitespace-mode RET +;; +;; + To toggle whitespace locally, type: +;; +;; M-x whitespace-mode RET +;; +;; * GLOBAL whitespace: +;; + To toggle whitespace options globally, type: +;; +;; M-x global-whitespace-toggle-options RET +;; +;; + To activate whitespace globally, type: +;; +;; C-u 1 M-x global-whitespace-mode RET +;; +;; + To deactivate whitespace globally, type: +;; +;; C-u 0 M-x global-whitespace-mode RET +;; +;; + To toggle whitespace globally, type: +;; +;; M-x global-whitespace-mode RET +;; +;; There are also the following useful commands: +;; +;; `whitespace-report' +;; Report some blank problems in buffer. +;; +;; `whitespace-report-region' +;; Report some blank problems in a region. +;; +;; `whitespace-cleanup' +;; Cleanup some blank problems in all buffer or at region. +;; +;; `whitespace-cleanup-region' +;; Cleanup some blank problems at region. +;; +;; The problems, which are 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 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': +;; 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. +;; +;; 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 +;; `space-before-tab::tab', replace SPACEs by TABs. +;; If `whitespace-style-color' 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. +;; +;; 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 +;; `space-after-tab::space', replace TABs by SPACEs. +;; +;; +;; Hooks +;; ----- +;; +;; whitespace has the following hook variables: +;; +;; `whitespace-mode-hook' +;; It is evaluated always when whitespace is turned on locally. +;; +;; `global-whitespace-mode-hook' +;; It is evaluated always when whitespace is turned on globally. +;; +;; `whitespace-load-hook' +;; It is evaluated after whitespace package is loaded. +;; +;; +;; Options +;; ------- +;; +;; 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-space' Face used to visualize SPACE. +;; +;; `whitespace-hspace' Face used to visualize HARD SPACE. +;; +;; `whitespace-tab' Face used to visualize TAB. +;; +;; `whitespace-newline' Face used to visualize NEWLINE char +;; mapping. +;; +;; `whitespace-trailing' Face used to visualize trailing +;; blanks. +;; +;; `whitespace-line' Face used to visualize "long" lines. +;; +;; `whitespace-space-before-tab' Face used to visualize SPACEs +;; before TAB. +;; +;; `whitespace-indentation' Face used to visualize 8 or more +;; SPACEs at beginning of line. +;; +;; `whitespace-empty' Face used to visualize empty lines at +;; beginning and/or end of buffer. +;; +;; `whitespace-space-after-tab' Face used to visualize 8 or more +;; SPACEs after TAB. +;; +;; `whitespace-space-regexp' Specify SPACE characters regexp. +;; +;; `whitespace-hspace-regexp' Specify HARD SPACE characters regexp. +;; +;; `whitespace-tab-regexp' Specify TAB characters regexp. +;; +;; `whitespace-trailing-regexp' Specify trailing characters regexp. +;; +;; `whitespace-space-before-tab-regexp' Specify SPACEs before TAB +;; regexp. +;; +;; `whitespace-indentation-regexp' Specify regexp for 8 or more +;; SPACEs at beginning of line. +;; +;; `whitespace-empty-at-bob-regexp' Specify regexp for empty lines +;; at beginning of buffer. +;; +;; `whitespace-empty-at-eob-regexp' Specify regexp for empty lines +;; at end of buffer. +;; +;; `whitespace-space-after-tab-regexp' Specify regexp for 8 or more +;; SPACEs after TAB. +;; +;; `whitespace-line-column' Specify column beyond which the line +;; is highlighted. +;; +;; `whitespace-display-mappings' Specify an alist of mappings +;; for displaying characters. +;; +;; `whitespace-global-modes' Modes for which global +;; `whitespace-mode' is automagically +;; turned on. +;; +;; `whitespace-action' Specify which action is taken when a +;; buffer is visited, killed or written. +;; +;; +;; Acknowledgements +;; ---------------- +;; +;; 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. +;; +;; Thanks to nschum (EmacsWiki) for the idea about highlight "long" +;; lines tail. See EightyColumnRule (EmacsWiki). +;; +;; Thanks to Juri Linkov for suggesting: +;; * `define-minor-mode'. +;; * `global-whitespace-*' name for global commands. +;; +;; Thanks to Robert J. Chassell for doc fix and testing. +;; +;; Thanks to Drew Adams for toggle commands +;; suggestion. +;; +;; Thanks to Antti Kaihola for +;; helping to fix `find-file-hooks' reference. +;; +;; Thanks to Andreas Roehler for +;; indicating defface byte-compilation warnings. +;; +;; Thanks to TimOCallaghan (EmacsWiki) for the idea about highlight +;; "long" lines. See EightyColumnRule (EmacsWiki). +;; +;; Thanks to Yanghui Bian for indicating a new +;; newline character mapping. +;; +;; Thanks to Pete Forman for indicating +;; whitespace-mode.el on XEmacs. +;; +;; Thanks to Miles Bader for handling display table via +;; visws.el (his code was modified, but the main idea was kept). +;; +;; Thanks to: +;; Rajesh Vaidheeswarran (original) whitespace.el +;; Aurelien Tisne show-whitespace-mode.el +;; Lawrence Mitchell whitespace-mode.el +;; Miles Bader visws.el +;; And to all people who contributed with them. +;; +;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; code: + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; User Variables: + + +;;; Interface to the command system + + +(defgroup whitespace nil + "Visualize blanks (TAB, (HARD) SPACE and NEWLINE)." + :link '(emacs-library-link :tag "Source Lisp File" "whitespace.el") + :version "23.1" + :group 'wp + :group 'data) + + +(defcustom whitespace-style-mark '(space-mark tab-mark newline-mark) + "*Specify which kind of blank is visualized via display table. + +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: + + trailing trailing blanks are visualized. + + tabs TABs are visualized. + + spaces SPACEs and HARD SPACEs are visualized. + + lines lines whose have columns beyond + `whitespace-line-column' are highlighted. + Whole line is highlighted. + It has precedence over + `lines-tail' (see below). + + lines-tail lines whose have columns beyond + `whitespace-line-column' are highlighted. + 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'. + + newline NEWLINEs are visualized. + + empty empty lines at beginning and/or end of buffer + are visualized. + + indentation::tab 8 or more SPACEs at beginning of line are + visualized. + + indentation::space TABs at beginning of line are visualized. + + 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. + + space-after-tab::tab 8 or more SPACEs after a TAB are + visualized. + + space-after-tab::space TABs are visualized when occurs 8 or + more SPACEs after a TAB. + + 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. + + space-before-tab::tab SPACEs before TAB are visualized. + + space-before-tab::space TABs are visualized when occurs SPACEs + before TAB. + + space-before-tab SPACEs before TAB are visualized, if + `indent-tabs-mode' (which see) is + non-nil; otherwise, the TABs are + visualized. + +Any other value is ignored. + +If nil, don't visualize TABs, (HARD) SPACEs and NEWLINEs via faces. + +There is an evaluation order for some values, if some values are +included in `whitespace-style-color' 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: + + * For indentation: + 1. indentation + 2. indentation::tab + 3. indentation::space + + * For SPACEs after TABs: + 1. space-after-tab + 2. space-after-tab::tab + 3. space-after-tab::space + + * For SPACEs before TABs: + 1. space-before-tab + 2. space-before-tab::tab + 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" + (choice :tag "Kind of Blank Face" + (const :tag "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" + space-before-tab) + (const :tag "NEWLINEs" newline) + (const :tag "Indentation SPACEs" indentation) + (const :tag "Empty Lines At BOB And/Or EOB" + empty) + (const :tag "SPACEs after TAB" + space-after-tab))) + :group 'whitespace) + + +(defcustom whitespace-space 'whitespace-space + "*Symbol face used to visualize SPACE. + +Used when `whitespace-style-color' includes the value `spaces'." + :type 'face + :group 'whitespace) + + +(defface whitespace-space + '((((class color) (background dark)) + (:background "grey20" :foreground "aquamarine3")) + (((class color) (background light)) + (:background "LightYellow" :foreground "aquamarine3")) + (t (:inverse-video t))) + "Face used to visualize SPACE." + :group 'whitespace) + + +(defcustom whitespace-hspace 'whitespace-hspace + "*Symbol face used to visualize HARD SPACE. + +Used when `whitespace-style-color' includes the value `spaces'." + :type 'face + :group 'whitespace) + + +(defface whitespace-hspace ; 'nobreak-space + '((((class color) (background dark)) + (:background "grey24" :foreground "aquamarine3")) + (((class color) (background light)) + (:background "LemonChiffon3" :foreground "aquamarine3")) + (t (:inverse-video t))) + "Face used to visualize HARD SPACE." + :group 'whitespace) + + +(defcustom whitespace-tab 'whitespace-tab + "*Symbol face used to visualize TAB. + +Used when `whitespace-style-color' includes the value `tabs'." + :type 'face + :group 'whitespace) + + +(defface whitespace-tab + '((((class color) (background dark)) + (:background "grey22" :foreground "aquamarine3")) + (((class color) (background light)) + (:background "beige" :foreground "aquamarine3")) + (t (:inverse-video t))) + "Face used to visualize TAB." + :group 'whitespace) + + +(defcustom whitespace-newline 'whitespace-newline + "*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'." + :type 'face + :group 'whitespace) + + +(defface whitespace-newline + '((((class color) (background dark)) + (:background "grey26" :foreground "aquamarine3" :bold t)) + (((class color) (background light)) + (:background "linen" :foreground "aquamarine3" :bold t)) + (t (:bold t :underline t))) + "Face used to visualize NEWLINE char mapping. + +See `whitespace-display-mappings'." + :group 'whitespace) + + +(defcustom whitespace-trailing 'whitespace-trailing + "*Symbol face used to visualize traling blanks. + +Used when `whitespace-style-color' includes the value `trailing'." + :type 'face + :group 'whitespace) + + +(defface whitespace-trailing ; 'trailing-whitespace + '((((class mono)) (:inverse-video t :bold t :underline t)) + (t (:background "red1" :foreground "yellow" :bold t))) + "Face used to visualize trailing blanks." + :group 'whitespace) + + +(defcustom whitespace-line 'whitespace-line + "*Symbol face used to visualize \"long\" lines. + +See `whitespace-line-column'. + +Used when `whitespace-style-color' includes the value `line'." + :type 'face + :group 'whitespace) + + +(defface whitespace-line + '((((class mono)) (:inverse-video t :bold t :underline t)) + (t (:background "gray20" :foreground "violet"))) + "Face used to visualize \"long\" lines. + +See `whitespace-line-column'." + :group 'whitespace) + + +(defcustom whitespace-space-before-tab 'whitespace-space-before-tab + "*Symbol face used to visualize SPACEs before TAB. + +Used when `whitespace-style-color' includes the value `space-before-tab'." + :type 'face + :group 'whitespace) + + +(defface whitespace-space-before-tab + '((((class mono)) (:inverse-video t :bold t :underline t)) + (t (:background "DarkOrange" :foreground "firebrick"))) + "Face used to visualize SPACEs before TAB." + :group 'whitespace) + + +(defcustom whitespace-indentation 'whitespace-indentation + "*Symbol face used to visualize 8 or more SPACEs at beginning of line. + +Used when `whitespace-style-color' includes the value `indentation'." + :type 'face + :group 'whitespace) + + +(defface whitespace-indentation + '((((class mono)) (:inverse-video t :bold t :underline t)) + (t (:background "yellow" :foreground "firebrick"))) + "Face used to visualize 8 or more SPACEs at beginning of line." + :group 'whitespace) + + +(defcustom whitespace-empty 'whitespace-empty + "*Symbol face used to visualize empty lines at beginning and/or end of buffer. + +Used when `whitespace-style-color' includes the value `empty'." + :type 'face + :group 'whitespace) + + +(defface whitespace-empty + '((((class mono)) (:inverse-video t :bold t :underline t)) + (t (:background "yellow" :foreground "firebrick"))) + "Face used to visualize empty lines at beginning and/or end of buffer." + :group 'whitespace) + + +(defcustom whitespace-space-after-tab 'whitespace-space-after-tab + "*Symbol face used to visualize 8 or more SPACEs after TAB. + +Used when `whitespace-style-color' includes the value `space-after-tab'." + :type 'face + :group 'whitespace) + + +(defface whitespace-space-after-tab + '((((class mono)) (:inverse-video t :bold t :underline t)) + (t (:background "yellow" :foreground "firebrick"))) + "Face used to visualize 8 or more SPACEs after TAB." + :group 'whitespace) + + +(defcustom whitespace-hspace-regexp + "\\(\\(\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)" + "*Specify HARD SPACE characters regexp. + +If you're using `mule' package, there may be other characters besides: + + \"\\xA0\" \"\\x8A0\" \"\\x920\" \"\\xE20\" \"\\xF20\" + +that should be considered HARD SPACE. + +Here are some examples: + + \"\\\\(^\\xA0+\\\\)\" \ +visualize only leading HARD SPACEs. + \"\\\\(\\xA0+$\\\\)\" \ +visualize only trailing HARD SPACEs. + \"\\\\(^\\xA0+\\\\|\\xA0+$\\\\)\" \ +visualize leading and/or trailing HARD SPACEs. + \"\\t\\\\(\\xA0+\\\\)\\t\" \ +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'." + :type '(regexp :tag "HARD SPACE Chars") + :group 'whitespace) + + +(defcustom whitespace-space-regexp "\\( +\\)" + "*Specify SPACE characters regexp. + +If you're using `mule' package, there may be other characters +besides \" \" that should be considered SPACE. + +Here are some examples: + + \"\\\\(^ +\\\\)\" visualize only leading SPACEs. + \"\\\\( +$\\\\)\" visualize only trailing SPACEs. + \"\\\\(^ +\\\\| +$\\\\)\" \ +visualize leading and/or trailing SPACEs. + \"\\t\\\\( +\\\\)\\t\" visualize only 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'." + :type '(regexp :tag "SPACE Chars") + :group 'whitespace) + + +(defcustom whitespace-tab-regexp "\\(\t+\\)" + "*Specify TAB characters regexp. + +If you're using `mule' package, there may be other characters +besides \"\\t\" that should be considered TAB. + +Here are some examples: + + \"\\\\(^\\t+\\\\)\" visualize only leading TABs. + \"\\\\(\\t+$\\\\)\" visualize only trailing TABs. + \"\\\\(^\\t+\\\\|\\t+$\\\\)\" \ +visualize leading and/or trailing TABs. + \" \\\\(\\t+\\\\) \" visualize only TABs between SPACEs. + +NOTE: Enclose always by \\\\( and \\\\) the elements to highlight. + Use exactly one pair of enclosing \\\\( and \\\\). + +Used when `whitespace-style-color' includes `tabs'." + :type '(regexp :tag "TAB Chars") + :group 'whitespace) + + +(defcustom whitespace-trailing-regexp + "\t\\| \\|\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20" + "*Specify trailing characters regexp. + +If you're using `mule' package, there may be other characters besides: + + \" \" \"\\t\" \"\\xA0\" \"\\x8A0\" \"\\x920\" \"\\xE20\" \ +\"\\xF20\" + +that should be considered blank. + +NOTE: DO NOT enclose by \\\\( and \\\\) the elements to highlight. + `whitespace-mode' surrounds this regexp by \"\\\\(\\\\(\" and + \"\\\\)+\\\\)$\". + +Used when `whitespace-style-color' includes `trailing'." + :type '(regexp :tag "Trailing Chars") + :group 'whitespace) + + +(defcustom whitespace-space-before-tab-regexp "\\( +\\)\\(\t+\\)" + "*Specify SPACEs before TAB regexp. + +If you're using `mule' package, there may be other characters besides: + + \" \" \"\\t\" \"\\xA0\" \"\\x8A0\" \"\\x920\" \"\\xE20\" \ +\"\\xF20\" + +that should be considered blank. + +Used when `whitespace-style-color' includes `space-before-tab', +`space-before-tab::tab' or `space-before-tab::space'." + :type '(regexp :tag "SPACEs Before TAB") + :group 'whitespace) + + +(defcustom whitespace-indentation-regexp + '("^\t*\\(\\( \\{%d\\}\\)+\\)[^\n\t]" + . "^ *\\(\t+\\)[^\n]") + "*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. + +If you're using `mule' package, there may be other characters besides: + + \" \" \"\\t\" \"\\xA0\" \"\\x8A0\" \"\\x920\" \"\\xE20\" \ +\"\\xF20\" + +that should be considered blank. + +Used when `whitespace-style-color' 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. + +If you're using `mule' package, there may be other characters besides: + + \" \" \"\\t\" \"\\xA0\" \"\\x8A0\" \"\\x920\" \"\\xE20\" \ +\"\\xF20\" + +that should be considered blank. + +Used when `whitespace-style-color' 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. + +If you're using `mule' package, there may be other characters besides: + + \" \" \"\\t\" \"\\xA0\" \"\\x8A0\" \"\\x920\" \"\\xE20\" \ +\"\\xF20\" + +that should be considered blank. + +Used when `whitespace-style-color' includes `empty'." + :type '(regexp :tag "Empty Lines At End Of Buffer") + :group 'whitespace) + + +(defcustom whitespace-space-after-tab-regexp + '("\t+\\(\\( \\{%d\\}\\)+\\)" + . "\\(\t+\\) +") + "*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. + +If you're using `mule' package, there may be other characters besides: + + \" \" \"\\t\" \"\\xA0\" \"\\x8A0\" \"\\x920\" \"\\xE20\" \ +\"\\xF20\" + +that should be considered blank. + +Used when `whitespace-style-color' 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. + +Used when `whitespace-style-color' includes `lines' or `lines-tail'." + :type '(integer :tag "Line Length") + :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 ?\x8A0 [?\x8A4] [?_]) ; hard space - currency + (space-mark ?\x920 [?\x924] [?_]) ; hard space - currency + (space-mark ?\xE20 [?\xE24] [?_]) ; hard space - currency + (space-mark ?\xF20 [?\xF24] [?_]) ; hard space - currency + ;; 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 [?\x8AF ?\n] [?$ ?\n]) ; eol - overscore + ;; (newline-mark ?\n [?\x8AC ?\n] [?$ ?\n]) ; eol - negation + ;; (newline-mark ?\n [?\x8B0 ?\n] [?$ ?\n]) ; eol - grade + ;; + ;; WARNING: the mapping below has a problem. + ;; When a TAB occupies exactly one column, it will display the + ;; 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 + ) + "*Specify an alist of mappings for displaying characters. + +Each element has the following form: + + (KIND CHAR VECTOR...) + +Where: + +KIND is the kind of character. + It can be one of the following symbols: + + tab-mark for TAB character + + space-mark for SPACE or HARD SPACE character + + newline-mark for NEWLINE character + +CHAR is the character to be mapped. + +VECTOR is a vector of characters to be displayed in place of CHAR. + The first display vector that can be displayed is used; + if no display vector for a mapping can be displayed, then + that character is displayed unmodified. + +The NEWLINE character is displayed using the face given by +`whitespace-newline' variable. + +Used when `whitespace-style-mark' is non-nil." + :type '(repeat + (list :tag "Character Mapping" + (choice :tag "Char Kind" + (const :tag "Tab" tab-mark) + (const :tag "Space" space-mark) + (const :tag "Newline" newline-mark)) + (character :tag "Char") + (repeat :inline t :tag "Vector List" + (vector :tag "" + (repeat :inline t + :tag "Vector Characters" + (character :tag "Char")))))) + :group 'whitespace) + + +(defcustom whitespace-global-modes t + "*Modes for which global `whitespace-mode' is automagically turned on. + +Global `whitespace-mode' is controlled by the command +`global-whitespace-mode'. + +If nil, means no modes have `whitespace-mode' automatically +turned on. + +If t, all modes that support `whitespace-mode' have it +automatically turned on. + +Else it should be a list of `major-mode' symbol names for which +`whitespace-mode' should be automatically turned on. The sense +of the list is negated if it begins with `not'. For example: + + (c-mode c++-mode) + +means that `whitespace-mode' is turned on for buffers in C and +C++ modes only." + :type '(choice :tag "Global Modes" + (const :tag "None" nil) + (const :tag "All" t) + (set :menu-tag "Mode Specific" :tag "Modes" + :value (not) + (const :tag "Except" not) + (repeat :inline t + (symbol :tag "Mode")))) + :group 'whitespace) + + +(defcustom whitespace-action nil + "*Specify which action is taken when a buffer is visited, killed or written. + +It's a list containing some or all of the following values: + + nil no action is taken. + + cleanup cleanup any bogus whitespace always when local + whitespace is turned on. + See `whitespace-cleanup' and + `whitespace-cleanup-region'. + + 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 or killed. + See `whitespace-cleanup' and + `whitespace-cleanup-region'. + + abort-on-bogus abort if there is any bogus whitespace and the + buffer is written or killed. + +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)))) + :group 'whitespace) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; User commands - Local mode + + +;;;###autoload +(define-minor-mode whitespace-mode + "Toggle whitespace minor mode visualization (\"ws\" on modeline). + +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." + :lighter " ws" + :init-value nil + :global nil + :group 'whitespace + (cond + (noninteractive ; running a batch job + (setq whitespace-mode nil)) + (whitespace-mode ; whitespace-mode on + (whitespace-turn-on) + (whitespace-action-when-on)) + (t ; whitespace-mode off + (whitespace-turn-off)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; User commands - Global mode + + +;;;###autoload +(define-minor-mode global-whitespace-mode + "Toggle whitespace global minor mode visualization (\"WS\" on modeline). + +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." + :lighter " WS" + :init-value nil + :global t + :group 'whitespace + (cond + (noninteractive ; running a batch job + (setq global-whitespace-mode nil)) + (global-whitespace-mode ; global-whitespace-mode on + (save-excursion + (add-hook 'find-file-hook 'whitespace-turn-on-if-enabled) + (dolist (buffer (buffer-list)) ; adjust all local mode + (set-buffer buffer) + (unless whitespace-mode + (whitespace-turn-on-if-enabled))))) + (t ; global-whitespace-mode off + (save-excursion + (remove-hook 'find-file-hook 'whitespace-turn-on-if-enabled) + (dolist (buffer (buffer-list)) ; adjust all local mode + (set-buffer buffer) + (unless whitespace-mode + (whitespace-turn-off))))))) + + +(defun whitespace-turn-on-if-enabled () + (when (cond + ((eq whitespace-global-modes t)) + ((listp whitespace-global-modes) + (if (eq (car-safe whitespace-global-modes) 'not) + (not (memq major-mode (cdr whitespace-global-modes))) + (memq major-mode whitespace-global-modes))) + (t nil)) + (let (inhibit-quit) + ;; Don't turn on whitespace mode if... + (or + ;; ...we don't have a display (we're running a batch job) + noninteractive + ;; ...or if the buffer is invisible (name starts with a space) + (eq (aref (buffer-name) 0) ?\ ) + ;; ...or if the buffer is temporary (name starts with *) + (and (eq (aref (buffer-name) 0) ?*) + ;; except the scratch buffer. + (not (string= (buffer-name) "*scratch*"))) + ;; Otherwise, turn on whitespace mode. + (whitespace-turn-on))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; User commands - Toggle + + +(defconst whitespace-color-value-list + '(tabs + spaces + trailing + lines + lines-tail + newline + empty + indentation + indentation::tab + indentation::space + space-after-tab + space-after-tab::tab + space-after-tab::space + 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 + space-mark + newline-mark + ) + "List of valid `whitespace-style-mark' values.") + + +(defconst whitespace-toggle-option-alist + '( ;; `whitespace-color-value-list' values + (?t . tabs) + (?s . spaces) + (?r . trailing) + (?l . lines) + (?L . lines-tail) + (?n . newline) + (?e . empty) + (?\C-i . indentation) + (?I . indentation::tab) + (?i . indentation::space) + (?\C-a . space-after-tab) + (?A . space-after-tab::tab) + (?a . space-after-tab::space) + (?\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) + ) + "Alist of toggle options. + +Each element has the form: + + (CHAR . SYMBOL) + +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'.") + + +(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-indent-tabs-mode indent-tabs-mode + "Used to save locally `indent-tabs-mode' value.") + +(defvar whitespace-tab-width tab-width + "Used to save locally `tab-width' value.") + + +;;;###autoload +(defun whitespace-toggle-options (arg) + "Toggle local `whitespace-mode' options. + +If local whitespace-mode is off, toggle the option given by ARG +and turn on local whitespace-mode. + +If local whitespace-mode is on, toggle the option given by ARG +and restart local whitespace-mode. + +Interactively, it reads one of the following chars: + + CHAR MEANING + (VIA FACES) + t toggle TAB visualization + s toggle SPACE and HARD SPACE visualization + r toggle trailing blanks visualization + l toggle \"long lines\" visualization + L toggle \"long lines\" tail visualization + n toggle NEWLINE visualization + e toggle empty line at bob and/or eob visualization + C-i toggle indentation SPACEs visualization (via `indent-tabs-mode') + I toggle indentation SPACEs visualization + i toggle indentation TABs visualization + C-a toggle SPACEs after TAB visualization (via `indent-tabs-mode') + A toggle SPACEs after TAB: SPACEs visualization + a toggle SPACEs after TAB: TABs visualization + C-b toggle SPACEs before TAB visualization (via `indent-tabs-mode') + B toggle SPACEs before TAB: SPACEs visualization + b toggle SPACEs before TAB: TABs visualization + + (VIA DISPLAY TABLE) + T toggle TAB visualization + S toggle SPACEs before TAB visualization + N toggle NEWLINE visualization + + x restore `whitespace-style-color' value + z restore `whitespace-style-mark' value + ? display brief help + +Non-interactively, ARG should be a symbol or a list of symbols. +The valid symbols are: + + tabs toggle TAB visualization + spaces toggle SPACE and HARD SPACE visualization + trailing toggle trailing blanks visualization + lines toggle \"long lines\" visualization + lines-tail toggle \"long lines\" tail visualization + newline toggle NEWLINE visualization + empty toggle empty line at bob and/or eob visualization + indentation toggle indentation SPACEs visualization + 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 + space-before-tab::space toggle SPACEs before TAB: TABs visualization + + tab-mark toggle TAB visualization + 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. + +See `whitespace-style-color', `whitespace-style-mark' 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))) + (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.") + + +;;;###autoload +(defun global-whitespace-toggle-options (arg) + "Toggle global `whitespace-mode' options. + +If global whitespace-mode is off, toggle the option given by ARG +and turn on global whitespace-mode. + +If global whitespace-mode is on, toggle the option given by ARG +and restart global whitespace-mode. + +Interactively, it accepts one of the following chars: + + CHAR MEANING + (VIA FACES) + t toggle TAB visualization + s toggle SPACE and HARD SPACE visualization + r toggle trailing blanks visualization + l toggle \"long lines\" visualization + L toggle \"long lines\" tail visualization + n toggle NEWLINE visualization + e toggle empty line at bob and/or eob visualization + C-i toggle indentation SPACEs visualization (via `indent-tabs-mode') + I toggle indentation SPACEs visualization + i toggle indentation TABs visualization + C-a toggle SPACEs after TAB visualization (via `indent-tabs-mode') + A toggle SPACEs after TAB: SPACEs visualization + a toggle SPACEs after TAB: TABs visualization + C-b toggle SPACEs before TAB visualization (via `indent-tabs-mode') + B toggle SPACEs before TAB: SPACEs visualization + b toggle SPACEs before TAB: TABs visualization + + (VIA DISPLAY TABLE) + T toggle TAB visualization + S toggle SPACEs before TAB visualization + N toggle NEWLINE visualization + + x restore `whitespace-style-color' value + z restore `whitespace-style-mark' value + ? display brief help + +Non-interactively, ARG should be a symbol or a list of symbols. +The valid symbols are: + + tabs toggle TAB visualization + spaces toggle SPACE and HARD SPACE visualization + trailing toggle trailing blanks visualization + lines toggle \"long lines\" visualization + lines-tail toggle \"long lines\" tail visualization + newline toggle NEWLINE visualization + empty toggle empty line at bob and/or eob visualization + indentation toggle indentation SPACEs visualization + 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 + space-before-tab::space toggle SPACEs before TAB: TABs visualization + + tab-mark toggle TAB visualization + 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. + +See `whitespace-style-color', `whitespace-style-mark' 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) + (global-whitespace-mode 0) + (global-whitespace-mode 1))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; User commands - Cleanup + + +;;;###autoload +(defun whitespace-cleanup () + "Cleanup some blank problems in all buffer or at region. + +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 +mark is active and \\[universal-argument] was pressed just before +calling `whitespace-cleanup' interactively. + +See also `whitespace-cleanup-region'. + +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 + 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': + 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. + +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 + `space-before-tab::tab', replace SPACEs by TABs. + If `whitespace-style-color' 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. + +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 + `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 + (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) + (let (overwrite-mode) ; enforce no overwrite + (goto-char (point-min)) + (when (re-search-forward + 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) + (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)))) + + +;;;###autoload +(defun whitespace-cleanup-region (start end) + "Cleanup some blank problems at region. + +The problems cleaned up are: + +1. 8 or more SPACEs at beginning of line. + If `whitespace-style-color' 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. + +2. 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 + `space-before-tab::tab', replace SPACEs by TABs. + If `whitespace-style-color' 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 + 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': + 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 + `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 + + +(defun whitespace-replace-action (action rstart rend regexp index) + "Do ACTION in the string matched by REGEXP between RSTART and REND. + +INDEX is the level group matched by REGEXP and used by ACTION. + +See also `tab-width'." + (goto-char rstart) + (while (re-search-forward regexp rend t) + (goto-char (match-end index)) + (funcall action (match-beginning index) (match-end index)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; 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 + ((or (eq kind 'tab) + whitespace-indent-tabs-mode) + (format (car regexp) whitespace-tab-width)) + ((or (eq kind 'space) + (not whitespace-indent-tabs-mode)) + (cdr regexp)))) + + +(defun whitespace-indentation-regexp (&optional kind) + "Return the indentation regexp depending on `whitespace-indent-tabs-mode'." + (whitespace-regexp whitespace-indentation-regexp kind)) + + +(defun whitespace-space-after-tab-regexp (&optional kind) + "Return the space-after-tab regexp depending on `whitespace-indent-tabs-mode'." + (whitespace-regexp whitespace-space-after-tab-regexp kind)) + + +(defconst whitespace-report-list + (list + (cons 'empty whitespace-empty-at-bob-regexp) + (cons 'empty whitespace-empty-at-eob-regexp) + (cons 'trailing (whitespace-trailing-regexp)) + (cons 'indentation nil) + (cons 'indentation::tab nil) + (cons 'indentation::space nil) + (cons 'space-before-tab whitespace-space-before-tab-regexp) + (cons 'space-before-tab::tab whitespace-space-before-tab-regexp) + (cons 'space-before-tab::space whitespace-space-before-tab-regexp) + (cons 'space-after-tab nil) + (cons 'space-after-tab::tab nil) + (cons 'space-after-tab::space nil) + ) + "List of whitespace bogus symbol and corresponding regexp.") + + +(defconst whitespace-report-text + '( ;; `indent-tabs-mode' has non-nil value + "\ + Whitespace Report + + Current Setting Whitespace Problem + + empty [] [] empty lines at beginning of buffer + empty [] [] empty lines at end of buffer + trailing [] [] SPACEs or TABs at end of line + indentation [] [] 8 or more SPACEs at beginning of line + indentation::tab [] [] 8 or more SPACEs at beginning of line + indentation::space [] [] TABs at beginning of line + space-before-tab [] [] SPACEs before TAB + space-before-tab::tab [] [] SPACEs before TAB: SPACEs + space-before-tab::space [] [] SPACEs before TAB: TABs + space-after-tab [] [] 8 or more SPACEs after TAB + space-after-tab::tab [] [] 8 or more SPACEs after TAB: SPACEs + space-after-tab::space [] [] 8 or more SPACEs after TAB: TABs + + indent-tabs-mode = + tab-width = \n\n" + . ;; `indent-tabs-mode' has nil value + "\ + Whitespace Report + + Current Setting Whitespace Problem + + empty [] [] empty lines at beginning of buffer + empty [] [] empty lines at end of buffer + trailing [] [] SPACEs or TABs at end of line + indentation [] [] TABs at beginning of line + indentation::tab [] [] 8 or more SPACEs at beginning of line + indentation::space [] [] TABs at beginning of line + space-before-tab [] [] SPACEs before TAB + space-before-tab::tab [] [] SPACEs before TAB: SPACEs + space-before-tab::space [] [] SPACEs before TAB: TABs + space-after-tab [] [] 8 or more SPACEs after TAB + space-after-tab::tab [] [] 8 or more SPACEs after TAB: SPACEs + space-after-tab::space [] [] 8 or more SPACEs after TAB: TABs + + indent-tabs-mode = + tab-width = \n\n") + "Text for whitespace bogus report. + +It is a cons of strings, where the car part is used when +`indent-tabs-mode' is non-nil, and the cdr part is used when +`indent-tabs-mode' is nil.") + + +(defconst whitespace-report-buffer-name "*Whitespace Report*" + "The buffer name for whitespace bogus report.") + + +;;;###autoload +(defun whitespace-report (&optional force report-if-bogus) + "Report some whitespace problems in buffer. + +Return nil if there is no whitespace problem; otherwise, return +non-nil. + +If FORCE is non-nil or \\[universal-argument] was pressed just +before calling `whitespace-report' interactively, it forces +`whitespace-style-color' to have: + + empty + trailing + indentation + space-before-tab + space-after-tab + +If REPORT-IF-BOGUS is non-nil, it reports only when there are any +whitespace problems in buffer. + +Report if some of the following whitespace problems exist: + +* If `indent-tabs-mode' is non-nil: + empty 1. empty lines at beginning of buffer. + empty 2. empty lines at end of buffer. + trailing 3. SPACEs or TABs at end of line. + indentation 4. 8 or more SPACEs at beginning of line. + space-before-tab 5. SPACEs before TAB. + space-after-tab 6. 8 or more SPACEs after TAB. + +* If `indent-tabs-mode' is nil: + empty 1. empty lines at beginning of buffer. + empty 2. empty lines at end of buffer. + trailing 3. SPACEs or TABs at end of line. + indentation 4. TABS at beginning of line. + space-before-tab 5. SPACEs before TAB. + space-after-tab 6. 8 or more SPACEs after TAB. + +See `whitespace-style-color' and `whitespace-style-mark' for +documentation. +See also `whitespace-cleanup' and `whitespace-cleanup-region' for +cleaning up these problems." + (interactive (list current-prefix-arg)) + (whitespace-report-region (point-min) (point-max) + force report-if-bogus)) + + +;;;###autoload +(defun whitespace-report-region (start end &optional force report-if-bogus) + "Report some whitespace problems in a region. + +Return nil if there is no whitespace problem; otherwise, return +non-nil. + +If FORCE is non-nil or \\[universal-argument] was pressed just +before calling `whitespace-report-region' interactively, it +forces `whitespace-style-color' to have: + + empty + indentation + space-before-tab + trailing + space-after-tab + +If REPORT-IF-BOGUS is non-nil, it reports only when there are any +whitespace problems in buffer. + +Report if some of the following whitespace problems exist: + +* If `indent-tabs-mode' is non-nil: + empty 1. empty lines at beginning of buffer. + empty 2. empty lines at end of buffer. + trailing 3. SPACEs or TABs at end of line. + indentation 4. 8 or more SPACEs at beginning of line. + space-before-tab 5. SPACEs before TAB. + space-after-tab 6. 8 or more SPACEs after TAB. + +* If `indent-tabs-mode' is nil: + empty 1. empty lines at beginning of buffer. + empty 2. empty lines at end of buffer. + trailing 3. SPACEs or TABs at end of line. + indentation 4. TABS at beginning of line. + space-before-tab 5. SPACEs before TAB. + space-after-tab 6. 8 or more SPACEs after TAB. + +See `whitespace-style-color' and `whitespace-style-mark' for +documentation. +See also `whitespace-cleanup' and `whitespace-cleanup-region' for +cleaning up these problems." + (interactive "r") + (setq force (or current-prefix-arg force)) + (save-excursion + (save-match-data + (let* ((has-bogus nil) + (rstart (min start end)) + (rend (max start end)) + (bogus-list + (mapcar + #'(lambda (option) + (when force + (add-to-list 'whitespace-style-color + (car option))) + (goto-char rstart) + (let ((regexp + (cond + ((eq (car option) 'indentation) + (whitespace-indentation-regexp)) + ((eq (car option) 'indentation::tab) + (whitespace-indentation-regexp 'tab)) + ((eq (car option) 'indentation::space) + (whitespace-indentation-regexp 'space)) + ((eq (car option) 'space-after-tab) + (whitespace-space-after-tab-regexp)) + ((eq (car option) 'space-after-tab::tab) + (whitespace-space-after-tab-regexp 'tab)) + ((eq (car option) 'space-after-tab::space) + (whitespace-space-after-tab-regexp 'space)) + (t + (cdr option))))) + (and (re-search-forward regexp rend t) + (setq has-bogus t)))) + whitespace-report-list))) + (when (if report-if-bogus has-bogus t) + (whitespace-kill-buffer whitespace-report-buffer-name) + ;; `whitespace-indent-tabs-mode' is local to current buffer + ;; `whitespace-tab-width' is local to current buffer + (let ((ws-indent-tabs-mode whitespace-indent-tabs-mode) + (ws-tab-width whitespace-tab-width)) + (with-current-buffer (get-buffer-create + whitespace-report-buffer-name) + (erase-buffer) + (insert (if ws-indent-tabs-mode + (car whitespace-report-text) + (cdr whitespace-report-text))) + (goto-char (point-min)) + (forward-line 3) + (dolist (option whitespace-report-list) + (forward-line 1) + (whitespace-mark-x + 27 (memq (car option) whitespace-style-color)) + (whitespace-mark-x 7 (car bogus-list)) + (setq bogus-list (cdr bogus-list))) + (forward-line 1) + (whitespace-insert-value ws-indent-tabs-mode) + (whitespace-insert-value ws-tab-width) + (when has-bogus + (goto-char (point-max)) + (insert " Type `M-x whitespace-cleanup'" + " to cleanup the buffer.\n\n" + " Type `M-x whitespace-cleanup-region'" + " to cleanup a region.\n\n")) + (whitespace-display-window (current-buffer))))) + has-bogus)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Internal functions + + +(defvar whitespace-font-lock-mode nil + "Used to remember whether a buffer had font lock mode on or not.") + +(defvar whitespace-font-lock nil + "Used to remember whether a buffer initially had font lock on or not.") + +(defvar whitespace-font-lock-keywords nil + "Used to save locally `font-lock-keywords' value.") + + +(defconst whitespace-help-text + "\ + Whitespace Toggle Options + + FACES + [] t - toggle TAB visualization + [] s - toggle SPACE and HARD SPACE visualization + [] r - toggle trailing blanks visualization + [] l - toggle \"long lines\" visualization + [] L - toggle \"long lines\" tail visualization + [] n - toggle NEWLINE visualization + [] e - toggle empty line at bob and/or eob visualization + [] C-i - toggle indentation SPACEs visualization (via `indent-tabs-mode') + [] I - toggle indentation SPACEs visualization + [] i - toggle indentation TABs visualization + [] C-a - toggle SPACEs after TAB visualization (via `indent-tabs-mode') + [] A - toggle SPACEs after TAB: SPACEs visualization + [] a - toggle SPACEs after TAB: TABs visualization + [] C-b - toggle SPACEs before TAB visualization (via `indent-tabs-mode') + [] B - toggle SPACEs before TAB: SPACEs visualization + [] b - toggle SPACEs before TAB: TABs visualization + + DISPLAY TABLE + [] T - toggle TAB visualization + [] S - toggle SPACE and HARD SPACE visualization + [] N - toggle NEWLINE visualization + + x - restore `whitespace-style-color' value + z - restore `whitespace-style-mark' value + + ? - display this text\n\n" + "Text for whitespace toggle options.") + + +(defconst whitespace-help-buffer-name "*Whitespace Toggle Options*" + "The buffer name for whitespace toggle options.") + + +(defun whitespace-insert-value (value) + "Insert VALUE at column 20 of next line." + (forward-line 1) + (move-to-column 20 t) + (insert (format "%s" value))) + + +(defun whitespace-mark-x (nchars condition) + "Insert the mark ('X' or ' ') after NCHARS depending on CONDITION." + (forward-char nchars) + (insert (if condition "X" " "))) + + +(defun whitespace-insert-option-mark (the-list the-value) + "Insert the option mark ('X' or ' ') in toggle options buffer." + (forward-line 2) + (dolist (sym the-list) + (forward-line 1) + (whitespace-mark-x 2 (memq sym the-value)))) + + +(defun whitespace-help-on (chars 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) + (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-display-window buffer))))) + + +(defun whitespace-display-window (buffer) + "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; \ +can't split window to display whitespace toggle options")) + (set-window-buffer (split-window nil size) buffer))) + + +(defun whitespace-kill-buffer (buffer-name) + "Kill buffer BUFFER-NAME and windows related with it." + (let ((buffer (get-buffer buffer-name))) + (when buffer + (delete-windows-on buffer) + (kill-buffer buffer)))) + + +(defun whitespace-help-off () + "Remove the buffer and window of the whitespace toggle options." + (whitespace-kill-buffer whitespace-help-buffer-name)) + + +(defun whitespace-interactive-char (local-p) + "Interactive function to read a char and return a symbol. + +If LOCAL-P is non-nil, it uses a local context; otherwise, it +uses a global context. + +It accepts one of the following chars: + + CHAR MEANING + (VIA FACES) + t toggle TAB visualization + s toggle SPACE and HARD SPACE visualization + r toggle trailing blanks visualization + l toggle \"long lines\" visualization + L toggle \"long lines\" tail visualization + n toggle NEWLINE visualization + e toggle empty line at bob and/or eob visualization + C-i toggle indentation SPACEs visualization (via `indent-tabs-mode') + I toggle indentation SPACEs visualization + i toggle indentation TABs visualization + C-a toggle SPACEs after TAB visualization (via `indent-tabs-mode') + A toggle SPACEs after TAB: SPACEs visualization + a toggle SPACEs after TAB: TABs visualization + C-b toggle SPACEs before TAB visualization (via `indent-tabs-mode') + B toggle SPACEs before TAB: SPACEs visualization + b toggle SPACEs before TAB: TABs visualization + + (VIA DISPLAY TABLE) + T toggle TAB visualization + S toggle SPACE and HARD SPACE visualization + N toggle NEWLINE visualization + + x restore `whitespace-style-color' value + z restore `whitespace-style-mark' 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))) + (prompt + (format "Whitespace Toggle %s (type ? for further options)-" + (if local-p "Local" "Global"))) + ch sym) + ;; read a valid option and get the corresponding symbol + (save-window-excursion + (condition-case data + (progn + (while + ;; while condition + (progn + (setq ch (read-char prompt)) + (not + (setq sym + (cdr + (assq ch whitespace-toggle-option-alist))))) + ;; while body + (if (eq ch ?\?) + (whitespace-help-on chars style) + (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 + + +(defun whitespace-toggle-list (local-p arg the-list default-list + sym-restore sym-list) + "Toggle options in THE-LIST based on list ARG. + +If LOCAL-P is non-nil, it uses a local context; otherwise, it +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." + (unless (if local-p whitespace-mode global-whitespace-mode) + (setq the-list default-list)) + (setq the-list (copy-sequence the-list)) ; keep original list + (dolist (sym (if (listp arg) arg (list arg))) + (cond + ;; restore default values + ((eq sym sym-restore) + (setq the-list default-list)) + ;; toggle valid values + ((memq sym sym-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) + ;; 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-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 + (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 + (whitespace-display-char-off))) + + +(defun whitespace-color-on () + "Turn on color visualization." + (when whitespace-active-color + (unless whitespace-font-lock + (setq whitespace-font-lock t + whitespace-font-lock-keywords + (copy-sequence font-lock-keywords))) + ;; 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) + (font-lock-add-keywords + nil + (list + ;; Show SPACEs + (list whitespace-space-regexp 1 whitespace-space t) + ;; Show HARD SPACEs + (list whitespace-hspace-regexp 1 whitespace-hspace t)) + t)) + (when (memq 'tabs whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show TABs + (list whitespace-tab-regexp 1 whitespace-tab t)) + t)) + (when (memq 'trailing whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show trailing blanks + (list (whitespace-trailing-regexp) 1 whitespace-trailing t)) + t)) + (when (or (memq 'lines whitespace-active-color) + (memq 'lines-tail whitespace-active-color)) + (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) + 0 ; whole line + 2) ; line tail + whitespace-line t)) + t)) + (cond + ((memq 'space-before-tab whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show SPACEs before TAB (indent-tabs-mode) + (list whitespace-space-before-tab-regexp + (if whitespace-indent-tabs-mode 1 2) + whitespace-space-before-tab t)) + t)) + ((memq 'space-before-tab::tab whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show SPACEs before TAB (SPACEs) + (list whitespace-space-before-tab-regexp + 1 whitespace-space-before-tab t)) + t)) + ((memq 'space-before-tab::space whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show SPACEs before TAB (TABs) + (list whitespace-space-before-tab-regexp + 2 whitespace-space-before-tab t)) + t))) + (cond + ((memq 'indentation whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show indentation SPACEs (indent-tabs-mode) + (list (whitespace-indentation-regexp) + 1 whitespace-indentation t)) + t)) + ((memq 'indentation::tab whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show indentation SPACEs (SPACEs) + (list (whitespace-indentation-regexp 'tab) + 1 whitespace-indentation t)) + t)) + ((memq 'indentation::space whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show indentation SPACEs (TABs) + (list (whitespace-indentation-regexp 'space) + 1 whitespace-indentation t)) + t))) + (when (memq 'empty whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show empty lines at beginning of buffer + (list whitespace-empty-at-bob-regexp + 1 whitespace-empty t)) + t) + (font-lock-add-keywords + nil + (list + ;; Show empty lines at end of buffer + (list whitespace-empty-at-eob-regexp + 1 whitespace-empty t)) + t)) + (cond + ((memq 'space-after-tab whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show SPACEs after TAB (indent-tabs-mode) + (list (whitespace-space-after-tab-regexp) + 1 whitespace-space-after-tab t)) + t)) + ((memq 'space-after-tab::tab whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show SPACEs after TAB (SPACEs) + (list (whitespace-space-after-tab-regexp 'tab) + 1 whitespace-space-after-tab t)) + t)) + ((memq 'space-after-tab::space whitespace-active-color) + (font-lock-add-keywords + nil + (list + ;; Show SPACEs after TAB (TABs) + (list (whitespace-space-after-tab-regexp 'space) + 1 whitespace-space-after-tab t)) + t))) + ;; now turn on font lock and highlight blanks + (font-lock-mode 1))) + + +(defun whitespace-color-off () + "Turn off color visualization." + (when whitespace-active-color + ;; turn off font lock + (font-lock-mode 0) + (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))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Hacked from visws.el (Miles Bader ) + + +(defsubst whitespace-char-valid-p (char) + ;; This check should be improved!!! + (or (< char 256) + (characterp char))) + + +(defun whitespace-display-vector-p (vec) + "Return true if every character in vector VEC can be displayed." + (let ((i (length vec))) + (when (> i 0) + (while (and (>= (setq i (1- i)) 0) + (whitespace-char-valid-p (aref vec i)))) + (< i 0)))) + + +(defun whitespace-display-char-on () + "Turn on character display mapping." + (when whitespace-display-mappings + (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))) + (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) + ;; Get a displayable mapping. + (setq vecs (cddr entry)) + (while (and vecs + (not (whitespace-display-vector-p (car vecs)))) + (setq vecs (cdr vecs))) + ;; Display a valid mapping. + (when vecs + (setq vec (copy-sequence (car vecs))) + ;; NEWLINE char + (when (and (eq (cadr entry) ?\n) + (memq 'newline whitespace-active-color)) + ;; Only insert face bits on NEWLINE char mapping to avoid + ;; obstruction of other faces like TABs and (HARD) SPACEs + ;; faces, font-lock faces, etc. + (dotimes (i (length vec)) + (or (eq (aref vec i) ?\n) + (aset vec i + (make-glyph-code (aref vec i) + whitespace-newline))))) + ;; Display mapping + (aset buffer-display-table (cadr entry) vec))))))) + + +(defun whitespace-display-char-off () + "Turn off character display mapping." + (and whitespace-display-mappings + whitespace-display-table-was-local + (setq whitespace-display-table-was-local nil + buffer-display-table whitespace-display-table))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Hook + + +(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-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) + 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-unload-function () + "Unload the whitespace library." + (global-whitespace-mode -1) + ;; be sure all local whitespace mode is turned off + (save-current-buffer + (dolist (buf (buffer-list)) + (set-buffer buf) + (whitespace-mode -1))) + nil) ; continue standard unloading + + +(provide 'whitespace) + + +(run-hooks 'whitespace-load-hook) + + +;; arch-tag: 1b1e2500-dbd4-4a26-8f7a-5a5edfd3c97e +;;; whitespace.el ends here