diff lisp/modes/whitespace-mode.el @ 24:4103f0995bd7 r19-15b95

Import from CVS: tag r19-15b95
author cvs
date Mon, 13 Aug 2007 08:51:03 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/modes/whitespace-mode.el	Mon Aug 13 08:51:03 2007 +0200
@@ -0,0 +1,565 @@
+;;; whitespace-mode.el -- minor mode for making whitespace visible
+
+;; Copyright (C) 1994, 1995, 1996 Heiko Muenkel
+
+;; Author: Heiko Muenkel <muenkel@tnt.uni-hannover.de>
+;; Keywords: modes, extensions
+
+;; This file is part of XEmacs.
+
+;;  XEmacs 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 2, or (at your
+;;  option) any later version.
+
+;;  XEmacs 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 XEmacs; if not, write to the Free Software
+;;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA.
+
+;;; Synched up with: FSF 19.34.
+ 
+;;; Commentary:
+
+;; $Id: whitespace-mode.el,v 1.2 1997/02/22 22:07:27 steve Exp $
+;; Description:
+;;
+;;	This is a minor mode, which highlights whitespaces (blanks and
+;;	tabs) with different faces, so that it is easier to
+;;	distinguish between them.  
+;;	Toggle the mode with: M-x whitespace-mode 
+;;     or with: M-x whitespace-incremental-mode
+;;	The second one should be used in big files.
+;;
+;;	If you want to know how the whitespaces are highlighted then
+;;	type: M-x whitespace-show-faces
+;;
+;;	There are 2 hook variables `whitespace-incremental-mode-hook'
+;;	and `whitespace-mode-hook' to customize the mode.
+;;
+;;	Look at the variable `whitespace-chars', if you only want to
+;;	highlight tabs or blanks and not both.
+;;
+;;	Set `whitespace-install-toolbar-icon' to t, if you want a
+;;	toolbar icon for this mode.
+;;
+;;	Set `whitespace-install-submenu' to t, if you want a submenu
+;;     for this mode. Sorry, at the moment there is no menu for the
+;;	Emacs 19. 
+;;
+;;	Thanks to Mike Scheidler for the toolbar icon code.
+;; 
+;; Installation:
+;;   
+;;     Put the files whitespace-mode.el and adapt.el in one of your
+;; 	load-path directories and the following lines (without the
+;; 	comment signs) in your .emacs (adapt.el is already in the
+;;	XEmacs 19.12).
+;;
+;;     (autoload 'whitespace-mode "whitespace-mode" 
+;;       "Toggle whitespace mode.
+;;	With arg, turn whitespace mode on iff arg is positive.
+;;	In whitespace mode the different whitespaces (tab, blank return)
+;;	are highlighted with different faces. The faces are:
+;;	`whitespace-blank-face', `whitespace-tab-face' and 
+;;	`whitespace-return-face'."
+;;	t)
+;;
+;;     (autoload 'whitespace-incremental-mode "whitespace-mode" 
+;;	  "Toggle whitespace incremental mode.
+;;     With arg, turn whitespace incremental mode on iff arg is positive.
+;;	In whitespace incremental mode the different whitespaces (tab and 
+;;	blank) are highlighted with different faces. The faces are:
+;;	`whitespace-blank-face' and `whitespace-tab-face'.
+;;	Use the command `whitespace-show-faces' to show their values.
+;;	In this mode only these tabs and blanks are highlighted, which are in 
+;;	the region from (point) - (window-heigh) to (point) + (window-heigh)."
+
+;;; Code:
+
+(provide 'whitespace-mode)
+(require 'adapt)
+
+;;; variables:
+
+(defvar whitespace-chars 'tabs-and-blanks
+  "*Determines, which whitespaces are highlighted.
+Valid values are:
+'tabs-and-blanks => tabs and blanks are highlighted;
+'tabs            => only tabs are highlighted;
+'blanks          => only blanks are highlighted;.
+
+Changing this variable during the whitespace-*-mode is active could lead
+to wrong highlighted whitespaces.")
+
+(make-variable-buffer-local 'whitespace-chars)
+
+(defvar whitespace-mode-hook nil
+  "*Run after the `whitespace-mode' is switched on.")
+
+(defvar whitespace-incremental-mode-hook nil
+  "*Run after the `whitespace-incremental-mode' is switched on.")
+
+
+(if (adapt-xemacsp)
+(progn
+
+(defvar whitespace-install-toolbar-icon nil
+  "Set it to t, if a toolbar icon should be installed during loading this file.
+The icon calls the function 'whitespace-toolbar-function'.")
+
+(defvar whitespace-install-submenu nil
+  "Set it to t, if a submenu should be installed during loading this file.")
+
+))
+
+
+(defvar whitespace-toolbar-function 'whitespace-incremental-mode
+  "*The toolbar icon for the whitespace mode calls this function.
+Valid values are: 'whitespace--mode and 'whitespace-incremental-mode.")
+
+(defvar whitespace-blank-and-tab-search-string "\\( \\)\\|\\(\t\\)"
+  "The regexp used to search for tabs and blanks.")
+
+(defvar whitespace-tab-search-string "\t"
+  "The search string used to find tabs.")
+
+(defvar whitespace-blank-search-string " "
+  "The search string used to find blanks.")
+
+;;; Defining faces
+(if (facep 'whitespace-blank-face)
+    nil
+  (make-face 'whitespace-blank-face)
+  (set-face-background 'whitespace-blank-face "LightBlue1"))
+
+(if (facep 'whitespace-tab-face)
+    nil
+  (make-face 'whitespace-tab-face)
+  (set-face-background 'whitespace-tab-face "yellow")
+  (set-face-underline-p 'whitespace-tab-face t))
+
+(defun whitespace-show-faces ()
+  "Shows the faces used by the `whitespace-mode'."
+  (interactive)
+  (save-excursion
+    (let ((actual-buffer-name (buffer-name (current-buffer)))
+	  (actual-whitespace-chars whitespace-chars)
+	  (whitespace-mode-active (or whitespace-mode 
+				      whitespace-incremental-mode))
+	  (buffer (get-buffer-create "*Help*")))
+      (set-buffer buffer)
+      (setq whitespace-chars actual-whitespace-chars)
+      (delete-region (point-min) (point-max))
+      (insert "In the whitespace minor mode\n"
+	      " this \" ")
+      (whitespace-highlight-region (1- (point)) (point))
+      (insert "\" is a blank, highlighted with `whitespace-blank-face' and\n"
+	      " this \"\t")
+      (whitespace-highlight-region (1- (point)) (point))
+      (insert "\" is a tab,  highlighted with `whitespace-tab-face'.")
+      
+      (newline 2)
+      (if (eq whitespace-chars 'blanks)
+	  (insert 
+	   "The highlighting of tabs is switched off.\n")
+	(if (eq whitespace-chars 'tabs)
+	    (insert
+	     "The highlighting of blanks is switched off.\n")))
+      (newline)
+      (if whitespace-mode-active
+	  (insert "A whitespace minor mode is active in the buffer\n  "
+		  actual-buffer-name
+		  ".\n")
+	(insert "No whitespace minor mode is active in the buffer\n  "
+		actual-buffer-name
+		".\n"))
+      (show-temp-buffer-in-current-frame buffer)
+      )))
+
+;;;
+(defun whitespace-highlight-chars-in-region (char-string from to face)
+  "Highlights the CHAR-STRING in the region from FROM to TO with the FACE."
+  (while (search-forward char-string end t)
+    (let ((extent))
+      (cond ((match-beginning 0)
+	     (setq extent (make-extent (match-beginning 0) (match-end 0)))
+	     (set-extent-face extent face)
+	     ))
+      (set-extent-property extent 'start-open t)
+      (set-extent-property extent 'end-open t)
+      )))
+
+(defun whitespace-highlight-region (from to)
+  "Highlights the whitespaces in the region from FROM to TO."
+  (let ((start (min from to))
+	(end (max from to)))
+    (save-excursion
+      ;;    (message "Highlighting tabs and blanks...")
+      (goto-char start)
+      (cond ((eq whitespace-chars 'tabs-and-blanks)
+	     (while (search-forward-regexp 
+		     whitespace-blank-and-tab-search-string end t)
+	       (let ((extent))
+		 (cond ((match-beginning 1) ; blanks ?
+			(setq extent (make-extent (match-beginning 1) 
+						  (match-end 1)))
+			(set-extent-face extent 'whitespace-blank-face)
+			)
+		       ((match-beginning 2) ; tabs ?
+			(setq extent (make-extent (match-beginning 2) 
+						  (match-end 2)))
+			(set-extent-face extent 'whitespace-tab-face)
+			)
+		       )
+		 (set-extent-property extent 'start-open t)
+		 (set-extent-property extent 'end-open t)
+		 )))
+	    ((eq whitespace-chars 'tabs)
+	     (whitespace-highlight-chars-in-region whitespace-tab-search-string 
+						   from 
+						   to
+						   'whitespace-tab-face))
+	    ((eq whitespace-chars 'blanks)
+	     (whitespace-highlight-chars-in-region 
+	      whitespace-blank-search-string 
+	      from 
+	      to
+	      'whitespace-blank-face))
+	    (t (error "ERROR: Bad value of whitespace-highlight-char")))
+      ;;    (message "")
+      )))
+
+(defun whitespace-highlight-buffer ()
+  "Highlights the whitespaces in the current buffer."
+  (whitespace-highlight-region (point-min) (point-max))
+)
+
+(defsubst whitespace-find-next-highlighted-region (from to)
+  "Returns nil or the next highlighted region."
+  (map-extents '(lambda (extent dummy)
+		 (if (extent-property extent 'whitespace-highlighted-region)
+		     extent))
+	       nil
+	       from
+	       to))
+
+(defun whitespace-incremental-highlight (from to)
+  "Highligthts the region from FROM to TO incremental."
+  (save-excursion
+    (goto-char from)
+    (let ((extent (extent-at (point) nil 'whitespace-highlighted-region))
+	  (next-extent nil)
+	  (start nil))
+      (while (< (point) to)
+	(if extent
+	    (goto-char (extent-end-position extent)))
+	(if (< (point) to)
+	    (progn
+	      (setq start (point))
+	      
+	      (setq next-extent (whitespace-find-next-highlighted-region 
+				 start
+				 to))
+	      (if extent
+		  (if next-extent
+		      (progn
+			(set-extent-endpoints extent 
+					      (extent-start-position extent)
+					      (extent-end-position next-extent)
+					      )
+			(whitespace-highlight-region start
+						     (1-
+						      (extent-start-position
+						       next-extent)))
+			(delete-extent next-extent))
+		    (set-extent-endpoints extent
+					  (extent-start-position extent)
+					  to)
+		    (whitespace-highlight-region start to))
+		(if next-extent
+		    (progn
+		      (setq extent next-extent)
+		      (whitespace-highlight-region start 
+						   (1- (extent-start-position
+							next-extent)))
+		      (set-extent-endpoints extent
+					    start
+					    (extent-end-position next-extent)))
+		  (setq extent (make-extent start to))
+		  (set-extent-property extent 'whitespace-highlighted-region t)
+		  (whitespace-highlight-region start to)))
+	      ))))))
+
+
+(defun whitespace-highlight-window ()
+  "Highlights the whitespaces in the current window."
+  (whitespace-incremental-highlight (save-excursion
+				      (forward-line (- (window-height)))
+				      (point))
+				    (save-excursion
+				      (forward-line (window-height))
+				      (point))))
+
+(defun whitespace-dehighlight-region (start end)
+  "Dehighlights the whitespaces in the region from START to END."
+  (map-extents '(lambda (extent dummy)
+		  (if (or (eq (extent-face extent) 'whitespace-blank-face)
+			  (eq (extent-face extent) 'whitespace-tab-face)
+			  (extent-property extent 
+					   'whitespace-highlighted-region))
+		      (progn
+			(delete-extent extent)
+			nil)))
+	       nil
+	       start
+	       end
+	       )
+  )
+
+(defun whitespace-dehighlight-buffer ()
+  "Dehighlights the whitespaces in the current buffer."
+  (whitespace-dehighlight-region (point-min) (point-max))
+  )
+
+(defun whitespace-highlight-after-change-function (beg end old-len)
+  "Called, when any modification is made to buffer text.  Highlights
+the whitespaces (blanks and tabs) in the region from BEG to
+END. OLD-LEN isn't used, but provided from the after-change hook."
+  (if (or (eq beg end)
+	  (null whitespace-mode))
+      nil
+    (whitespace-dehighlight-region beg end)
+    (whitespace-highlight-region beg end)))
+
+(defvar whitespace-mode nil
+  "Non-nil, if the `whitespace-mode' is active.")
+
+(make-variable-buffer-local 'whitespace-mode)
+
+(defun whitespace-mode (&optional arg)
+  "Toggle whitespace mode.
+With arg, turn whitespace mode on iff arg is positive.
+In whitespace mode the different whitespaces (tab and blank)
+are highlighted with different faces. The faces are:
+`whitespace-blank-face' and `whitespace-tab-face'.
+Use the command `whitespace-show-faces' to show their values."
+  (interactive "P")
+  (setq whitespace-mode
+	(if (null arg) (not whitespace-mode)
+	  (> (prefix-numeric-value arg) 0)))
+  (if (and whitespace-mode whitespace-incremental-mode)
+      (progn
+	(whitespace-incremental-highlight (point-min) (point-max))
+	(setq whitespace-incremental-mode nil)
+	(remove-hook 'post-command-hook 'whitespace-highlight-window)
+	(run-hooks 'whitespace-mode-hook)
+	)
+    (setq whitespace-incremental-mode nil)
+    (remove-hook 'post-command-hook 'whitespace-highlight-window)
+    (redraw-modeline) ;(force-mode-line-update)
+    (if whitespace-mode
+	(progn
+	  (whitespace-highlight-buffer)
+	  (make-local-variable 'after-change-functions)
+	  (add-hook 'after-change-functions 
+		    'whitespace-highlight-after-change-function)
+	  (run-hooks 'whitespace-mode-hook))
+      (whitespace-dehighlight-buffer)
+      (remove-hook 'after-change-functions 
+		   'whitespace-highlight-after-change-function)
+      (remove-hook 'post-command-hook 'whitespace-highlight-window)
+      )))
+
+(defvar whitespace-incremental-mode nil
+  "Non-nil, if the `whitespace-incremental-mode' is active.")
+
+(make-variable-buffer-local 'whitespace-incremental-mode)
+
+(defun whitespace-incremental-mode (&optional arg)
+  "Toggle whitespace incremental mode.
+With arg, turn whitespace incremental mode on iff arg is positive.
+In whitespace incremental mode the different whitespaces (tab and blank)
+are highlighted with different faces. The faces are:
+`whitespace-blank-face' and `whitespace-tab-face'.
+Use the command `whitespace-show-faces' to show their values.
+In this mode only these tabs and blanks are highlighted, which are in 
+the region from (point) - (window-heigh) to (point) + (window-heigh)."
+  (interactive "P")
+  (setq whitespace-incremental-mode
+	(if (null arg) (not whitespace-incremental-mode)
+	  (> (prefix-numeric-value arg) 0)))
+  (if (and whitespace-mode whitespace-incremental-mode)
+	(set-extent-property (make-extent (point-min) (point-max))
+			     'whitespace-highlighted-region
+			     t))
+  (setq whitespace-mode nil)
+  (redraw-modeline) ;(force-mode-line-update)
+  ;(set-buffer-modified-p (buffer-modified-p)) ;No-op, but updates mode line.
+  (if whitespace-incremental-mode
+      (progn
+	(whitespace-highlight-window)
+	(make-local-variable 'post-command-hook)
+	(add-hook 'post-command-hook 'whitespace-highlight-window)
+	(make-local-variable 'after-change-functions)
+	(add-hook 'after-change-functions 
+		  'whitespace-highlight-after-change-function)
+	(run-hooks 'whitespace-incremental-mode-hook))
+    (whitespace-dehighlight-buffer)
+    (remove-hook 'after-change-functions 
+		 'whitespace-highlight-after-change-function)
+    (remove-hook 'post-command-hook 'whitespace-highlight-window)
+    ))
+
+
+;;; Add whitespace-mode and whitespace-incremental-mode to the minor-mode-alist
+
+(or (assq 'whitespace-mode minor-mode-alist)
+    (setq minor-mode-alist
+	  (cons '(whitespace-mode " WSP") minor-mode-alist)))
+
+(or (assq 'whitespace-incremental-mode minor-mode-alist)
+    (setq minor-mode-alist
+	  (cons '(whitespace-incremental-mode " WSPI") minor-mode-alist)))
+
+
+;;; Menu for the whitespace mode
+
+(defun whitespace-set-whitespace-chars (new-whitespace-chars)
+  "Sets the variable `whitespace-chars' and activates the change."
+  (interactive (list (read (completing-read "Whitespaces to highlight: "
+					    '(("tabs-and-blanks")
+					      ("tabs")
+					      ("blanks"))
+					    nil
+					    t
+					    (symbol-name 'whitespace-chars)))))
+  (if (eq whitespace-chars new-whitespace-chars)
+      nil ; nothing to do
+    (setq whitespace-chars new-whitespace-chars)
+    (setq-default whitespace-chars new-whitespace-chars)
+    (cond (whitespace-mode (whitespace-mode) 
+			   (whitespace-mode))
+	  (whitespace-incremental-mode (whitespace-incremental-mode)
+				       (whitespace-incremental-mode))
+	  )))
+
+(defvar whitespace-menu nil
+  "A menu for the whitespace minor mode.")
+  
+(setq whitespace-menu
+      '("Whitespace Menu"
+	["Highlight Whitespaces" 
+	 whitespace-mode 
+	 :style toggle 
+	 :selected whitespace-mode]
+	["Incremental Highlighting"
+	 whitespace-incremental-mode
+	 :style toggle
+	 :selected whitespace-incremental-mode
+	 ]
+	"---"
+	["Show Whitespace Faces" whitespace-show-faces t]
+	"---"
+	["Highlight Tabs & Blanks" 
+	 (whitespace-set-whitespace-chars 'tabs-and-blanks)
+	 :style radio
+	 :selected (eq whitespace-chars 'tabs-and-blanks)]
+	["Highlight Only Tabs"
+	 (whitespace-set-whitespace-chars 'tabs)
+	 :style radio
+	 :selected (eq whitespace-chars 'tabs)]
+	["Highlight Only Blanks"
+	 (whitespace-set-whitespace-chars 'blanks)
+	 :style radio
+	 :selected (eq whitespace-chars 'blanks)]
+	))
+
+(if (and (boundp 'whitespace-install-submenu) whitespace-install-submenu)
+    (add-submenu '("Apps") whitespace-menu))
+
+;;; Toolbar icon for the XEmacs
+
+(if (featurep 'toolbar)
+
+(defvar toolbar-wspace-icon
+  (toolbar-make-button-list
+   "/* XPM */
+static char * whitespace[] = {
+\"28 28 4 1\",
+\" 	c Gray75 s backgroundToolBarColor\",
+\".	c black\",
+\"X	c Gray60\",
+\"o	c white\",
+\"                            \",
+\"                            \",
+\"                            \",
+\"                            \",
+\"         ..      .          \",
+\"       XXX.XXXXXX   .       \",
+\"       Xoo.oooooXX  .       \",
+\" .. .. ..o.o..oo..X...  ..  \",
+\"  .  . X.o..o.ooX. X.  .  . \",
+\"  .  . .oo.oo.ooX.XX.  .... \",
+\"   ... .oo.oo.ooo.oo.  .    \",
+\"   .  .Xoo.oo.ooo.oo.  .  . \",
+\"   .  .Xo...o..o...o..  ..  \",
+\"       XooooooooooooX       \",
+\"       XooooooooooooX       \",
+\" .... ....ooo...ooo...  ..  \",
+\" .  .  .oo.o.oo.oo.oX. .  . \",
+\"  .    .oo.ooo..oo.oX  .... \",
+\"   ..  .oo.o..o.oo.oX  .    \",
+\" .  .  .oo.o.oo.oo.oX. .  . \",
+\" ....  ...oo.....oo..   ..  \",
+\"       .ooooooooooooX       \",
+\"       .XXXXXXXXXXXXX       \",
+\"       .                    \",
+\"      ...                   \",
+\"                            \",
+\"                            \",
+\"                            \"
+};")
+  "A whitespace icon.")
+)
+
+(defun whitespace-toolbar-function ()
+  "Calls the function determined by `whitespace-toolbar-function'."
+  (interactive)
+  (call-interactively whitespace-toolbar-function))
+
+(if (and (adapt-xemacsp)
+	 whitespace-install-toolbar-icon
+	 (featurep 'toolbar) 
+	 (eq (device-type (selected-device)) 'x))
+    (add-spec-list-to-specifier 
+     default-toolbar
+     '((global 
+	(nil
+	 [toolbar-file-icon     find-file       t       "Open a file"   ]
+	 [toolbar-folder-icon   dired           t       "View directory"]
+	 [toolbar-disk-icon     save-buffer     t       "Save buffer"   ]
+	 [toolbar-printer-icon  print-buffer    t       "Print buffer"  ]
+	 [toolbar-cut-icon      x-kill-primary-selection   t "Kill region"]
+	 [toolbar-copy-icon     x-copy-primary-selection   t "Copy region"]
+	 [toolbar-paste-icon    
+	  x-yank-clipboard-selection t "Paste from clipboard"]
+	 [toolbar-undo-icon     undo            t       "Undo edit"     ]
+	 [toolbar-replace-icon  query-replace   t       "Replace text"  ]
+	 [toolbar-wspace-icon  
+	  whitespace-toolbar-function t "Toggle whitespace mode"]
+	 nil
+	 [toolbar-compile-icon  toolbar-compile t       "Compile"       ]
+	 [toolbar-debug-icon    toolbar-debug   t       "Debug"         ]
+	 [toolbar-spell-icon    toolbar-ispell  t       "Spellcheck"    ]
+	 [toolbar-mail-icon     toolbar-mail    t       "Mail"          ]
+	 [toolbar-news-icon     toolbar-news    t       "News"          ]
+	 [toolbar-info-icon     toolbar-info    t       "Information"   ]
+	 )))))
+
+;;; whitespace-mode.el ends here