ERC: Sync version 5.3, release candidate 1.
[bpt/emacs.git] / lisp / whitespace.el
CommitLineData
e8af40ee 1;;; whitespace.el --- warn about and clean bogus whitespaces in the file
acc975b1 2
c90f2757 3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
409cc4a3 4;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
acc975b1 5
7f565d87 6;; Author: Rajesh Vaidheeswarran <rv@gnu.org>
acc975b1
DL
7;; Keywords: convenience
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
b4aa6026 13;; the Free Software Foundation; either version 3, or (at your option)
acc975b1
DL
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
acc975b1
DL
25
26;;; Commentary:
37a23b5d
RV
27;;
28;; URL: http://www.dsmit.com/lisp/
29;;
07089c84
SM
30;; The whitespace library is intended to find and help fix five different types
31;; of whitespace problems that commonly exist in source code.
37a23b5d 32;;
07089c84
SM
33;; 1. Leading space (empty lines at the top of a file).
34;; 2. Trailing space (empty lines at the end of a file).
35;; 3. Indentation space (8 or more spaces at beginning of line, that should be
c98ddbe5 36;; replaced with TABS).
07089c84
SM
37;; 4. Spaces followed by a TAB. (Almost always, we never want that).
38;; 5. Spaces or TABS at the end of a line.
37a23b5d 39;;
07089c84 40;; Whitespace errors are reported in a buffer, and on the modeline.
37a23b5d 41;;
07089c84
SM
42;; Modeline will show a W:<x>!<y> to denote a particular type of whitespace,
43;; where `x' and `y' can be one (or more) of:
37a23b5d 44;;
07089c84
SM
45;; e - End-of-Line whitespace.
46;; i - Indentation whitespace.
47;; l - Leading whitespace.
48;; s - Space followed by Tab.
49;; t - Trailing whitespace.
37a23b5d 50;;
07089c84
SM
51;; If any of the whitespace checks is turned off, the modeline will display a
52;; !<y>.
37a23b5d 53;;
07089c84
SM
54;; (since (3) is the most controversial one, here is the rationale: Most
55;; terminal drivers and printer drivers have TAB configured or even
56;; hardcoded to be 8 spaces. (Some of them allow configuration, but almost
57;; always they default to 8.)
37a23b5d 58;;
07089c84
SM
59;; Changing `tab-width' to other than 8 and editing will cause your code to
60;; look different from within Emacs, and say, if you cat it or more it, or
61;; even print it.
37a23b5d 62;;
07089c84
SM
63;; Almost all the popular programming modes let you define an offset (like
64;; c-basic-offset or perl-indent-level) to configure the offset, so you
65;; should never have to set your `tab-width' to be other than 8 in all
66;; these modes. In fact, with an indent level of say, 4, 2 TABS will cause
67;; Emacs to replace your 8 spaces with one \t (try it). If vi users in
68;; your office complain, tell them to use vim, which distinguishes between
69;; tabstop and shiftwidth (vi equivalent of our offsets), and also ask them
70;; to set smarttab.)
37a23b5d 71;;
07089c84
SM
72;; All the above have caused (and will cause) unwanted codeline integration and
73;; merge problems.
37a23b5d 74;;
07089c84
SM
75;; whitespace.el will complain if it detects whitespaces on opening a file, and
76;; warn you on closing a file also (in case you had inserted any
77;; whitespaces during the process of your editing).
37a23b5d 78;;
acc975b1 79;; Exported functions:
37a23b5d 80;;
acc975b1
DL
81;; `whitespace-buffer' - To check the current buffer for whitespace problems.
82;; `whitespace-cleanup' - To cleanup all whitespaces in the current buffer.
24b72a45
RS
83;; `whitespace-region' - To check between point and mark for whitespace
84;; problems.
85;; `whitespace-cleanup-region' - To cleanup all whitespaces between point
86;; and mark in the current buffer.
acc975b1
DL
87
88;;; Code:
89
7a15a271 90(defvar whitespace-version "3.5" "Version of the whitespace library.")
acc975b1 91
24b72a45
RS
92(defvar whitespace-all-buffer-files nil
93 "An associated list of buffers and files checked for whitespace cleanliness.
acc975b1 94
24b72a45
RS
95This is to enable periodic checking of whitespace cleanliness in the files
96visited by the buffers.")
acc975b1 97
24b72a45
RS
98(defvar whitespace-rescan-timer nil
99 "Timer object used to rescan the files in buffers that have been modified.")
acc975b1 100
dd24f431
GM
101;; Tell Emacs about this new kind of minor mode
102(defvar whitespace-mode nil
103 "Non-nil when Whitespace mode (a minor mode) is enabled.")
104(make-variable-buffer-local 'whitespace-mode)
dd24f431
GM
105
106(defvar whitespace-mode-line nil
107 "String to display in the mode line for Whitespace mode.")
108(make-variable-buffer-local 'whitespace-mode-line)
dd24f431 109
a3db02ad 110(defvar whitespace-check-buffer-leading nil
7f34d6d4 111 "Test leading whitespace for file in current buffer if t.")
a3db02ad 112(make-variable-buffer-local 'whitespace-check-buffer-leading)
be1320bd 113;;;###autoload(put 'whitespace-check-buffer-leading 'safe-local-variable 'booleanp)
a3db02ad
RV
114
115(defvar whitespace-check-buffer-trailing nil
7f34d6d4 116 "Test trailing whitespace for file in current buffer if t.")
a3db02ad 117(make-variable-buffer-local 'whitespace-check-buffer-trailing)
be1320bd 118;;;###autoload(put 'whitespace-check-buffer-trailing 'safe-local-variable 'booleanp)
a3db02ad
RV
119
120(defvar whitespace-check-buffer-indent nil
7f34d6d4 121 "Test indentation whitespace for file in current buffer if t.")
a3db02ad 122(make-variable-buffer-local 'whitespace-check-buffer-indent)
be1320bd 123;;;###autoload(put 'whitespace-check-buffer-indent 'safe-local-variable 'booleanp)
a3db02ad
RV
124
125(defvar whitespace-check-buffer-spacetab nil
7f34d6d4 126 "Test Space-followed-by-TABS whitespace for file in current buffer if t.")
a3db02ad 127(make-variable-buffer-local 'whitespace-check-buffer-spacetab)
be1320bd 128;;;###autoload(put 'whitespace-check-buffer-spacetab 'safe-local-variable 'booleanp)
a3db02ad
RV
129
130(defvar whitespace-check-buffer-ateol nil
7f34d6d4 131 "Test end-of-line whitespace for file in current buffer if t.")
a3db02ad 132(make-variable-buffer-local 'whitespace-check-buffer-ateol)
be1320bd 133;;;###autoload(put 'whitespace-check-buffer-ateol 'safe-local-variable 'booleanp)
a3db02ad 134
5dc2e846 135(defvar whitespace-highlighted-space nil
7f34d6d4 136 "The variable to store the extent to highlight.")
5dc2e846 137(make-variable-buffer-local 'whitespace-highlighted-space)
5dc2e846 138
9d8f0a3c
RS
139(defalias 'whitespace-make-overlay
140 (if (featurep 'xemacs) 'make-extent 'make-overlay))
141(defalias 'whitespace-overlay-put
142 (if (featurep 'xemacs) 'set-extent-property 'overlay-put))
143(defalias 'whitespace-delete-overlay
144 (if (featurep 'xemacs) 'delete-extent 'delete-overlay))
145(defalias 'whitespace-overlay-start
146 (if (featurep 'xemacs) 'extent-start 'overlay-start))
147(defalias 'whitespace-overlay-end
148 (if (featurep 'xemacs) 'extent-end 'overlay-end))
149(defalias 'whitespace-mode-line-update
150 (if (featurep 'xemacs) 'redraw-modeline 'force-mode-line-update))
151
fc333790
DL
152(defgroup whitespace nil
153 "Check for and fix five different types of whitespaces in source code."
154 :version "21.1"
37a23b5d 155 :link '(emacs-commentary-link "whitespace.el")
9d8f0a3c
RS
156 ;; Since XEmacs doesn't have a 'convenience group, use the next best group
157 ;; which is 'editing?
158 :group (if (featurep 'xemacs) 'editing 'convenience))
acc975b1 159
18d51459 160(defcustom whitespace-check-leading-whitespace t
7f34d6d4 161 "Flag to check leading whitespace. This is the global for the system.
6b588eb7 162It can be overridden by setting a buffer local variable
7f34d6d4 163`whitespace-check-buffer-leading'."
18d51459
RS
164 :type 'boolean
165 :group 'whitespace)
166
167(defcustom whitespace-check-trailing-whitespace t
7f34d6d4 168 "Flag to check trailing whitespace. This is the global for the system.
6b588eb7 169It can be overridden by setting a buffer local variable
7f34d6d4 170`whitespace-check-buffer-trailing'."
18d51459
RS
171 :type 'boolean
172 :group 'whitespace)
173
174(defcustom whitespace-check-spacetab-whitespace t
7f34d6d4 175 "Flag to check space followed by a TAB. This is the global for the system.
6b588eb7 176It can be overridden by setting a buffer local variable
7f34d6d4 177`whitespace-check-buffer-spacetab'."
18d51459
RS
178 :type 'boolean
179 :group 'whitespace)
180
5dc2e846 181(defcustom whitespace-spacetab-regexp "[ ]+\t"
113fa448 182 "Regexp to match one or more spaces followed by a TAB."
fc333790 183 :type 'regexp
24b72a45 184 :group 'whitespace)
acc975b1 185
1f8437c4 186(defcustom whitespace-check-indent-whitespace indent-tabs-mode
7f34d6d4 187 "Flag to check indentation whitespace. This is the global for the system.
6b588eb7 188It can be overridden by setting a buffer local variable
7f34d6d4 189`whitespace-check-buffer-indent'."
18d51459
RS
190 :type 'boolean
191 :group 'whitespace)
192
113fa448
EZ
193(defcustom whitespace-indent-regexp "^\t*\\( \\)+"
194 "Regexp to match multiples of eight spaces near line beginnings.
195The default value ignores leading TABs."
fc333790 196 :type 'regexp
24b72a45
RS
197 :group 'whitespace)
198
18d51459 199(defcustom whitespace-check-ateol-whitespace t
7f34d6d4 200 "Flag to check end-of-line whitespace. This is the global for the system.
6b588eb7 201It can be overridden by setting a buffer local variable
7f34d6d4 202`whitespace-check-buffer-ateol'."
18d51459
RS
203 :type 'boolean
204 :group 'whitespace)
205
5dc2e846 206(defcustom whitespace-ateol-regexp "[ \t]+$"
113fa448 207 "Regexp to match one or more TABs or spaces at line ends."
fc333790 208 :type 'regexp
24b72a45
RS
209 :group 'whitespace)
210
211(defcustom whitespace-errbuf "*Whitespace Errors*"
fc333790 212 "The name of the buffer where whitespace related messages will be logged."
24b72a45
RS
213 :type 'string
214 :group 'whitespace)
215
c98ddbe5
RV
216(defcustom whitespace-clean-msg "clean."
217 "If non-nil, this message will be displayed after a whitespace check
218determines a file to be clean."
219 :type 'string
220 :group 'whitespace)
221
1f8437c4 222(defcustom whitespace-abort-on-error nil
7f34d6d4
JB
223 "While writing a file, abort if the file is unclean.
224If `whitespace-auto-cleanup' is set, that takes precedence over
225this variable."
1f8437c4
RV
226 :type 'boolean
227 :group 'whitespace)
228
24b72a45
RS
229(defcustom whitespace-auto-cleanup nil
230 "Cleanup a buffer automatically on finding it whitespace unclean."
acc975b1
DL
231 :type 'boolean
232 :group 'whitespace)
233
234(defcustom whitespace-silent nil
24b72a45 235 "All whitespace errors will be shown only in the modeline when t.
acc975b1
DL
236
237Note that setting this may cause all whitespaces introduced in a file to go
238unnoticed when the buffer is killed, unless the user visits the `*Whitespace
24b72a45 239Errors*' buffer before opening (or closing) another file."
acc975b1
DL
240 :type 'boolean
241 :group 'whitespace)
242
243(defcustom whitespace-modes '(ada-mode asm-mode autoconf-mode awk-mode
18d51459
RS
244 c-mode c++-mode cc-mode
245 change-log-mode cperl-mode
acc975b1
DL
246 electric-nroff-mode emacs-lisp-mode
247 f90-mode fortran-mode html-mode
248 html3-mode java-mode jde-mode
249 ksh-mode latex-mode LaTeX-mode
250 lisp-mode m4-mode makefile-mode
251 modula-2-mode nroff-mode objc-mode
252 pascal-mode perl-mode prolog-mode
253 python-mode scheme-mode sgml-mode
18d51459
RS
254 sh-mode shell-script-mode simula-mode
255 tcl-mode tex-mode texinfo-mode
256 vrml-mode xml-mode)
acc975b1 257
7f34d6d4 258 "Major modes in which we turn on whitespace checking.
acc975b1 259
fc333790 260These are mostly programming and documentation modes. But you may add other
24b72a45
RS
261modes that you want whitespaces checked in by adding something like the
262following to your `.emacs':
acc975b1 263
24b72a45
RS
264\(setq whitespace-modes (cons 'my-mode (cons 'my-other-mode
265 whitespace-modes))\)
acc975b1 266
24b72a45 267Or, alternately, you can use the Emacs `customize' command to set this."
fc333790 268 :type '(repeat symbol)
24b72a45 269 :group 'whitespace)
acc975b1 270
7f565d87 271(defcustom whitespace-rescan-timer-time 600
24b72a45
RS
272 "Period in seconds to rescan modified buffers for whitespace creep.
273
274This is the period after which the timer will fire causing
275`whitespace-rescan-files-in-buffers' to check for whitespace creep in
18d51459
RS
276modified buffers.
277
278To disable timer scans, set this to zero."
acc975b1
DL
279 :type 'integer
280 :group 'whitespace)
281
dd24f431
GM
282(defcustom whitespace-display-in-modeline t
283 "Display whitespace errors on the modeline."
284 :type 'boolean
285 :group 'whitespace)
acc975b1 286
5dc2e846 287(defcustom whitespace-display-spaces-in-color t
ee01ad0e
MB
288 "Display the bogus whitespaces by coloring them with the face
289`whitespace-highlight'."
5dc2e846
RV
290 :type 'boolean
291 :group 'whitespace)
292
293(defgroup whitespace-faces nil
294 "Faces used in whitespace."
295 :prefix "whitespace-"
296 :group 'whitespace
297 :group 'faces)
298
ee01ad0e
MB
299(defface whitespace-highlight '((((class color) (background light))
300 (:background "green1"))
301 (((class color) (background dark))
302 (:background "sea green"))
303 (((class grayscale mono)
304 (background light))
305 (:background "black"))
306 (((class grayscale mono)
307 (background dark))
308 (:background "white")))
5dc2e846
RV
309 "Face used for highlighting the bogus whitespaces that exist in the buffer."
310 :group 'whitespace-faces)
ee01ad0e
MB
311;; backward-compatibility alias
312(put 'whitespace-highlight-face 'face-alias 'whitespace-highlight)
5dc2e846 313
acc975b1
DL
314(if (not (assoc 'whitespace-mode minor-mode-alist))
315 (setq minor-mode-alist (cons '(whitespace-mode whitespace-mode-line)
316 minor-mode-alist)))
317
a3db02ad
RV
318(set-default 'whitespace-check-buffer-leading
319 whitespace-check-leading-whitespace)
320(set-default 'whitespace-check-buffer-trailing
321 whitespace-check-trailing-whitespace)
322(set-default 'whitespace-check-buffer-indent
323 whitespace-check-indent-whitespace)
324(set-default 'whitespace-check-buffer-spacetab
325 whitespace-check-spacetab-whitespace)
326(set-default 'whitespace-check-buffer-ateol
327 whitespace-check-ateol-whitespace)
328
acc975b1 329(defun whitespace-check-whitespace-mode (&optional arg)
24b72a45 330 "Test and set the whitespace-mode in qualifying buffers."
acc975b1
DL
331 (if (null whitespace-mode)
332 (setq whitespace-mode
333 (if (or arg (member major-mode whitespace-modes))
334 t
335 nil))))
336
a3db02ad
RV
337;;;###autoload
338(defun whitespace-toggle-leading-check ()
339 "Toggle the check for leading space in the local buffer."
340 (interactive)
341 (let ((current-val whitespace-check-buffer-leading))
342 (setq whitespace-check-buffer-leading (not current-val))
343 (message "Will%s check for leading space in buffer."
344 (if whitespace-check-buffer-leading "" " not"))
345 (if whitespace-check-buffer-leading (whitespace-buffer-leading))))
346
347;;;###autoload
348(defun whitespace-toggle-trailing-check ()
349 "Toggle the check for trailing space in the local buffer."
350 (interactive)
351 (let ((current-val whitespace-check-buffer-trailing))
352 (setq whitespace-check-buffer-trailing (not current-val))
353 (message "Will%s check for trailing space in buffer."
354 (if whitespace-check-buffer-trailing "" " not"))
355 (if whitespace-check-buffer-trailing (whitespace-buffer-trailing))))
356
357;;;###autoload
358(defun whitespace-toggle-indent-check ()
359 "Toggle the check for indentation space in the local buffer."
360 (interactive)
361 (let ((current-val whitespace-check-buffer-indent))
362 (setq whitespace-check-buffer-indent (not current-val))
363 (message "Will%s check for indentation space in buffer."
364 (if whitespace-check-buffer-indent "" " not"))
365 (if whitespace-check-buffer-indent
366 (whitespace-buffer-search whitespace-indent-regexp))))
367
368;;;###autoload
369(defun whitespace-toggle-spacetab-check ()
370 "Toggle the check for space-followed-by-TABs in the local buffer."
371 (interactive)
372 (let ((current-val whitespace-check-buffer-spacetab))
373 (setq whitespace-check-buffer-spacetab (not current-val))
374 (message "Will%s check for space-followed-by-TABs in buffer."
375 (if whitespace-check-buffer-spacetab "" " not"))
376 (if whitespace-check-buffer-spacetab
377 (whitespace-buffer-search whitespace-spacetab-regexp))))
378
379
380;;;###autoload
381(defun whitespace-toggle-ateol-check ()
382 "Toggle the check for end-of-line space in the local buffer."
383 (interactive)
384 (let ((current-val whitespace-check-buffer-ateol))
385 (setq whitespace-check-buffer-ateol (not current-val))
386 (message "Will%s check for end-of-line space in buffer."
387 (if whitespace-check-buffer-ateol "" " not"))
388 (if whitespace-check-buffer-ateol
389 (whitespace-buffer-search whitespace-ateol-regexp))))
390
391
24b72a45 392;;;###autoload
acc975b1 393(defun whitespace-buffer (&optional quiet)
fc333790
DL
394 "Find five different types of white spaces in buffer.
395These are:
acc975b1
DL
3961. Leading space \(empty lines at the top of a file\).
3972. Trailing space \(empty lines at the end of a file\).
3983. Indentation space \(8 or more spaces, that should be replaced with TABS\).
3994. Spaces followed by a TAB. \(Almost always, we never want that\).
4005. Spaces or TABS at the end of a line.
401
402Check for whitespace only if this buffer really contains a non-empty file
403and:
4041. the major mode is one of the whitespace-modes, or
24b72a45 4052. `whitespace-buffer' was explicitly called with a prefix argument."
acc975b1 406 (interactive)
dd24f431
GM
407 (let ((whitespace-error nil))
408 (whitespace-check-whitespace-mode current-prefix-arg)
409 (if (and buffer-file-name (> (buffer-size) 0) whitespace-mode)
410 (progn
411 (whitespace-check-buffer-list (buffer-name) buffer-file-name)
412 (whitespace-tickle-timer)
113fa448 413 (overlay-recenter (point-max))
8eda2ca3 414 (remove-overlays nil nil 'face 'whitespace-highlight)
dd24f431
GM
415 (if whitespace-auto-cleanup
416 (if buffer-read-only
417 (if (not quiet)
418 (message "Can't cleanup: %s is read-only" (buffer-name)))
f473c8d5 419 (whitespace-cleanup-internal))
a3db02ad 420 (let ((whitespace-leading (if whitespace-check-buffer-leading
dd24f431
GM
421 (whitespace-buffer-leading)
422 nil))
a3db02ad 423 (whitespace-trailing (if whitespace-check-buffer-trailing
dd24f431
GM
424 (whitespace-buffer-trailing)
425 nil))
a3db02ad 426 (whitespace-indent (if whitespace-check-buffer-indent
18d51459 427 (whitespace-buffer-search
dd24f431 428 whitespace-indent-regexp)
18d51459 429 nil))
a3db02ad 430 (whitespace-spacetab (if whitespace-check-buffer-spacetab
dd24f431
GM
431 (whitespace-buffer-search
432 whitespace-spacetab-regexp)
433 nil))
a3db02ad 434 (whitespace-ateol (if whitespace-check-buffer-ateol
dd24f431
GM
435 (whitespace-buffer-search
436 whitespace-ateol-regexp)
437 nil))
438 (whitespace-errmsg nil)
439 (whitespace-filename buffer-file-name)
440 (whitespace-this-modeline ""))
441
442 ;; Now let's complain if we found any of the above.
443 (setq whitespace-error (or whitespace-leading whitespace-indent
444 whitespace-spacetab whitespace-ateol
445 whitespace-trailing))
446
447 (if whitespace-error
acc975b1 448 (progn
dd24f431
GM
449 (setq whitespace-errmsg
450 (concat whitespace-filename " contains:\n"
451 (if whitespace-leading
452 "Leading whitespace\n")
453 (if whitespace-indent
454 (concat "Indentation whitespace"
455 whitespace-indent "\n"))
456 (if whitespace-spacetab
457 (concat "Space followed by Tab"
458 whitespace-spacetab "\n"))
459 (if whitespace-ateol
460 (concat "End-of-line whitespace"
461 whitespace-ateol "\n"))
462 (if whitespace-trailing
463 "Trailing whitespace\n")
464 "\ntype `M-x whitespace-cleanup' to "
465 "cleanup the file."))
466 (setq whitespace-this-modeline
467 (concat (if whitespace-ateol "e")
468 (if whitespace-indent "i")
469 (if whitespace-leading "l")
470 (if whitespace-spacetab "s")
471 (if whitespace-trailing "t")))))
472 (whitespace-update-modeline whitespace-this-modeline)
c22c3db0
SM
473 (if (get-buffer whitespace-errbuf)
474 (kill-buffer whitespace-errbuf))
475 (with-current-buffer (get-buffer-create whitespace-errbuf)
dd24f431
GM
476 (if whitespace-errmsg
477 (progn
478 (insert whitespace-errmsg)
479 (if (not (or quiet whitespace-silent))
c22c3db0 480 (display-buffer (current-buffer) t))
dd24f431
GM
481 (if (not quiet)
482 (message "Whitespaces: [%s%s] in %s"
483 whitespace-this-modeline
484 (let ((whitespace-unchecked
485 (whitespace-unchecked-whitespaces)))
486 (if whitespace-unchecked
487 (concat "!" whitespace-unchecked)
488 ""))
489 whitespace-filename)))
c98ddbe5
RV
490 (if (and (not quiet) (not (equal whitespace-clean-msg "")))
491 (message "%s %s" whitespace-filename
492 whitespace-clean-msg))))))))
c22c3db0 493 whitespace-error))
acc975b1 494
24b72a45 495;;;###autoload
acc975b1 496(defun whitespace-region (s e)
fc333790 497 "Check the region for whitespace errors."
acc975b1
DL
498 (interactive "r")
499 (save-excursion
500 (save-restriction
501 (narrow-to-region s e)
502 (whitespace-buffer))))
503
24b72a45 504;;;###autoload
acc975b1 505(defun whitespace-cleanup ()
24b72a45 506 "Cleanup the five different kinds of whitespace problems.
0d92660c
RS
507It normally applies to the whole buffer, but in Transient Mark mode
508when the mark is active it applies to the region.
04f0adee 509See `whitespace-buffer' docstring for a summary of the problems."
acc975b1 510 (interactive)
f473c8d5
RV
511 (if (and transient-mark-mode mark-active)
512 (whitespace-cleanup-region (region-beginning) (region-end))
513 (whitespace-cleanup-internal)))
514
6e6f0cb6 515(defun whitespace-cleanup-internal (&optional region-only)
acc975b1
DL
516 ;; If this buffer really contains a file, then run, else quit.
517 (whitespace-check-whitespace-mode current-prefix-arg)
518 (if (and buffer-file-name whitespace-mode)
519 (let ((whitespace-any nil)
520 (whitespace-tabwith 8)
521 (whitespace-tabwith-saved tab-width))
522
523 ;; since all printable TABS should be 8, irrespective of how
524 ;; they are displayed.
525 (setq tab-width whitespace-tabwith)
526
a3db02ad 527 (if (and whitespace-check-buffer-leading
18d51459 528 (whitespace-buffer-leading))
acc975b1
DL
529 (progn
530 (whitespace-buffer-leading-cleanup)
531 (setq whitespace-any t)))
532
a3db02ad 533 (if (and whitespace-check-buffer-trailing
18d51459 534 (whitespace-buffer-trailing))
acc975b1
DL
535 (progn
536 (whitespace-buffer-trailing-cleanup)
537 (setq whitespace-any t)))
538
a3db02ad 539 (if (and whitespace-check-buffer-indent
18d51459 540 (whitespace-buffer-search whitespace-indent-regexp))
acc975b1
DL
541 (progn
542 (whitespace-indent-cleanup)
543 (setq whitespace-any t)))
544
a3db02ad 545 (if (and whitespace-check-buffer-spacetab
18d51459 546 (whitespace-buffer-search whitespace-spacetab-regexp))
acc975b1
DL
547 (progn
548 (whitespace-buffer-cleanup whitespace-spacetab-regexp "\t")
549 (setq whitespace-any t)))
550
a3db02ad 551 (if (and whitespace-check-buffer-ateol
18d51459 552 (whitespace-buffer-search whitespace-ateol-regexp))
acc975b1
DL
553 (progn
554 (whitespace-buffer-cleanup whitespace-ateol-regexp "")
555 (setq whitespace-any t)))
556
557 ;; Call this recursively till everything is taken care of
18d51459 558 (if whitespace-any
2b058c72 559 (whitespace-cleanup-internal region-only)
6e6f0cb6 560 ;; if we are done, talk to the user
acc975b1 561 (progn
6e6f0cb6
EZ
562 (unless whitespace-silent
563 (if region-only
564 (message "The region is now clean")
565 (message "%s is now clean" buffer-file-name)))
dd24f431 566 (whitespace-update-modeline)))
acc975b1
DL
567 (setq tab-width whitespace-tabwith-saved))))
568
24b72a45 569;;;###autoload
acc975b1 570(defun whitespace-cleanup-region (s e)
fc333790 571 "Whitespace cleanup on the region."
acc975b1
DL
572 (interactive "r")
573 (save-excursion
574 (save-restriction
575 (narrow-to-region s e)
6e6f0cb6 576 (whitespace-cleanup-internal t))
acc975b1
DL
577 (whitespace-buffer t)))
578
579(defun whitespace-buffer-leading ()
113fa448
EZ
580 "Return t if the current buffer has leading newline characters.
581If highlighting is enabled, highlight these characters."
acc975b1 582 (save-excursion
113fa448
EZ
583 (goto-char (point-min))
584 (skip-chars-forward "\n")
585 (unless (bobp)
586 (whitespace-highlight-the-space (point-min) (point))
587 t)))
acc975b1
DL
588
589(defun whitespace-buffer-leading-cleanup ()
113fa448 590 "Remove any leading newline characters from current buffer."
acc975b1 591 (save-excursion
185d43ee
RS
592 (goto-char (point-min))
593 (skip-chars-forward "\n")
594 (delete-region (point-min) (point))))
acc975b1
DL
595
596(defun whitespace-buffer-trailing ()
113fa448
EZ
597 "Return t if the current buffer has extra trailing newline characters.
598If highlighting is enabled, highlight these characters."
acc975b1 599 (save-excursion
113fa448
EZ
600 (goto-char (point-max))
601 (skip-chars-backward "\n")
602 (forward-line)
603 (unless (eobp)
604 (whitespace-highlight-the-space (point) (point-max))
605 t)))
acc975b1
DL
606
607(defun whitespace-buffer-trailing-cleanup ()
113fa448 608 "Remove extra trailing newline characters from current buffer."
acc975b1 609 (save-excursion
185d43ee
RS
610 (goto-char (point-max))
611 (skip-chars-backward "\n")
113fa448
EZ
612 (unless (eobp)
613 (forward-line)
614 (delete-region (point) (point-max)))))
acc975b1
DL
615
616(defun whitespace-buffer-search (regexp)
617 "Search for any given whitespace REGEXP."
113fa448
EZ
618 (with-local-quit
619 (let (whitespace-retval)
620 (save-excursion
621 (goto-char (point-min))
622 (while (re-search-forward regexp nil t)
623 (whitespace-highlight-the-space (match-beginning 0) (match-end 0))
624 (push (match-beginning 0) whitespace-retval)))
625 (when whitespace-retval
626 (format " %s" (nreverse whitespace-retval))))))
acc975b1
DL
627
628(defun whitespace-buffer-cleanup (regexp newregexp)
629 "Search for any given whitespace REGEXP and replace it with the NEWREGEXP."
630 (save-excursion
631 (goto-char (point-min))
632 (while (re-search-forward regexp nil t)
633 (replace-match newregexp))))
634
635(defun whitespace-indent-cleanup ()
24b72a45 636 "Search for 8/more spaces at the start of a line and replace it with tabs."
acc975b1
DL
637 (save-excursion
638 (goto-char (point-min))
639 (while (re-search-forward whitespace-indent-regexp nil t)
640 (let ((column (current-column))
641 (indent-tabs-mode t))
642 (delete-region (match-beginning 0) (point))
643 (indent-to column)))))
644
dd24f431
GM
645(defun whitespace-unchecked-whitespaces ()
646 "Return the list of whitespaces whose testing has been suppressed."
a3db02ad
RV
647 (let ((unchecked-spaces
648 (concat (if (not whitespace-check-buffer-ateol) "e")
649 (if (not whitespace-check-buffer-indent) "i")
650 (if (not whitespace-check-buffer-leading) "l")
651 (if (not whitespace-check-buffer-spacetab) "s")
652 (if (not whitespace-check-buffer-trailing) "t"))))
653 (if (not (equal unchecked-spaces ""))
654 unchecked-spaces
dd24f431
GM
655 nil)))
656
657(defun whitespace-update-modeline (&optional whitespace-err)
fc333790
DL
658 "Update modeline with whitespace errors.
659Also with whitespaces whose testing has been turned off."
dd24f431 660 (if whitespace-display-in-modeline
0e38b2a2
GM
661 (progn
662 (setq whitespace-mode-line nil)
663 ;; Whitespace errors
664 (if (and whitespace-err (not (equal whitespace-err "")))
665 (setq whitespace-mode-line whitespace-err))
666 ;; Whitespace suppressed errors
667 (let ((whitespace-unchecked (whitespace-unchecked-whitespaces)))
668 (if whitespace-unchecked
669 (setq whitespace-mode-line
670 (concat whitespace-mode-line "!" whitespace-unchecked))))
671 ;; Add the whitespace modeline prefix
672 (setq whitespace-mode-line (if whitespace-mode-line
673 (concat " W:" whitespace-mode-line)
674 nil))
5dc2e846 675 (whitespace-mode-line-update))))
18d51459 676
5dc2e846
RV
677(defun whitespace-highlight-the-space (b e)
678 "Highlight the current line, unhighlighting a previously jumped to line."
679 (if whitespace-display-spaces-in-color
c22c3db0 680 (let ((ol (whitespace-make-overlay b e)))
ee01ad0e 681 (whitespace-overlay-put ol 'face 'whitespace-highlight))))
5dc2e846 682
7dbe67a4 683(defun whitespace-unhighlight-the-space()
5dc2e846
RV
684 "Unhighlight the currently highlight line."
685 (if (and whitespace-display-spaces-in-color whitespace-highlighted-space)
c22c3db0
SM
686 (progn
687 (mapc 'whitespace-delete-overlay whitespace-highlighted-space)
113fa448 688 (setq whitespace-highlighted-space nil))))
acc975b1
DL
689
690(defun whitespace-check-buffer-list (buf-name buf-file)
24b72a45
RS
691 "Add a buffer and its file to the whitespace monitor list.
692
693The buffer named BUF-NAME and its associated file BUF-FILE are now monitored
694periodically for whitespace."
acc975b1
DL
695 (if (and whitespace-mode (not (member (list buf-file buf-name)
696 whitespace-all-buffer-files)))
697 (add-to-list 'whitespace-all-buffer-files (list buf-file buf-name))))
698
699(defun whitespace-tickle-timer ()
24b72a45
RS
700 "Tickle timer to periodically to scan qualifying files for whitespace creep.
701
702If timer is not set, then set it to scan the files in
703`whitespace-all-buffer-files' periodically (defined by
704`whitespace-rescan-timer-time') for whitespace creep."
f0fe5c14
MC
705 (if (and whitespace-rescan-timer-time
706 (/= whitespace-rescan-timer-time 0)
707 (not whitespace-rescan-timer))
acc975b1 708 (setq whitespace-rescan-timer
fc333790
DL
709 (add-timeout whitespace-rescan-timer-time
710 'whitespace-rescan-files-in-buffers nil
711 whitespace-rescan-timer-time))))
acc975b1
DL
712
713(defun whitespace-rescan-files-in-buffers (&optional arg)
24b72a45 714 "Check monitored files for whitespace creep since last scan."
acc975b1 715 (let ((whitespace-all-my-files whitespace-all-buffer-files)
24b72a45 716 buffile bufname thiselt buf)
acc975b1
DL
717 (if (not whitespace-all-my-files)
718 (progn
fc333790 719 (disable-timeout whitespace-rescan-timer)
acc975b1
DL
720 (setq whitespace-rescan-timer nil))
721 (while whitespace-all-my-files
722 (setq thiselt (car whitespace-all-my-files))
723 (setq whitespace-all-my-files (cdr whitespace-all-my-files))
724 (setq buffile (car thiselt))
725 (setq bufname (cadr thiselt))
726 (setq buf (get-buffer bufname))
727 (if (buffer-live-p buf)
728 (save-excursion
729 ;;(message "buffer %s live" bufname)
730 (set-buffer bufname)
731 (if whitespace-mode
732 (progn
733 ;;(message "checking for whitespace in %s" bufname)
734 (if whitespace-auto-cleanup
735 (progn
736 ;;(message "cleaning up whitespace in %s" bufname)
f473c8d5 737 (whitespace-cleanup-internal))
acc975b1
DL
738 (progn
739 ;;(message "whitespace-buffer %s." (buffer-name))
740 (whitespace-buffer t))))
741 ;;(message "Removing %s from refresh list" bufname)
742 (whitespace-refresh-rescan-list buffile bufname)))
743 ;;(message "Removing %s from refresh list" bufname)
744 (whitespace-refresh-rescan-list buffile bufname))))))
745
746(defun whitespace-refresh-rescan-list (buffile bufname)
113fa448 747 "Refresh the list of files to be rescanned for whitespace creep."
acc975b1 748 (if whitespace-all-buffer-files
fc333790
DL
749 (setq whitespace-all-buffer-files
750 (delete (list buffile bufname) whitespace-all-buffer-files))
751 (when whitespace-rescan-timer
752 (disable-timeout whitespace-rescan-timer)
753 (setq whitespace-rescan-timer nil))))
754
35bf5a4e
RS
755;;;###autoload
756(defalias 'global-whitespace-mode 'whitespace-global-mode)
757
fc333790 758;;;###autoload
07089c84 759(define-minor-mode whitespace-global-mode
fc333790 760 "Toggle using Whitespace mode in new buffers.
4837b516 761With ARG, turn the mode on if ARG is positive, otherwise turn it off.
fc333790
DL
762
763When this mode is active, `whitespace-buffer' is added to
07089c84 764`find-file-hook' and `kill-buffer-hook'."
9800cbdd 765 :global t
9800cbdd 766 :group 'whitespace
07089c84 767 (if whitespace-global-mode
acc975b1 768 (progn
07089c84
SM
769 (add-hook 'find-file-hook 'whitespace-buffer)
770 (add-hook 'write-file-functions 'whitespace-write-file-hook nil t)
fc333790 771 (add-hook 'kill-buffer-hook 'whitespace-buffer))
07089c84
SM
772 (remove-hook 'find-file-hook 'whitespace-buffer)
773 (remove-hook 'write-file-functions 'whitespace-write-file-hook t)
fc333790 774 (remove-hook 'kill-buffer-hook 'whitespace-buffer)))
acc975b1 775
1f8437c4
RV
776;;;###autoload
777(defun whitespace-write-file-hook ()
07089c84
SM
778 "Hook function to be called on the buffer when whitespace check is enabled.
779This is meant to be added buffer-locally to `write-file-functions'."
1f8437c4
RV
780 (let ((werr nil))
781 (if whitespace-auto-cleanup
f473c8d5 782 (whitespace-cleanup-internal)
1f8437c4
RV
783 (setq werr (whitespace-buffer)))
784 (if (and whitespace-abort-on-error werr)
8c16bd8c
DG
785 (error "Abort write due to whitespaces in %s"
786 buffer-file-name)))
1f8437c4
RV
787 nil)
788
6341c3fc
JB
789(defun whitespace-unload-function ()
790 "Unload the whitespace library."
3e1da214
JB
791 (if (unintern "whitespace-unload-hook")
792 ;; if whitespace-unload-hook is defined, let's get rid of it
793 ;; and recursively call `unload-feature'
794 (progn (unload-feature 'whitespace) t)
795 ;; this only happens in the recursive call
796 (whitespace-global-mode -1)
797 (save-current-buffer
798 (dolist (buf (buffer-list))
799 (set-buffer buf)
800 (remove-hook 'write-file-functions 'whitespace-write-file-hook t)))
801 ;; continue standard unloading
802 nil))
6341c3fc 803
fc333790 804(defun whitespace-unload-hook ()
07089c84 805 (remove-hook 'find-file-hook 'whitespace-buffer)
e23d264d 806 (remove-hook 'write-file-functions 'whitespace-write-file-hook t)
fc333790
DL
807 (remove-hook 'kill-buffer-hook 'whitespace-buffer))
808
fd07aeb3
RS
809(add-hook 'whitespace-unload-hook 'whitespace-unload-hook)
810
acc975b1 811(provide 'whitespace)
ab5796a9 812
c22c3db0 813;; arch-tag: 4ff44e87-b63c-402d-95a6-15e51e58bd0c
acc975b1 814;;; whitespace.el ends here