emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

More intelligent command for C-x TAB (understand also tab-stop-list)


From: Teemu Likonen
Subject: More intelligent command for C-x TAB (understand also tab-stop-list)
Date: Sat, 13 Jul 2013 09:41:58 +0300
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux)

I propose binding a new command to C-x TAB. This new command would have
all the functionality of the current command (indent-rigidly) but also
added intelligence to understand tab-stop-list.

I have discussed this in #8196:
<http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8196>. But as there was
some misunderstanding I try to write a better explanation here.

The current C-x TAB command (indent-rigidly) command moves region
forward or backward by the number of columns given as prefix argument.
If user does not give the command a prefix argument the default is to
move by 1 column.

My proposed new C-x TAB command would do the same thing as
indent-rigidly when given a numeric prefix argument. There would be
difference only when user doesn't give it a numeric prefix argument. In
such case the new C-x TAB command would move the region to the next or
previous tab stop as defined in the tab-stop-list variable. The lowest
indentation level of the region would be moved to the tab stop column.

Here's a concrete editing example. We have defined tab-stop-list
variable as (4 8 12 16 20 etc.) and we have a buffer with the following
text:

 (defun foo ()
   (some-code)
   (more-code))

Now I mark the above piece of code with M-h and execute "M-x
indent-rigidly". The result is this:

  (defun foo ()
    (some-code)
    (more-code))

The text advances by one column. With my proposed new command it would
move to the next tab stop column:

    (defun foo ()
      (some-code)
      (more-code))

The lowest indentation point of that region is now at column 4 because
that's the next tab stop defined in tab-stop-list variable. In my
proposed new command there is a repeat feature too. If I keep on
repeating TAB (that is, C-x TAB TAB TAB) the region would move to the
next tab stops: 8, 12, 16, 20 etc.

With the negative non-numeric prefix argument (C-u -) my proposed
command would do the same but go to the previous tab stop column as
defined in tab-stop-list variable.

The name for this new command could be "indent-region-to-tab-stop", for
example, and it relies on "indent-region" to do the actual job.

For those who want to try this command just evaluate the code below.
Emacs developers are free to use the code because I have done the
copyright-assignment paperwork for FSF.


--8<---------------cut here---------------start------------->8---
(defun 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 indent-region-to-tab-stop-engine (beg end arg)
  "Back-end function for `indent-region-to-tab-stop'."
  (interactive "r\nP")
  (let* ((beg (save-excursion (goto-char beg) (line-beginning-position)))
         (current (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 indent-region-to-tab-stop (beg end arg)
  "Indent region to a tab stop column or to the 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 'indent-region-to-tab-stop-engine)
    (repeat nil)))
--8<---------------cut here---------------end--------------->8---

Attachment: pgpXT2dwvjd9k.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]