changeset 79869:a8237408c221

New file: blank-mode.el
author Vinicius Jose Latorre <viniciusjl@ig.com.br>
date Thu, 17 Jan 2008 12:48:41 +0000
parents 9538ce91bacf
children b508fea5860e
files lisp/ChangeLog lisp/blank-mode.el
diffstat 2 files changed, 1289 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Thu Jan 17 12:05:19 2008 +0000
+++ b/lisp/ChangeLog	Thu Jan 17 12:48:41 2008 +0000
@@ -1,3 +1,11 @@
+2008-01-17 Vinicius Jose Latorre <viniciusjl@ig.com.br>
+2008-01-17 Miles Bader <miles@gnu.org>
+
+	* blank-mode.el: New file.  Minor mode to visualise TAB,
+	(HARD) SPACE, NEWLINE.  Miles Bader <miles@gnu.org> wrote the original
+	code for handling display table (via visws.el package), his code was
+	modified, but the main idea was kept.
+
 2008-01-16  Alan Mackenzie  <acm@muc.de>
 
 	* progmodes/cc-vars.el (c-constant-symbol): Put this defun inside
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/blank-mode.el	Thu Jan 17 12:48:41 2008 +0000
@@ -0,0 +1,1281 @@
+;;; blank-mode.el --- minor mode to visualise TAB, (HARD) SPACE, NEWLINE
+
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+;;   Free Software Foundation, Inc.
+
+;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
+;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
+;; Keywords: data, wp
+;; Version: 8.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 visualise blanks (TAB, (HARD) SPACE
+;; and NEWLINE).
+;;
+;; blank-mode uses two ways to visualise blanks: faces and display
+;; table.
+;;
+;; * Faces are used to highlight the background with a color.
+;;   blank-mode 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 `blank-style' and `blank-chars' variables are used to select
+;; which way should be used to visualise blanks.
+;;
+;; Note that when blank-mode is turned on, blank-mode saves the
+;; font-lock state, that is, if font-lock is on or off.  And
+;; blank-mode restores the font-lock state when it is turned off.  So,
+;; if blank-mode is turned on and font-lock is off, blank-mode also
+;; turns on the font-lock to highlight blanks, but the font-lock will
+;; be turned off when blank-mode is turned off.  Thus, turn on
+;; font-lock before blank-mode is on, if you want that font-lock
+;; continues on after blank-mode is turned off.
+;;
+;; When blank-mode 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 blank-mode: local and global.
+;;
+;; * Local blank-mode affects only the current buffer.
+;;
+;; * Global blank-mode affects all current and future buffers.  That
+;;   is, if you turn on global blank-mode and then create a new
+;;   buffer, the new buffer will also have blank-mode on.  The
+;;   `blank-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 blank-mode has priority over global blank-mode.  Blank 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 blank-mode are on:
+;;
+;; * if local blank-mode is turned off, blank-mode is turned off for
+;;   the current buffer only.
+;;
+;; * if global blank-mode is turned off, blank-mode continues on only
+;;   in the buffers in which local blank-mode is on.
+;;
+;; To use blank-mode, insert in your ~/.emacs:
+;;
+;;    (require 'blank-mode)
+;;
+;; Or autoload at least one of the commands`blank-mode',
+;; `blank-toggle-options', `global-blank-mode' or
+;; `global-blank-toggle-options'.  For example:
+;;
+;;    (autoload 'blank-mode                  "blank-mode"
+;;      "Toggle blank visualisation."          t)
+;;    (autoload 'blank-toggle-options        "blank-mode"
+;;      "Toggle local `blank-mode' options."   t)
+;;
+;; blank-mode was inspired by:
+;;
+;;    show-whitespace-mode.el  Aurelien Tisne <aurelien.tisne@free.fr>
+;;       Simple mode to highlight whitespaces
+;;       (inspired the idea to use font-lock)
+;;
+;;    whitespace-mode.el       Lawrence Mitchell <wence@gmx.li>
+;;       Major mode for editing Whitespace
+;;       (inspired the idea to use display table)
+;;
+;;    visws.el                 Miles Bader <miles@gnu.org>
+;;       Make whitespace visible
+;;       (handle display table, his code was modified, but the main
+;;       idea was kept)
+;;
+;;
+;; Using blank-mode
+;; ----------------
+;;
+;; There is no problem if you mix local and global minor mode usage.
+;;
+;; * LOCAL blank-mode:
+;;    + To toggle blank-mode options locally, type:
+;;
+;;         M-x blank-toggle-options RET
+;;
+;;    + To activate blank-mode locally, type:
+;;
+;;         C-u 1 M-x blank-mode RET
+;;
+;;    + To deactivate blank-mode locally, type:
+;;
+;;         C-u 0 M-x blank-mode RET
+;;
+;;    + To toggle blank-mode locally, type:
+;;
+;;         M-x blank-mode RET
+;;
+;; * GLOBAL blank-mode:
+;;    + To toggle blank-mode options globally, type:
+;;
+;;         M-x global-blank-toggle-options RET
+;;
+;;    + To activate blank-mode globally, type:
+;;
+;;         C-u 1 M-x global-blank-mode RET
+;;
+;;    + To deactivate blank-mode globally, type:
+;;
+;;         C-u 0 M-x global-blank-mode RET
+;;
+;;    + To toggle blank-mode globally, type:
+;;
+;;         M-x global-blank-mode RET
+;;
+;;
+;; Hooks
+;; -----
+;;
+;; blank-mode has the following hook variables:
+;;
+;; `blank-mode-hook'
+;;    It is evaluated always when blank-mode is turned on locally.
+;;
+;; `global-blank-mode-hook'
+;;    It is evaluated always when blank-mode is turned on globally.
+;;
+;; `blank-load-hook'
+;;    It is evaluated after blank-mode package is loaded.
+;;
+;;
+;; Options
+;; -------
+;;
+;; Below it's shown a brief description of blank-mode options, please,
+;; see the options declaration in the code for a long documentation.
+;;
+;; `blank-style'		Specify the visualisation style.
+;;
+;; `blank-chars'		Specify which kind of blank is
+;;				visualised.
+;;
+;; `blank-space-face'		Face used to visualise SPACE.
+;;
+;; `blank-hspace-face'		Face used to visualise HARD SPACE.
+;;
+;; `blank-tab-face'		Face used to visualise TAB.
+;;
+;; `blank-newline-face'		Face used to visualise NEWLINE char
+;;				mapping.
+;;
+;; `blank-trailing-face'	Face used to visualise trailing
+;;				blanks.
+;;
+;; `blank-line-face'		Face used to visualise "long" lines.
+;;
+;; `blank-space-before-tab-face'	Face used to visualise SPACEs
+;;					before TAB.
+;;
+;; `blank-space-regexp'		Specify SPACE characters regexp.
+;;
+;; `blank-hspace-regexp'	Specify HARD SPACE characters regexp.
+;;
+;; `blank-tab-regexp'		Specify TAB characters regexp.
+;;
+;; `blank-trailing-regexp'	Specify trailing characters regexp.
+;;
+;; `blank-space-before-tab-regexp'	Specify SPACEs before TAB
+;;					regexp.
+;;
+;; `blank-line-length'		Specify length beyond which the line
+;;				is highlighted.
+;;
+;; `blank-display-mappings'	Specify an alist of mappings for
+;;				displaying characters.
+;;
+;; `blank-global-modes'		Modes for which global `blank-mode' is
+;;				automagically turned on.
+;;
+;;
+;; Acknowledgements
+;; ----------------
+;;
+;; Thanks to Juri Linkov <juri@jurta.org> for suggesting:
+;;    * `define-minor-mode'.
+;;    * `global-blank-*' name for global commands.
+;;
+;; Thanks to Robert J. Chassell <bob@gnu.org> for doc fix and testing.
+;;
+;; Thanks to Drew Adams <drew.adams@oracle.com> for toggle commands
+;; suggestion.
+;;
+;; Thanks to Antti Kaihola <antti.kaihola@linux-aktivaattori.org> for
+;; helping to fix `find-file-hooks' reference.
+;;
+;; Thanks to Andreas Roehler <andreas.roehler@easy-emacs.de> for
+;; indicating defface byte-compilation warnings.
+;;
+;; Thanks to TimOCallaghan (EmacsWiki) for the idea about highlight
+;; "long" lines. See EightyColumnRule (EmacsWiki).
+;;
+;; Thanks to Yanghui Bian <yanghuibian@gmail.com> for indicating a new
+;; newline character mapping.
+;;
+;; Thanks to Pete Forman <pete.forman@westgeo.com> for indicating
+;; whitespace-mode on XEmacs.
+;;
+;; Thanks to Miles Bader <miles@gnu.org> for handling display table via
+;; visws.el (his code was modified, but the main idea was kept).
+;;
+;; Thanks to:
+;;    Aurelien Tisne <aurelien.tisne@free.fr>	show-whitespace-mode.el
+;;    Lawrence Mitchell <wence@gmx.li>		whitespace-mode.el
+;;    Miles Bader <miles@gnu.org>		visws.el
+;; And to all people who contributed with them.
+;;
+;;
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; code:
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; User Variables:
+
+
+;;; Interface to the command system
+
+
+(defgroup blank nil
+  "Visualise blanks (TAB, (HARD) SPACE and NEWLINE)."
+  :link '(emacs-library-link :tag "Source Lisp File" "blank-mode.el")
+  :version "22.2"
+  :group 'wp
+  :group 'data)
+
+
+(defcustom blank-style '(mark color)
+  "*Specify the visualisation style.
+
+It's a list which element value can be:
+
+   mark		display mappings are visualised.
+
+   color	faces are visualised.
+
+Any other value is ignored.
+
+If it's nil, don't visualise TABs, (HARD) SPACEs and NEWLINEs.
+
+See also `blank-display-mappings' for documentation."
+  :type '(repeat :tag "Style of Blank"
+		 (choice :tag "Style of Blank"
+			 (const :tag "Display Table" mark)
+			 (const :tag "Faces" color)))
+  :group 'blank)
+
+
+(defcustom blank-chars
+  '(tabs spaces trailing lines space-before-tab newline)
+  "*Specify which kind of blank is visualised.
+
+It's a list which element value can be:
+
+   trailing		trailing blanks are visualised.
+
+   tabs			TABs are visualised.
+
+   spaces		SPACEs and HARD SPACEs are visualised.
+
+   lines		lines whose length is greater than
+			`blank-line-length' are highlighted.
+
+   space-before-tab	SPACEs before TAB are visualised.
+
+   newline		NEWLINEs are visualised.
+
+Any other element value is ignored.
+
+If it's nil, don't visualise TABs, (HARD) SPACEs and NEWLINEs.
+
+Used when `blank-style' has `color' as an element.
+If `blank-chars' has `newline' as an element, used when `blank-style'
+has `mark' as an element."
+  :type '(repeat :tag "Kind of Blank"
+		 (choice :tag "Kind of Blank"
+			 (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)))
+  :group 'blank)
+
+
+(defcustom blank-space-face 'blank-space-face
+  "*Symbol face used to visualise SPACE.
+
+Used when `blank-style' has `color' as an element."
+  :type 'face
+  :group 'blank)
+
+
+(defface blank-space-face
+  '((((class color) (background dark))
+     (:background "grey20"      :foreground "aquamarine3"))
+    (((class color) (background light))
+     (:background "LightYellow" :foreground "aquamarine3"))
+    (t (:inverse-video t)))
+  "Face used to visualise SPACE."
+  :group 'blank)
+
+
+(defcustom blank-hspace-face 'blank-hspace-face
+  "*Symbol face used to visualise HARD SPACE.
+
+Used when `blank-style' has `color' as an element."
+  :type 'face
+  :group 'blank)
+
+
+(defface blank-hspace-face		; '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 visualise HARD SPACE."
+  :group 'blank)
+
+
+(defcustom blank-tab-face 'blank-tab-face
+  "*Symbol face used to visualise TAB.
+
+Used when `blank-style' has `color' as an element."
+  :type 'face
+  :group 'blank)
+
+
+(defface blank-tab-face
+  '((((class color) (background dark))
+     (:background "grey22" :foreground "aquamarine3"))
+    (((class color) (background light))
+     (:background "beige"  :foreground "aquamarine3"))
+    (t (:inverse-video t)))
+  "Face used to visualise TAB."
+  :group 'blank)
+
+
+(defcustom blank-newline-face 'blank-newline-face
+  "*Symbol face used to visualise NEWLINE char mapping.
+
+See `blank-display-mappings'.
+
+Used when `blank-style' has `mark' and `color' as elements
+and `blank-chars' has `newline' as an element."
+  :type 'face
+  :group 'blank)
+
+
+(defface blank-newline-face
+  '((((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 visualise NEWLINE char mapping.
+
+See `blank-display-mappings'."
+  :group 'blank)
+
+
+(defcustom blank-trailing-face 'blank-trailing-face
+  "*Symbol face used to visualise traling blanks.
+
+Used when `blank-style' has `color' as an element."
+  :type 'face
+  :group 'blank)
+
+
+(defface blank-trailing-face		; 'trailing-whitespace
+  '((((class mono)) (:inverse-video t :bold t :underline t))
+    (t (:background "red1" :foreground "yellow" :bold t)))
+  "Face used to visualise trailing blanks."
+  :group 'blank)
+
+
+(defcustom blank-line-face 'blank-line-face
+  "*Symbol face used to visualise \"long\" lines.
+
+See `blank-line-legnth'.
+
+Used when `blank-style' has `color' as an element."
+  :type 'face
+  :group 'blank)
+
+
+(defface blank-line-face
+  '((((class mono)) (:inverse-video t :bold t :underline t))
+    (t (:background "gray20" :foreground "violet")))
+  "Face used to visualise \"long\" lines.
+
+See `blank-line-length'."
+  :group 'blank)
+
+
+(defcustom blank-space-before-tab-face 'blank-space-before-tab-face
+  "*Symbol face used to visualise SPACEs before TAB.
+
+Used when `blank-style' has `color' as an element."
+  :type 'face
+  :group 'blank)
+
+
+(defface blank-space-before-tab-face
+  '((((class mono)) (:inverse-video t :bold t :underline t))
+    (t (:background "DarkOrange" :foreground "firebrick")))
+  "Face used to visualise SPACEs before TAB."
+  :group 'blank)
+
+
+(defcustom blank-hspace-regexp
+  "\\(\\(\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20\\)+\\)"
+  "*Specify HARD SPACE characters regexp.
+
+If you're using `mule' package, it may exist other characters besides:
+
+   \"\\xA0\"   \"\\x8A0\"   \"\\x920\"   \"\\xE20\"   \"\\xF20\"
+
+that it should be considered HARD SPACE.
+
+Here are some examples:
+
+   \"\\\\(^\\xA0+\\\\)\"		\
+visualise only leading HARD SPACEs.
+   \"\\\\(\\xA0+$\\\\)\"		\
+visualise only trailing HARD SPACEs.
+   \"\\\\(^\\xA0+\\\\|\\xA0+$\\\\)\"	\
+visualise leading and/or trailing HARD SPACEs.
+   \"\\t\\\\(\\xA0+\\\\)\\t\"		\
+visualise only HARD SPACEs between TABs.
+
+NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
+      Use exactly one pair of enclosing \\\\( and \\\\).
+
+Used when `blank-style' has `color' as an element, and
+`blank-chars' has `spaces' as an element."
+  :type '(regexp :tag "HARD SPACE Chars")
+  :group 'blank)
+
+
+(defcustom blank-space-regexp "\\( +\\)"
+  "*Specify SPACE characters regexp.
+
+If you're using `mule' package, it may exist other characters
+besides \" \" that it should be considered SPACE.
+
+Here are some examples:
+
+   \"\\\\(^ +\\\\)\"		visualise only leading SPACEs.
+   \"\\\\( +$\\\\)\"		visualise only trailing SPACEs.
+   \"\\\\(^ +\\\\| +$\\\\)\"	\
+visualise leading and/or trailing SPACEs.
+   \"\\t\\\\( +\\\\)\\t\"	visualise only SPACEs between TABs.
+
+NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
+      Use exactly one pair of enclosing \\\\( and \\\\).
+
+Used when `blank-style' has `color' as an element, and
+`blank-chars' has `spaces' as an element."
+  :type '(regexp :tag "SPACE Chars")
+  :group 'blank)
+
+
+(defcustom blank-tab-regexp "\\(\t+\\)"
+  "*Specify TAB characters regexp.
+
+If you're using `mule' package, it may exist other characters
+besides \"\\t\" that it should be considered TAB.
+
+Here are some examples:
+
+   \"\\\\(^\\t+\\\\)\"		visualise only leading TABs.
+   \"\\\\(\\t+$\\\\)\"		visualise only trailing TABs.
+   \"\\\\(^\\t+\\\\|\\t+$\\\\)\"	\
+visualise leading and/or trailing TABs.
+   \" \\\\(\\t+\\\\) \"	visualise only TABs between SPACEs.
+
+NOTE: Enclose always by \\\\( and \\\\) the elements to highlight.
+      Use exactly one pair of enclosing \\\\( and \\\\).
+
+Used when `blank-style' has `color' as an element, and
+`blank-chars' has `tabs' as an element."
+  :type '(regexp :tag "TAB Chars")
+  :group 'blank)
+
+
+(defcustom blank-trailing-regexp
+  "\t\\| \\|\xA0\\|\x8A0\\|\x920\\|\xE20\\|\xF20"
+  "*Specify trailing characters regexp.
+
+If you're using `mule' package, it may exist other characters besides:
+
+   \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
+\"\\xF20\"
+
+that it should be considered blank.
+
+NOTE: DOES NOT enclose by \\\\( and \\\\) the elements to highlight.
+      `blank-mode' surrounds this regexp by \"\\\\(\\\\(\" and
+      \"\\\\)+\\\\)$\".
+
+Used when `blank-style' has `color' as an element, and
+`blank-chars' has `trailing' as an element."
+  :type '(regexp :tag "Trailing Chars")
+  :group 'blank)
+
+
+(defcustom blank-space-before-tab-regexp "\\( +\\)\t"
+  "*Specify SPACEs before TAB regexp.
+
+If you're using `mule' package, it may exist other characters besides:
+
+   \" \"  \"\\t\"  \"\\xA0\"  \"\\x8A0\"  \"\\x920\"  \"\\xE20\"  \
+\"\\xF20\"
+
+that it should be considered blank.
+
+Used when `blank-style' has `color' as an element, and
+`blank-chars' has `space-before-tab' as an element."
+  :type '(regexp :tag "SPACEs Before TAB")
+  :group 'blank)
+
+
+(defcustom blank-line-length 80
+  "*Specify length beyond which the line is highlighted.
+
+Used when `blank-style' has `color' as an element, and
+`blank-chars' has `lines' as an element."
+  :type '(integer :tag "Line Length")
+  :group 'blank)
+
+
+;; Hacked from `visible-whitespace-mappings' in visws.el
+(defcustom blank-display-mappings
+  ;; Due to limitations of glyph representation, the char code can not
+  ;; be above ?\x1FFFF.  Probably, this will be fixed after Emacs
+  ;; unicode merging.
+  '(
+    (?\     [?\xB7]       [?.])		; space - centered dot
+    (?\xA0  [?\xA4]       [?_])		; hard space - currency
+    (?\x8A0 [?\x8A4]      [?_])		; hard space - currency
+    (?\x920 [?\x924]      [?_])		; hard space - currency
+    (?\xE20 [?\xE24]      [?_])		; hard space - currency
+    (?\xF20 [?\xF24]      [?_])		; hard space - currency
+    ;; NEWLINE is displayed using the face `blank-newline-face'
+    (?\n    [?$ ?\n])			; end-of-line - dollar sign
+    ;; (?\n    [?\u21B5 ?\n] [?$ ?\n])	; end-of-line - downwards arrow
+    ;; (?\n    [?\xB6 ?\n]   [?$ ?\n])	; end-of-line - pilcrow
+    ;; (?\n    [?\x8AF ?\n]  [?$ ?\n])	; end-of-line - overscore
+    ;; (?\n    [?\x8AC ?\n]  [?$ ?\n])	; end-of-line - negation
+    ;; (?\n    [?\x8B0 ?\n]  [?$ ?\n])	; end-of-line - 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.
+    (?\t    [?\xBB ?\t]   [?\\ ?\t])	; tab - left quote mark
+    )
+  "*Specify an alist of mappings for displaying characters.
+
+Each element has the following form:
+
+   (CHAR VECTOR...)
+
+Where:
+
+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
+`blank-newline-face' variable.  The characters in the vector to be
+displayed will not have applied this face if the character code is
+above #x1FFFF.
+
+Used when `blank-style' has `mark' as an element."
+  :type '(repeat
+	  (list :tag "Character Mapping"
+		(character :tag "Char")
+		(repeat :inline t :tag "Vector List"
+			(vector :tag ""
+				(repeat :inline t
+					:tag "Vector Characters"
+					(character :tag "Char"))))))
+  :group 'blank)
+
+
+(defcustom blank-global-modes t
+  "*Modes for which global `blank-mode' is automagically turned on.
+
+Global `blank-mode' is controlled by the command `global-blank-mode'.
+
+If nil, means no modes have `blank-mode' automatically turned on.
+If t, all modes that support `blank-mode' have it automatically
+turned on.
+If a list, it should be a list of `major-mode' symbol names for
+which `blank-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 `blank-mode' is turned on for buffers in C and C++
+modes only."
+  :type '(choice (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 'blank)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; User commands - Local mode
+
+
+;;;###autoload
+(define-minor-mode blank-mode
+  "Toggle blank minor mode visualisation (bl on modeline).
+
+If ARG is null, toggle blank visualisation.
+If ARG is a number and is greater than zero, turn on
+visualisation; otherwise, turn off visualisation.
+Only useful with a windowing system."
+  :lighter    " bl"
+  :init-value nil
+  :global     nil
+  :group      'blank
+  (cond
+   (noninteractive			; running a batch job
+    (setq blank-mode nil))
+   (blank-mode				; blank-mode on
+    (blank-turn-on))
+   (t					; blank-mode off
+    (blank-turn-off))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; User commands - Global mode
+
+
+(define-minor-mode global-blank-mode
+  "Toggle blank global minor mode visualisation (BL on modeline).
+
+If ARG is null, toggle blank visualisation.
+If ARG is a number and is greater than zero, turn on
+visualisation; otherwise, turn off visualisation.
+Only useful with a windowing system."
+  :lighter    " BL"
+  :init-value nil
+  :global     t
+  :group      'blank
+  (cond
+   (noninteractive			; running a batch job
+    (setq global-blank-mode nil))
+   (global-blank-mode			; global-blank-mode on
+    (save-excursion
+      (if (boundp 'find-file-hook)
+	  (add-hook 'find-file-hook 'blank-turn-on-if-enabled t)
+	(add-hook 'find-file-hooks 'blank-turn-on-if-enabled t))
+      (dolist (buffer (buffer-list))	; adjust all local mode
+	(set-buffer buffer)
+	(unless blank-mode
+	  (blank-turn-on-if-enabled)))))
+   (t					; global-blank-mode off
+    (save-excursion
+      (if (boundp 'find-file-hook)
+	  (remove-hook 'find-file-hook 'blank-turn-on-if-enabled)
+	(remove-hook 'find-file-hooks 'blank-turn-on-if-enabled))
+      (dolist (buffer (buffer-list))	; adjust all local mode
+	(set-buffer buffer)
+	(unless blank-mode
+	  (blank-turn-off)))))))
+
+
+(defun blank-turn-on-if-enabled ()
+  (when (cond
+	 ((eq blank-global-modes t))
+	 ((listp blank-global-modes)
+	  (if (eq (car-safe blank-global-modes) 'not)
+	      (not (memq major-mode (cdr blank-global-modes)))
+	    (memq major-mode blank-global-modes)))
+	 (t nil))
+    (let (inhibit-quit)
+      ;; Don't turn on blank 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 blank mode.
+       (blank-turn-on)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; User commands - Toggle
+
+
+(defconst blank-chars-value-list
+  '(tabs
+    spaces
+    trailing
+    space-before-tab
+    lines
+    newline
+    )
+  "List of valid `blank-chars' value.")
+
+
+(defconst blank-style-value-list
+  '(color
+    mark
+    )
+  "List of valid `blank-style' value.")
+
+
+(defconst blank-toggle-option-alist
+  '((?t . tabs)
+    (?s . spaces)
+    (?r . trailing)
+    (?b . space-before-tab)
+    (?l . lines)
+    (?n . newline)
+    (?c . color)
+    (?m . mark)
+    (?x . blank-chars)
+    (?z . blank-style)
+    )
+  "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 `blank-chars-value-list' and `blank-style-value-list'.")
+
+
+(defvar blank-active-chars nil
+  "Used to save locally `blank-chars' value.")
+(make-variable-buffer-local 'blank-active-chars)
+
+(defvar blank-active-style nil
+  "Used to save locally `blank-style' value.")
+(make-variable-buffer-local 'blank-active-style)
+
+
+;;;###autoload
+(defun blank-toggle-options (arg)
+  "Toggle local `blank-mode' options.
+
+If local blank-mode is off, toggle the option given by ARG and
+turn on local blank-mode.
+
+If local blank-mode is on, toggle the option given by ARG and
+restart local blank-mode.
+
+Interactively, it reads one of the following chars:
+
+  CHAR	MEANING
+   t	toggle TAB visualisation
+   s	toggle SPACE and HARD SPACE visualisation
+   r	toggle trailing blanks visualisation
+   b	toggle SPACEs before TAB visualisation
+   l	toggle \"long lines\" visualisation
+   n	toggle NEWLINE visualisation
+   c	toggle color faces
+   m	toggle visual mark
+   x	restore `blank-chars' value
+   z	restore `blank-style' value
+   ?	display brief help
+
+Non-interactively, ARG should be a symbol or a list of symbol.
+The valid symbols are:
+
+   tabs			toggle TAB visualisation
+   spaces		toggle SPACE and HARD SPACE visualisation
+   trailing		toggle trailing blanks visualisation
+   space-before-tab	toggle SPACEs before TAB visualisation
+   lines		toggle \"long lines\" visualisation
+   newline		toggle NEWLINE visualisation
+   color		toggle color faces
+   mark			toggle visual mark
+   blank-chars		restore `blank-chars' value
+   blank-style		restore `blank-style' value
+
+Only useful with a windowing system."
+  (interactive (blank-interactive-char t))
+  (let ((blank-chars
+	 (blank-toggle-list t arg blank-active-chars blank-chars
+			    'blank-chars blank-chars-value-list))
+	(blank-style
+	 (blank-toggle-list t arg blank-active-style blank-style
+			    'blank-style blank-style-value-list)))
+    (blank-mode 0)
+    (blank-mode 1)))
+
+
+(defvar blank-toggle-chars nil
+  "Used to toggle the global `blank-chars' value.")
+(defvar blank-toggle-style nil
+  "Used to toggle the global `blank-style' value.")
+
+
+;;;###autoload
+(defun global-blank-toggle-options (arg)
+  "Toggle global `blank-mode' options.
+
+If global blank-mode is off, toggle the option given by ARG and
+turn on global blank-mode.
+
+If global blank-mode is on, toggle the option given by ARG and
+restart global blank-mode.
+
+Interactively, it reads one of the following chars:
+
+  CHAR	MEANING
+   t	toggle TAB visualisation
+   s	toggle SPACE and HARD SPACE visualisation
+   r	toggle trailing blanks visualisation
+   b	toggle SPACEs before TAB visualisation
+   l	toggle \"long lines\" visualisation
+   n	toggle NEWLINE visualisation
+   c	toggle color faces
+   m	toggle visual mark
+   x	restore `blank-chars' value
+   z	restore `blank-style' value
+   ?	display brief help
+
+Non-interactively, ARG should be a symbol or a list of symbol.
+The valid symbols are:
+
+   tabs			toggle TAB visualisation
+   spaces		toggle SPACE and HARD SPACE visualisation
+   trailing		toggle trailing blanks visualisation
+   space-before-tab	toggle SPACEs before TAB visualisation
+   lines		toggle \"long lines\" visualisation
+   newline		toggle NEWLINE visualisation
+   color		toggle color faces
+   mark			toggle visual mark
+   blank-chars		restore `blank-chars' value
+   blank-style		restore `blank-style' value
+
+Only useful with a windowing system."
+  (interactive (blank-interactive-char nil))
+  (let ((blank-chars
+	 (blank-toggle-list nil arg blank-toggle-chars blank-chars
+			    'blank-chars blank-chars-value-list))
+	(blank-style
+	 (blank-toggle-list nil arg blank-toggle-style blank-style
+			    'blank-style blank-style-value-list)))
+    (setq blank-toggle-chars blank-chars
+	  blank-toggle-style blank-style)
+    (global-blank-mode 0)
+    (global-blank-mode 1)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Internal functions
+
+
+(defvar blank-font-lock-mode nil
+  "Used to remember whether a buffer had font lock mode on or not.")
+(make-variable-buffer-local 'blank-font-lock-mode)
+
+(defvar blank-font-lock nil
+  "Used to remember whether a buffer initially had font lock on or not.")
+(make-variable-buffer-local 'blank-font-lock)
+
+(defvar blank-font-lock-keywords nil
+  "Used to save locally `font-lock-keywords' value.")
+(make-variable-buffer-local 'blank-font-lock-keywords)
+
+
+(defconst blank-help-text
+  "\
+      blank-mode toggle options:
+
+ []  t - toggle TAB visualisation
+ []  s - toggle SPACE and HARD SPACE visualisation
+ []  r - toggle trailing blanks visualisation
+ []  b - toggle SPACEs before TAB visualisation
+ []  l - toggle \"long lines\" visualisation
+ []  n - toggle NEWLINE visualisation
+
+ []  c - toggle color faces
+ []  m - toggle visual mark
+
+      x - restore `blank-chars' value
+      z - restore `blank-style' value
+
+      ? - display this text\n\n"
+  "Text for blank toggle options.")
+
+
+(defconst blank-help-buffer-name "*Blank Toggle Options*"
+  "The buffer name for blank toggle options.")
+
+
+(defun blank-insert-option-mark (the-list the-value)
+  "Insert the option mark ('X' or ' ') in toggle options buffer."
+  (forward-line 1)
+  (dolist (sym  the-list)
+    (forward-line 1)
+    (forward-char 2)
+    (insert (if (memq sym the-value) "X" " "))))
+
+
+(defun blank-help-on (chars style)
+  "Display the blank toggle options."
+  (unless (get-buffer blank-help-buffer-name)
+    (delete-other-windows)
+    (let ((buffer (get-buffer-create blank-help-buffer-name)))
+      (save-excursion
+	(set-buffer buffer)
+	(erase-buffer)
+	(insert blank-help-text)
+	(goto-char (point-min))
+	(blank-insert-option-mark blank-chars-value-list chars)
+	(blank-insert-option-mark blank-style-value-list style)
+	(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 blank toggle options"))
+	  (set-window-buffer (split-window nil size) buffer))))))
+
+
+(defun blank-help-off ()
+  "Remove the buffer and window of the blank toggle options."
+  (let ((buffer (get-buffer blank-help-buffer-name)))
+    (when buffer
+      (delete-windows-on buffer)
+      (kill-buffer buffer))))
+
+
+(defun blank-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 reads one of the following chars:
+
+  CHAR	MEANING
+   t	toggle TAB visualisation
+   s	toggle SPACE and HARD SPACE visualisation
+   r	toggle trailing blanks visualisation
+   b	toggle SPACEs before TAB visualisation
+   l	toggle \"long lines\" visualisation
+   n	toggle NEWLINE visualisation
+   c	toggle color faces
+   m	toggle visual mark
+   x	restore `blank-chars' value
+   z	restore `blank-style' value
+   ?	display brief help
+
+See also `blank-toggle-option-alist'."
+  (let* ((is-off (not (if local-p blank-mode global-blank-mode)))
+	 (chars  (cond (is-off  blank-chars) ; use default value
+		       (local-p blank-active-chars)
+		       (t       blank-toggle-chars)))
+	 (style  (cond (is-off  blank-style) ; use default value
+		       (local-p blank-active-style)
+		       (t       blank-toggle-style)))
+	 (prompt
+	  (format "Blank 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 blank-toggle-option-alist)))))
+	      ;; while body
+	      (if (eq ch ?\?)
+		  (blank-help-on chars style)
+		(ding)))
+	    (blank-help-off)
+	    (message " "))		; clean echo area
+	;; handler
+	((quit error)
+	 (blank-help-off)
+	 (error (error-message-string data)))))
+    (list sym)))			; return the apropriate symbol
+
+
+(defun blank-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 blank-mode global-blank-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)
+
+
+(defun blank-turn-on ()
+  "Turn on blank visualisation."
+  (setq blank-active-style (if (listp blank-style)
+			       blank-style
+			     (list blank-style)))
+  (setq blank-active-chars (if (listp blank-chars)
+			       blank-chars
+			     (list blank-chars)))
+  (and (memq 'color blank-active-style)
+       (blank-color-on))
+  (and (memq 'mark  blank-active-style)
+       (blank-display-char-on)))
+
+
+(defun blank-turn-off ()
+  "Turn off blank visualisation."
+  (and (memq 'color blank-active-style)
+       (blank-color-off))
+  (and (memq 'mark  blank-active-style)
+       (blank-display-char-off)))
+
+
+(defun blank-color-on ()
+  "Turn on color visualisation."
+  (when blank-active-chars
+    (unless blank-font-lock
+      (setq blank-font-lock t
+	    blank-font-lock-keywords
+	    (copy-sequence font-lock-keywords)))
+    ;; turn off font lock
+    (setq blank-font-lock-mode font-lock-mode)
+    (font-lock-mode 0)
+    ;; add blank-mode color into font lock
+    (when (memq 'spaces blank-active-chars)
+      (font-lock-add-keywords
+       nil
+       (list
+	;; Show SPACEs
+	(list blank-space-regexp  1 blank-space-face  t)
+	;; Show HARD SPACEs
+	(list blank-hspace-regexp 1 blank-hspace-face t))
+       t))
+    (when (memq 'tabs blank-active-chars)
+      (font-lock-add-keywords
+       nil
+       (list
+	;; Show TABs
+	(list blank-tab-regexp 1 blank-tab-face t))
+       t))
+    (when (memq 'trailing blank-active-chars)
+      (font-lock-add-keywords
+       nil
+       (list
+	;; Show trailing blanks
+	(list (concat "\\(\\(" blank-trailing-regexp "\\)+\\)$")
+	      1 blank-trailing-face t))
+       t))
+    (when (memq 'lines blank-active-chars)
+      (font-lock-add-keywords
+       nil
+       (list
+	;; Show "long" lines
+	(list (concat "^\\(.\\{" (int-to-string blank-line-length)
+		      ",\\}\\)$")
+	      1 blank-line-face t))
+       t))
+    (when (memq 'space-before-tab blank-active-chars)
+      (font-lock-add-keywords
+       nil
+       (list
+	;; Show SPACEs before TAB
+	(list blank-space-before-tab-regexp
+	      1 blank-space-before-tab-face t))
+       t))
+    ;; now turn on font lock and highlight blanks
+    (font-lock-mode 1)))
+
+
+(defun blank-color-off ()
+  "Turn off color visualisation."
+  (when blank-active-chars
+    (when blank-font-lock
+      (setq blank-font-lock nil
+	    font-lock-keywords blank-font-lock-keywords))
+    ;; turn off font lock
+    (font-lock-mode 0)
+    ;; restore original font lock state
+    (font-lock-mode blank-font-lock-mode)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Hacked from visws.el (Miles Bader <miles@gnu.org>)
+
+
+(defvar blank-display-table nil
+  "Used to save a local display table.")
+(make-variable-buffer-local 'blank-display-table)
+
+(defvar blank-display-table-was-local nil
+  "Used to remember whether a buffer initially had a local display table or not.")
+(make-variable-buffer-local 'blank-display-table-was-local)
+
+
+(defsubst blank-char-valid-p (char)
+  ;; This check should be improved!!!
+  (or (< char 256)
+      (char-valid-p char)))
+
+
+(defun blank-legal-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)
+		  (blank-char-valid-p (aref vec i))))
+      (< i 0))))
+
+
+(defun blank-display-char-on ()
+  "Turn on character display mapping."
+  (when blank-display-mappings
+    (let (vecs vec)
+      ;; Remember whether a buffer has a local display table.
+      (unless blank-display-table-was-local
+	(setq blank-display-table-was-local t
+	      blank-display-table
+	      (copy-sequence buffer-display-table)))
+      (unless buffer-display-table
+	(setq buffer-display-table (make-display-table)))
+      (dolist (entry blank-display-mappings)
+	(setq vecs (cdr entry))
+	;; Get a displayable mapping.
+	(while (and vecs
+		    (not (blank-legal-display-vector-p (car vecs))))
+	  (setq vecs (cdr vecs)))
+	;; Display a valid mapping.
+	(when vecs
+	  (setq vec (copy-sequence (car vecs)))
+	  (cond
+	   ;; Any char except newline
+	   ((not (eq (car entry) ?\n))
+	    (aset buffer-display-table (car entry) vec))
+	   ;; Newline char - display it
+	   ((memq 'newline blank-active-chars)
+	    ;; Only insert face bits on NEWLINE char mapping to avoid
+	    ;; obstruction of other faces like TABs and (HARD) SPACEs
+	    ;; faces, font-lock faces, etc.
+	    (when (memq 'color blank-active-style)
+	      (dotimes (i (length vec))
+		;; Due to limitations of glyph representation, the char
+		;; code can not be above ?\x1FFFF.  Probably, this will
+		;; be fixed after Emacs unicode merging.
+		(or (eq (aref vec i) ?\n)
+		    (> (aref vec i) #x1FFFF)
+		    (aset vec i (make-glyph-code (aref vec i)
+						 blank-newline-face)))))
+	    ;; Display mapping
+	    (aset buffer-display-table (car entry) vec))
+	   ;; Newline char - don't display it
+	   (t
+	    ;; Do nothing
+	    )))))))
+
+
+(defun blank-display-char-off ()
+  "Turn off character display mapping."
+  (and blank-display-mappings
+       blank-display-table-was-local
+       (setq blank-display-table-was-local nil
+	     buffer-display-table          blank-display-table)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(provide 'blank-mode)
+
+
+(run-hooks 'blank-load-hook)
+
+
+;;; blank-mode.el ends here