Subject: 23.1; Feature request with code: "C-x TAB" to understand tab-stop-list

From: Teemu Likonen <[email-masked]>
Date: Mon, 07 Mar 2011 20:19:13 +0200

I think it would be better if "C-x TAB" (bound to indent-rigidly)
advanced the indentation to the next tab stop (as in tab-stop-list) by
default, instead of by 1. Similarly, if negative prefix argument were
given (with "C-u -") it would change the indentation to the previous tab
stop. Only when the prefix argument is actual number, positive or
negative integer, it would move the indentation to the left or right by
the given count.

To demonstrate this I have written the following functions. Function
tl-indent-region is a kind of replacement for indent-rigidly, so it can
be bound to "C-x TAB".

--8<---------------cut here---------------start------------->8---
(global-set-key (kbd "C-x TAB") #'tl-indent-region)

(defun tl-region-indentation (beg end)
  "Return the smallest indentation in range from BEG to END.
Blank lines are ignored."
  (save-excursion
    (let ((beg (progn (goto-char beg) (line-beginning-position)))
          indent)
      (goto-char beg)
      (while (re-search-forward "^\\s-*[[:print:]]" end t)
        (setq indent (min (or indent (current-indentation))
                          (current-indentation))))
      indent)))

(defun tl-indent-region-engine (beg end arg)
  "Back-end function for `tl-indent-region'."
  (interactive "r\nP")
  (let* ((beg (save-excursion (goto-char beg) (line-beginning-position)))
         (current (tl-region-indentation beg end))
         (indent (cond ((not arg)
                        (- (catch 'answer
                             (dolist (col tab-stop-list (1+ current))
                               (when (> col current)
                                 (throw 'answer col))))
                           current))
                       ((eq arg '-)
                        (- (catch 'answer
                             (dolist (col (reverse tab-stop-list) 0)
                               (when (< col current)
                                 (throw 'answer col))))
                           current))
                       (t (prefix-numeric-value arg)))))
    (indent-rigidly beg end indent)))

(defun tl-indent-region (beg end arg)
  "Indent region to a tab stop column or to a specified column.

Indent the region from BEG to END according to the command's
prefix argument ARG. If ARG is nil (i.e., there is no prefix
argument) indent the region to the next tab stop column in
`tab-stop-list'. With negative prefix ARG (C-u -) indent the
region to the previous tab stop column. If ARG is an integer
indent the region by ARG columns (just like `indent-rigidly'
command).

If this command is invoked by a multi-character key sequence, it
can be repeated by repeating the final character of the
sequence."

  (interactive "r\nP")
  (require 'repeat)
  (let ((repeat-message-function #'ignore))
    (setq last-repeatable-command #'tl-indent-region-engine)
    (repeat nil)))
--8<---------------cut here---------------end--------------->8---