- If `whitespace-chars' includes the value `space-after-tab',
- replace SPACEs by TABs."
- (interactive "@*r")
- (let ((rstart (min start end))
- (rend (copy-marker (max start end)))
- (tab-width 8) ; assure TAB width
- (indent-tabs-mode t) ; always insert TABs
- overwrite-mode ; enforce no overwrite
- tmp)
- (save-excursion
- (save-match-data
- ;; problem 1: 8 or more SPACEs at bol
- ;; action: replace 8 or more SPACEs at bol by TABs
- (when (memq 'indentation whitespace-chars)
- (goto-char rstart)
- (while (re-search-forward
- whitespace-indentation-regexp rend t)
- (setq tmp (current-indentation))
- (delete-horizontal-space)
- (unless (eolp)
- (indent-to tmp))))
- ;; problem 3: SPACEs or TABs at eol
- ;; action: remove all SPACEs or TABs at eol
- (when (memq 'trailing whitespace-chars)
- (let ((regexp (concat "\\(\\(" whitespace-trailing-regexp
- "\\)+\\)$")))
- (goto-char rstart)
- (while (re-search-forward regexp rend t)
- (delete-region (match-beginning 1) (match-end 1)))))
- ;; problem 4: 8 or more SPACEs after TAB
- ;; action: replace 8 or more SPACEs by TABs
- (when (memq 'space-after-tab whitespace-chars)
- (whitespace-replace-spaces-by-tabs
- rstart rend whitespace-space-after-tab-regexp))
- ;; problem 2: SPACEs before TAB
- ;; action: replace SPACEs before TAB by TABs
- (when (memq 'space-before-tab whitespace-chars)
- (whitespace-replace-spaces-by-tabs
- rstart rend whitespace-space-before-tab-regexp))))
- (set-marker rend nil))) ; point marker to nowhere
-
-
-(defun whitespace-replace-spaces-by-tabs (rstart rend regexp)
- "Replace all SPACEs by TABs matched by REGEXP between RSTART and REND."
+ If `whitespace-style' includes the value `space-after-tab':
+ replace SPACEs by TABs, if `indent-tabs-mode' is non-nil;
+ otherwise, replace TABs by SPACEs.
+ If `whitespace-style' includes the value
+ `space-after-tab::tab', replace SPACEs by TABs.
+ If `whitespace-style' includes the value
+ `space-after-tab::space', replace TABs by SPACEs.
+
+See `whitespace-style', `indent-tabs-mode' and `tab-width' for
+documentation."
+ (interactive "@r")
+ (if buffer-read-only
+ ;; read-only buffer
+ (whitespace-warn-read-only "cleanup region")
+ ;; non-read-only buffer
+ (let ((rstart (min start end))
+ (rend (copy-marker (max start end)))
+ (indent-tabs-mode whitespace-indent-tabs-mode)
+ (tab-width whitespace-tab-width)
+ overwrite-mode ; enforce no overwrite
+ tmp)
+ (save-excursion
+ (save-match-data
+ ;; PROBLEM 1: 8 or more SPACEs at bol
+ (cond
+ ;; ACTION: replace 8 or more SPACEs at bol by TABs, if
+ ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs
+ ;; by SPACEs.
+ ((memq 'indentation whitespace-style)
+ (let ((regexp (whitespace-indentation-regexp)))
+ (goto-char rstart)
+ (while (re-search-forward regexp rend t)
+ (setq tmp (current-indentation))
+ (goto-char (match-beginning 0))
+ (delete-horizontal-space)
+ (unless (eolp)
+ (indent-to tmp)))))
+ ;; ACTION: replace 8 or more SPACEs at bol by TABs.
+ ((memq 'indentation::tab whitespace-style)
+ (whitespace-replace-action
+ 'tabify rstart rend
+ (whitespace-indentation-regexp 'tab) 0))
+ ;; ACTION: replace TABs by SPACEs.
+ ((memq 'indentation::space whitespace-style)
+ (whitespace-replace-action
+ 'untabify rstart rend
+ (whitespace-indentation-regexp 'space) 0)))
+ ;; PROBLEM 3: SPACEs or TABs at eol
+ ;; ACTION: remove all SPACEs or TABs at eol
+ (when (memq 'trailing whitespace-style)
+ (whitespace-replace-action
+ 'delete-region rstart rend
+ whitespace-trailing-regexp 1))
+ ;; PROBLEM 4: 8 or more SPACEs after TAB
+ (cond
+ ;; ACTION: replace 8 or more SPACEs by TABs, if
+ ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs
+ ;; by SPACEs.
+ ((memq 'space-after-tab whitespace-style)
+ (whitespace-replace-action
+ (if whitespace-indent-tabs-mode 'tabify 'untabify)
+ rstart rend (whitespace-space-after-tab-regexp) 1))
+ ;; ACTION: replace 8 or more SPACEs by TABs.
+ ((memq 'space-after-tab::tab whitespace-style)
+ (whitespace-replace-action
+ 'tabify rstart rend
+ (whitespace-space-after-tab-regexp 'tab) 1))
+ ;; ACTION: replace TABs by SPACEs.
+ ((memq 'space-after-tab::space whitespace-style)
+ (whitespace-replace-action
+ 'untabify rstart rend
+ (whitespace-space-after-tab-regexp 'space) 1)))
+ ;; PROBLEM 2: SPACEs before TAB
+ (cond
+ ;; ACTION: replace SPACEs before TAB by TABs, if
+ ;; `indent-tabs-mode' is non-nil; otherwise, replace TABs
+ ;; by SPACEs.
+ ((memq 'space-before-tab whitespace-style)
+ (whitespace-replace-action
+ (if whitespace-indent-tabs-mode 'tabify 'untabify)
+ rstart rend whitespace-space-before-tab-regexp
+ (if whitespace-indent-tabs-mode 1 2)))
+ ;; ACTION: replace SPACEs before TAB by TABs.
+ ((memq 'space-before-tab::tab whitespace-style)
+ (whitespace-replace-action
+ 'tabify rstart rend
+ whitespace-space-before-tab-regexp 1))
+ ;; ACTION: replace TABs by SPACEs.
+ ((memq 'space-before-tab::space whitespace-style)
+ (whitespace-replace-action
+ 'untabify rstart rend
+ whitespace-space-before-tab-regexp 2)))))
+ (set-marker rend nil)))) ; point marker to nowhere
+
+
+(defun whitespace-replace-action (action rstart rend regexp index)
+ "Do ACTION in the string matched by REGEXP between RSTART and REND.
+
+INDEX is the level group matched by REGEXP and used by ACTION.
+
+See also `tab-width'."