Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Indenting paragraphs manually

82 views
Skip to first unread message

Dani Moncayo

unread,
Mar 4, 2011, 6:17:46 PM3/4/11
to help-gn...@gnu.org
Hi!

I'm looking for a simple way of indenting paragraphs manually (in text
modes), and I've just read this node of the Emacs Manual: (info "(emacs)
Indentation"). It explains, among other things, the general behavior of
the <TAB> key in text modes:

In text modes, <TAB> inserts some combination of space and tab
characters to advance point to the next tab stop (*note Tab Stops).
If the region is active and spans multiple lines, it advances the first
character of each of those lines to the next tab stop (*note Using
Region). [...]


I'm used to that behavior in other editors, and I like it, but
is not what I currently see in Emacs. e.g.:
- Start Emacs (emacs -Q)
- Set text-mode in the *scratch* buffer. (text-mode).
- Set transient-mark-mode on. (transient-mark-mode 1).
- Select the first 3 lines.
- Type <TAB>

What I was expecting:
- The selected lines move to the next tab-stop.
- The region remains active, so that I can repeat the indentation
several times in a row.

What I see:
- The selected lines are not not moved at all.
- The region is deactivated.

Please, could someone explain this? Am I missing something? (I guess I
am, and that's why I'm posting to help-gnu-emacs instead of
bug-gnu-emacs)

TIA

---
Dani Moncayo

In GNU Emacs 24.0.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 2.22.0)
of 2011-02-26 on dani-P5PL2
Windowing system distributor `The X.Org Foundation', version 11.0.10900000

Andrea Crotti

unread,
Mar 5, 2011, 3:26:54 PM3/5/11
to Dani Moncayo, help-gn...@gnu.org
Dani Moncayo <dmon...@gmail.com> writes:

So you're misunderstanding the use of TAB in this case.
TAB indents, but "smartly", so it actually never really inserts a tab
(apart maybe some modes where this is the good thing to do)

What you want to do can be done with rectangle mode, so
- select the region you want
- C-x r t RET TAB
and you're done

Peter Dyballa

unread,
Mar 5, 2011, 5:01:05 PM3/5/11
to Dani Moncayo, help-gn...@gnu.org

Am 05.03.2011 um 00:17 schrieb Dani Moncayo:

> Am I missing something?

Yes: many new meanings of <TAB>. (I try not use it that often, so I
can't do what the documentation can: explain them.)

--
Greetings

Pete

Upgraded, adj.:
Didn't work the first time.


Harry Putnam

unread,
Mar 5, 2011, 5:23:23 PM3/5/11
to help-gn...@gnu.org
Andrea Crotti <andrea....@gmail.com> writes:

> So you're misunderstanding the use of TAB in this case.
> TAB indents, but "smartly", so it actually never really inserts a tab
> (apart maybe some modes where this is the good thing to do)
>

Skipping for a moment that you already showed a way to do this in
rectangle mode....

If one were to actually insert a TAB with C-q C-i... then should the
action this string describes work?:

PJ Weisberg

unread,
Mar 5, 2011, 6:28:58 PM3/5/11
to help-gnu-emacs
On Fri, Mar 4, 2011 at 3:17 PM, Dani Moncayo <dmon...@gmail.com> wrote:

> What I was expecting:
>  - The selected lines move to the next tab-stop.
>  - The region remains active, so that I can repeat the indentation
> several times in a row.
>
> What I see:
>  - The selected lines are not not moved at all.
>  - The region is deactivated.
>
> Please, could someone explain this? Am I missing something?  (I guess I
> am, and that's why I'm posting to help-gnu-emacs instead of
> bug-gnu-emacs)
>

It certainly does seem like a bug to me. I would go ahead and report
it with M-x report-emacs-bug.

-PJ

Le Wang

unread,
Mar 5, 2011, 9:29:28 PM3/5/11
to help-gnu-emacs
On Sun, Mar 6, 2011 at 7:28 AM, PJ Weisberg <p...@irregularexpressions.net> wrote:
On Fri, Mar 4, 2011 at 3:17 PM, Dani Moncayo <dmon...@gmail.com> wrote:

> What I was expecting:
>  - The selected lines move to the next tab-stop.



>  - The region remains active, so that I can repeat the indentation
> several times in a row.

 
> What I see:
>  - The selected lines are not not moved at all.
 
This part does look like a bug.  

>  - The region is deactivated.

If the bug didn't exist, the region would still be deactivated as a part of the command loop because you've modified the buffer.

You can keep the region active by wrapping the function call around a (let (deactivate-mark) ...)
 
It certainly does seem like a bug to me.  I would go ahead and report
it with M-x report-emacs-bug.

-PJ


Yes, file the bug report.  In the mean time, as a work-around, cua-mode rectangles do exactly what you want.


--
Le

PJ Weisberg

unread,
Mar 5, 2011, 10:08:57 PM3/5/11
to help-gn...@gnu.org
On 3/5/11, Le Wang <l26...@gmail.com> wrote:
> On Sun, Mar 6, 2011 at 7:28 AM, PJ Weisberg
> <p...@irregularexpressions.net>wrote:
>
>> On Fri, Mar 4, 2011 at 3:17 PM, Dani Moncayo <dmon...@gmail.com> wrote:
>>
>> > What I was expecting:
>> > - The selected lines move to the next tab-stop.
>>
>
>
>
>> - The region remains active, so that I can repeat the indentation
>> > several times in a row.
>>
>
>
>
>> > What I see:
>> > - The selected lines are not not moved at all.
>>
>
> This part does look like a bug.
>
>> - The region is deactivated.
>>
>
> If the bug didn't exist, the region would still be deactivated as a part of
> the command loop because you've modified the buffer.

That's the part that seemed like a bug to me: the region getting
deactivated as part of the command loop. The text *did* move when I
tried it, but in other editors it would be possible to move it by more
than one tab-stop by pressing TAB multiple times.

-PJ

rusi

unread,
Mar 6, 2011, 3:18:16 AM3/6/11
to
On Mar 6, 4:28 am, PJ Weisberg <p...@irregularexpressions.net> wrote:

Theres more strange (buggy?) behavior here.

I took the text (note flush left):

In text modes, <TAB> inserts some combination of space and tab
characters to advance point to the next tab stop (*note Tab Stops).
If the region is active and spans multiple lines, it advances the
first
character of each of those lines to the next tab stop (*note Using
Region). [...]

Then did the described action (except for turning transient-mode on)
At first it put 1 tab at start of each line

The second time it added 1 tab on 1st line,2 on second, 3 on third, 4
on fourth etc !!

Le Wang

unread,
Mar 6, 2011, 3:37:51 AM3/6/11
to PJ Weisberg, help-gn...@gnu.org
On Sun, Mar 6, 2011 at 11:08 AM, PJ Weisberg <p...@irregularexpressions.net> wrote:
> If the bug didn't exist, the region would still be deactivated as a part of
> the command loop because you've modified the buffer.

That's the part that seemed like a bug to me: the region getting
deactivated as part of the command loop.  The text *did* move when I
tried it, but in other editors it would be possible to move it by more
than one tab-stop by pressing TAB multiple times.

Ok, this appears to be a regression in CVS Emacs.  Emacs 23.2.1 does indent the region properly, as you say.

Region deactivation is the default behaviour in Emacs for all functions I can think of.  It would be surprising if it did something else.  You can reactivate the region with C-xC-x.


--
Le

Le Wang

unread,
Mar 6, 2011, 4:10:54 AM3/6/11
to rusi, help-gn...@gnu.org
It runs indent-line-function, which is indent-relative at the beginning of each line in the region, because indent-region-function is nil.
--
Le

Dani Moncayo

unread,
Mar 6, 2011, 6:47:02 AM3/6/11
to Andrea Crotti, help-gn...@gnu.org
Hi Andrea,

On Sat, Mar 5, 2011 at 21:26, Andrea Crotti <andrea....@gmail.com> wrote:
> So you're misunderstanding the use of TAB in this case.
> TAB indents, but "smartly", so it actually never really inserts a tab
> (apart maybe some modes where this is the good thing to do)
>

Based on the manual section I quoted before, What is exactly my
misunderstanding? I think it says that selecting multiple lines *in a
text mode buffer* and hitting <TAB> should produce an indentation of
every line. Isn't that right?


> What you want to do can be done with rectangle mode, so
> - select the region you want
> - C-x r t RET TAB
> and you're done
>

Yes, I know that way of indenting several lines, but IMO it's too
laborious. I'd like to have a more agile way.


--
Dani Moncayo

Dani Moncayo

unread,
Mar 6, 2011, 6:50:52 AM3/6/11
to Peter Dyballa, help-gn...@gnu.org
On Sat, Mar 5, 2011 at 23:01, Peter Dyballa <Peter_...@web.de> wrote:
>
> Am 05.03.2011 um 00:17 schrieb Dani Moncayo:
>
>> Am I missing something?
>
> Yes: many new meanings of <TAB>. (I try not use it that often, so I can't do
> what the documentation can: explain them.)
>
My reasoning was based on the manual section I quoted before. It
explains the behavior of <TAB> in text mode buffers, but as I said, I
don't experience that behavior in practice.


--
Dani Moncayo

Peter Dyballa

unread,
Mar 6, 2011, 8:50:19 AM3/6/11
to Dani Moncayo, help-gn...@gnu.org

Am 06.03.2011 um 12:47 schrieb Dani Moncayo:

> Based on the manual section I quoted before, What is exactly my
> misunderstanding? I think it says that selecting multiple lines *in a
> text mode buffer* and hitting <TAB> should produce an indentation of
> every line. Isn't that right?


The *scratch* buffer is not a text-mode buffer (it is meant for Elisp
code scratches, for testing programme code for GNU Emacs). Open <some
file>.txt and see again!

--
Greetings

Pete

The world would be a better place if Larry Wall had been born in
Iceland, or any other country where the native language actually has
syntax.
– Peter da Silva


Dani Moncayo

unread,
Mar 6, 2011, 9:12:11 AM3/6/11
to Peter Dyballa, help-gn...@gnu.org
On Sun, Mar 6, 2011 at 14:50, Peter Dyballa <Peter_...@web.de> wrote:
>
> The *scratch* buffer is not a text-mode buffer (it is meant for Elisp code
> scratches, for testing programme code for GNU Emacs). Open <some file>.txt
> and see again!
>

My second step (after starting emacs) was to set text mode in the
scratch buffer, remember?.

I don't care about what buffer you are in, as long as you are in *text mode*.


--
Dani Moncayo

Pascal J. Bourguignon

unread,
Mar 6, 2011, 9:18:42 AM3/6/11
to
Peter Dyballa <Peter_...@Web.DE> writes:

> Am 06.03.2011 um 12:47 schrieb Dani Moncayo:
>
>> Based on the manual section I quoted before, What is exactly my
>> misunderstanding? I think it says that selecting multiple lines *in a
>> text mode buffer* and hitting <TAB> should produce an indentation of
>> every line. Isn't that right?
>
>
> The *scratch* buffer is not a text-mode buffer (it is meant for Elisp
> code scratches, for testing programme code for GNU Emacs). Open <some
> file>.txt and see again!

As soon as you type M-x text-mode RET in the *scratch* buffer, it
becomes a text buffer.

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

Gregor Zattler

unread,
Mar 6, 2011, 11:30:08 AM3/6/11
to help-gnu-emacs
Hi Dani,
* Dani Moncayo <dmon...@gmail.com> [05. Mar. 2011]:

> - The selected lines are not not moved at all.

As discussed in this thread this is a regression. It works in
Emacs 23.2. but not in Emacs 24.0.50 ... I filed a bug report:

24.0.50; Regression: TAB does not indent region
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8187

> - The region is deactivated.

Regarding this issue I filed a wishlist bug:

indenting region with TAB deactivates region
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8189


Ciao, Gregor
--
-... --- .-. . -.. ..--.. ...-.-

Dani Moncayo

unread,
Mar 6, 2011, 11:50:09 AM3/6/11
to help-gnu-emacs

Thanks, let's see what the maintainers say.


--
Dani Moncayo

Uday Reddy

unread,
Mar 6, 2011, 12:58:53 PM3/6/11
to
On 3/5/2011 8:26 PM, Andrea Crotti wrote:

>> What I see:
>> - The selected lines are not not moved at all.
>> - The region is deactivated.
>>
>> Please, could someone explain this? Am I missing something? (I guess I
>> am, and that's why I'm posting to help-gnu-emacs instead of
>> bug-gnu-emacs)

The region getting deactivated is part of the design. Funny that nobody
seems to have mentioned it. Most operations that make use of the active
mark deactivate it. You have to activate it again if you want to repeat
some operation. C-xC-x is a good way of doing so.

The selected lines not moving seems to be a bug in the development
version. In the current release, 23.2, the lines are moving the first
time, but they are moving correctly a second time. So, that is buggy as
well. Sigh...

In any case, the traditional way of moving a region of text is to use
`indent-rigidly' (C-x TAB). You can give it a prefix argument, e.g.,
M-10, to say indent 10 spaces.

Cheers,
Uday

Dani Moncayo

unread,
Mar 6, 2011, 2:17:11 PM3/6/11
to Uday Reddy, help-gn...@gnu.org
On Sun, Mar 6, 2011 at 18:58, Uday Reddy <uDOTsD...@cs.bham.ac.uk> wrote:
>
> The region getting deactivated is part of the design.  Funny that nobody
> seems to have mentioned it.  Most operations that make use of the active
> mark deactivate it.  You have to activate it again if you want to repeat
> some operation.  C-xC-x is a good way of doing so.
>
> The selected lines not moving seems to be a bug in the development version.
>  In the current release, 23.2, the lines are moving the first time, but they
> are moving correctly a second time.  So, that is buggy as well.  Sigh...
>
> In any case, the traditional way of moving a region of text is to use
> `indent-rigidly' (C-x TAB).  You can give it a prefix argument, e.g., M-10,
> to say indent 10 spaces.
>

Ah, good. Thanks for the info.

The way you've mentioned works, but IMO it has two drawbacks:
- It is a bit cumbersome to type C-u _number_ C-x <TAB> each time you
want to indent a paragraph.
- It is not "interactive": i.e. Many times you don't know beforehand
the value of _number_. So,
it would be nice if you could make several indentations in a row
while seeing the new position
of the text at the end of each one.

Thus, I think it would be nice to have a way of indenting the active
region that didn't have the above drawbacks.


--
Dani Moncayo

Drew Adams

unread,
Mar 6, 2011, 2:44:26 PM3/6/11
to Dani Moncayo, Uday Reddy, help-gn...@gnu.org
> The way you've mentioned works, but IMO it has two drawbacks:
> - It is a bit cumbersome to type C-u _number_ C-x <TAB> each time you
> want to indent a paragraph.

C-u 3 C-x TAB C-x z z z z ...
indents 3 chars each time you hit z

> - It is not "interactive": i.e. Many times you don't know beforehand
> the value of _number_. So, it would be nice if you could make
> several indentations in a row while seeing the new position of the
> text at the end of each one.

If you don't know the number of chars to indent, then start with 1:

C-x TAB C-x z z z ...

It is easy to hold down `z', no?

And if you go too far, hit `C-- C-x z z z...' to come back.


Dani Moncayo

unread,
Mar 6, 2011, 2:42:57 PM3/6/11
to Teemu Likonen, Uday Reddy, help-gn...@gnu.org
On Sun, Mar 6, 2011 at 20:27, Teemu Likonen <tlik...@iki.fi> wrote:

> * 2011-03-06 20:17 (+0100), Dani Moncayo wrote:
>
>> The way you've mentioned works, but IMO it has two drawbacks:
>>  - It is a bit cumbersome to type C-u _number_ C-x <TAB> each time you
>> want to indent a paragraph.
>>  - It is not "interactive": i.e. Many times you don't know beforehand
>> the value of _number_. So,
>>    it would be nice if you could make several indentations in a row
>> while seeing the new position
>>    of the text at the end of each one.
>
> You can type "C-x TAB" once and then repeat it with "C-x z".
>

Indeed, that is another solution, but IMO has it's own drawbacks:
- As shown, the indentation is made by steps of 1 space.
- If you use a prefix argument (to avoid the above problem), it
becomes cumbersome.

The complexity of this method is also higher than having a simple,
easy to type command that indents the region to the next tab stop and
can be repeated several times in a row.

--
Dani Moncayo

Teemu Likonen

unread,
Mar 6, 2011, 2:27:53 PM3/6/11
to Dani Moncayo, Uday Reddy, help-gn...@gnu.org

Dani Moncayo

unread,
Mar 6, 2011, 3:57:20 PM3/6/11
to Drew Adams, Uday Reddy, help-gn...@gnu.org, Teemu Likonen
On Sun, Mar 6, 2011 at 21:26, Drew Adams <drew....@oracle.com> wrote:
>> > You can type "C-x TAB" once and then repeat it with "C-x z".
>>
>> Indeed, that is another solution, but IMO has it's own drawbacks:
>>  - As shown, the indentation is made by steps of 1 space.
>>  - If you use a prefix argument (to avoid the above problem), it
>>    becomes cumbersome.
>>
>> The complexity of this method is also higher than having a simple,
>> easy to type command that indents the region to the next tab stop and
>> can be repeated several times in a row.
>
> (defun incremental-tab (arg)
>  (interactive "P")
>  (require 'repeat)
>  (let ((repeat-message-function  'ignore))
>    (setq last-repeatable-command  'indent-rigidly)
>    (repeat nil)))
>
> (define-key ctl-x-map "\t" 'incremental-tab)
>
> Or if `C-x TAB TAB...' is too much for you, hold down `f5':
>
> (global-set-key [f5] 'incremental-tab)
>
> Hit `C--' at any time to reverse, `C-1' to reverse back again:
>
> `f5 f5 f5 f5 C-- f5 f5 C-1 f5'...
>
>

Thanks, Drew! (I have to find the time to learn elisp... :) )

You've implemented a solution for this problem, but what do you think
about my original question in this thread, i.e., the behavior of the
<TAB> key in text mode, in the current Emacs trunk? Do you understand
it? Does the manual describes it well?

--
Dani Moncayo

Drew Adams

unread,
Mar 6, 2011, 3:26:39 PM3/6/11
to Dani Moncayo, Teemu Likonen, Uday Reddy, help-gn...@gnu.org

Teemu Likonen

unread,
Mar 6, 2011, 4:44:01 PM3/6/11
to Dani Moncayo, help-gn...@gnu.org
* 2011-03-06 20:42 (+0100), Dani Moncayo wrote:

> Indeed, that is another solution, but IMO has it's own drawbacks:
> - As shown, the indentation is made by steps of 1 space.
> - If you use a prefix argument (to avoid the above problem), it
> becomes cumbersome.
>
> The complexity of this method is also higher than having a simple,

> easy to type command that indents the region to the next tab stop and
> can be repeated several times in a row.

Do you mean the the next tab stop according to tab-stop-list variable?
If the indentation of lines in the current region differs between lines,
which line should be indented to the next tab stop position? Maybe the
one with the smallest amount of indentation (excluding blank lines)?
Here's a quick example:


(defun my-region-indentation (beg end)
(let (indent)
(save-excursion
(goto-char beg)
(while (re-search-forward "^\\s-*[[:print:]]" end t)
(setq indent (min (or indent (current-indentation))
(current-indentation)))))
indent))


(defun my-indent-region-next-tab-stop (beg end)
"Indent region forward to the next tab stop."
(interactive "r")
(let* ((current (my-region-indentation beg end))
(next (catch 'answer
(dolist (i tab-stop-list 0)
(when (> i current)
(throw 'answer i))))))
(indent-rigidly beg end (- next current))))


(defun my-indent-region-previous-tab-stop (beg end)
"Indent region backward to the previous tab stop."
(interactive "r")
(let* ((current (my-region-indentation beg end))
(prev (catch 'answer
(dolist (i (reverse (append (list 0) tab-stop-list)) 0)
(when (< i current)
(throw 'answer i))))))
(indent-rigidly beg end (- prev current))))


(global-set-key [f5] #'my-indent-region-previous-tab-stop)
(global-set-key [f6] #'my-indent-region-next-tab-stop)

Drew Adams

unread,
Mar 6, 2011, 4:42:01 PM3/6/11
to Dani Moncayo, Uday Reddy, help-gn...@gnu.org, Teemu Likonen
> Thanks, Drew! (I have to find the time to learn elisp... :) )
>
> You've implemented a solution for this problem, but what do you think
> about my original question in this thread, i.e., the behavior of the
> <TAB> key in text mode, in the current Emacs trunk? Do you understand
> it? Does the manual describes it well?

I haven't followed this thread. But reading your original post and trying Emacs
-Q (on Windows), I agree with you, PJ, and Le that this seems to be a bug. I
tried a few versions, none of which seem to have the currently documented
behavior:

Emacs 22 - but the behavior matches the then-documented behavior, so OK.

Emacs 23 and 24 - behavior is more or less as described except for this: the
region is deactivated, so you cannot hit TAB again to indent more (you must use
`C-x C-x' first). Le Wang already mentioned this.

I'm also not sure about the "advance...to next tab stop" thing. Different lines
in the region can get indented different amounts, especially if repeating TAB
(after C-x C-x) after the first TAB indents to align with the first
non-whitespace char of the previous line.

I suggest you file a bug. Emacs developers will let you know whether they agree
that it is a bug. If they agree, they will decide whether the behavior should
change to fit the doc, vice versa, or some combination. If they disagree, it
might still be the case that the doc could be improved to prevent
misunderstanding.

---

In general (not just for you or this thread), my advice is to not hesitate to
file a bug report. Better to discuss such things in a bug-report thread than
here. This list is for helping and getting help.

Obviously, if you are (i.e., one is) unsure what something should do then there
is a gray area, but there is no reason (IMHO) to hesitate to file a bug report.

If you have read the doc and are still unsure what the behavior should be, then
there's a good chance that at least the doc could be improved. Letting the
developers know what is unclear to you, no matter what your level, can help
everyone.


Le Wang

unread,
Mar 7, 2011, 12:04:09 AM3/7/11
to Dani Moncayo, help-gn...@gnu.org
On Sun, Mar 6, 2011 at 7:47 PM, Dani Moncayo <dmon...@gmail.com> wrote:
Yes, I know that way of indenting several lines, but IMO it's too
laborious. I'd like to have a more agile way.

 My comment about cua-mode rectangles seems to have gottel lost in the shuffle.   IMO, this is the "agile" way to get exactly what you want.

1. evaluate (assuming you want no part of cua bindings)

(setq cua-enable-cua-keys 'emacs)
  ;; <kp-enter> rotates around the rectangle corners, if "RET" gets overriden
(cua-selection-mode 1)
2. select region you want, press C-enter, and your selection becomes a rectangle.   If the point isn't on the left side of the rectangle, press Enter until it moves there.

3. press Tab, space, backspace, whatever to change the indentation.  cua-mod rectangle remains selected.

--
Le

Dani Moncayo

unread,
Mar 7, 2011, 2:32:19 AM3/7/11
to Le Wang, help-gn...@gnu.org

Sorry for missing your advice, Le.

Indeed your way works and it's ease to use.

Anyway, It seems that the behavior of <TAB> is broken in the trunk,
and also in Emacs 23, so that when that is fixed, we'll be able to
indent paragraphs (in text mode), the way I was expecting (and is
documented).

Thanks for your advice!

--
Dani Moncayo

Teemu Likonen

unread,
Mar 7, 2011, 3:18:26 AM3/7/11
to Dani Moncayo, help-gn...@gnu.org
* 2011-03-06 23:44 (+0200), Teemu Likonen wrote:

> Do you mean the the next tab stop according to tab-stop-list variable?
> If the indentation of lines in the current region differs between
> lines, which line should be indented to the next tab stop position?
> Maybe the one with the smallest amount of indentation (excluding blank
> lines)? Here's a quick example:

I found that feature quite useful so I wrote a proper version. I bind it
to "C-x TAB" since this pretty much supersedes indent-rigidly. See the
command's documentation (below) for more info.


(global-set-key (kbd "C-c 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)))
(end (progn (goto-char end) (line-end-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-next-tab-stop (beg end)
(let* ((current (tl-region-indentation beg end))
(next (catch 'answer
(dolist (i tab-stop-list (or (car (last tab-stop-list)) 0))


(when (> i current)
(throw 'answer i))))))
(indent-rigidly beg end (- next current))))


(defun tl-indent-region-previous-tab-stop (beg end)
(let* ((current (tl-region-indentation beg end))
(prev (catch 'answer
(dolist (i (reverse (cons 0 tab-stop-list)) 0)


(when (< i current)
(throw 'answer i))))))
(indent-rigidly beg end (- prev current))))


(defun tl-indent-region-engine (beg end arg)
(interactive "r\nP")
(let ((current (tl-region-indentation beg end)))
(cond ((not arg)
(tl-indent-region-next-tab-stop beg end))
((eq arg '-)
(tl-indent-region-previous-tab-stop beg end))
(t
(indent-rigidly beg end (prefix-numeric-value arg))))))


(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'. If ARG is negative indent the region to the
previous tab stop column. If ARG is a positive or negative
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")
(let ((repeat-message-function #'ignore))
(setq last-repeatable-command #'tl-indent-region-engine)
(repeat nil)))

Le Wang

unread,
Mar 7, 2011, 8:42:19 AM3/7/11
to Teemu Likonen, help-gn...@gnu.org
On Mon, Mar 7, 2011 at 4:18 PM, Teemu Likonen <tlik...@iki.fi> wrote:

...
 
 (let ((repeat-message-function #'ignore))
   (setq last-repeatable-command #'tl-indent-region-engine)
   (repeat nil)))


Wow, this repeat bit is a /COOL/ trick.  I'll have to file this snippet away.  Region stays active, and deactivates when repeating stops (no mucking with deactivate-mark manually) ... very cool.

Thanks for sharing!


--
Le

Le Wang

unread,
Mar 7, 2011, 9:38:37 AM3/7/11
to Teemu Likonen, help-gn...@gnu.org
Teemu, one bug in the code is that you need to call (require 'repeat) at the beginning, otherwise when it gets autoloaded later `repeat-message-function' doesn't get initialized properly because of the "(let ..." binding.


--
Le

Teemu Likonen

unread,
Mar 7, 2011, 9:52:17 AM3/7/11
to Le Wang, help-gn...@gnu.org
* 2011-03-07 22:38 (+0800), Le Wang wrote:

> Teemu, one bug in the code is that you need to call (require 'repeat)
> at the beginning, otherwise when it gets autoloaded later
> `repeat-message-function' doesn't get initialized properly because of
> the "(let ..." binding.

Thanks. I have made some other adjustments too, so here's a new version:


(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'. If ARG is negative indent the region to the
previous tab stop column. If ARG is a positive or negative
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)

Drew Adams

unread,
Mar 7, 2011, 10:04:13 AM3/7/11
to Le Wang, Teemu Likonen, help-gn...@gnu.org
(let ((repeat-message-function 'ignore))
(setq last-repeatable-command 'indent-rigidly)
(repeat nil)))

> Wow, this repeat bit is a /COOL/ trick. I'll have to file this
> snippet away. Region stays active, and deactivates when
> repeating stops (no mucking with deactivate-mark manually)
> ... very cool. Thanks for sharing!

You're welcome. It dawned on me one day, and I've used it a lot ever since.

Actually, I define a repeatabilizer function like this:

(defun bmkp-repeat-command (command)
"Repeat COMMAND."
(let ((repeat-message-function 'ignore))
(setq last-repeatable-command command)
(repeat nil)))

Then I pass any number of ordinary, non-repeatable commands to that, to create
repeatable versions of them. Then I bind the repeatable ones. Example (from
Bookmark+):

(defun bmkp-next-bookmark-repeat (arg) ; `C-x p right', `C-x p f'
"Jump to the Nth-next bookmark in the bookmark navigation list.
This is a repeatable version of `bmkp-next-bookmark'.
N defaults to 1, meaning the next bookmark.
Plain `C-u' means start over at the first bookmark (and no repeat)."


(interactive "P")
(require 'repeat)

(bmkp-repeat-command 'bmkp-next-bookmark))

(define-key bookmark-map [right] 'bmkp-next-bookmark-repeat)
(define-key bookmark-map "f" 'bmkp-next-bookmark-repeat)

You can put a repeatable command on a prefix key, to save keys. For example, in
Bookmark+ `bookmark-map' is bound to the prefix key `C-x p' - it is available by
default for all bookmark commands.

There are several repeatable commands on this prefix key: `C-x p f', `C-x p
right', `C-x p down', etc. So you can use `C-x p f f f f f f f'... to cycle one
thing, `C-x p down down down'... to cycle another, etc., and still have lots of
other, non-repeatable keys on the same prefix `C-x p'.

You can even put (repeatable) mouse-wheel rotations on a prefix key:

(define-key bookmark-map (vector (list mouse-wheel-up-event))
'bmkp-next-bookmark-this-buffer-repeat)

Using a common prefix key gives users a quick way to see all of the related
default key bindings: `C-x p C-h'. (They can always define shortcut keys if
they want.)

Here is an example where `s' is both a prefix key and a suffix for the prefix
key (different keymap here):

(defun bmkp-bmenu-change-sort-order-repeat (arg) ; `s s'... in bookmark list
"Cycle to the next sort order.
With a prefix arg, reverse current sort order.
This is a repeatable version of `bmkp-bmenu-change-sort-order'."


(interactive "P")
(require 'repeat)

(bmkp-repeat-command 'bmkp-bmenu-change-sort-order))

(define-key bookmark-bmenu-mode-map "ss"
'bmkp-bmenu-change-sort-order-repeat)

Here is a related thread based on this idea of using a prefix key as its own
suffix:
http://lists.gnu.org/archive/html/emacs-devel/2009-08/msg01153.html


Drew Adams

unread,
Mar 7, 2011, 10:13:16 AM3/7/11
to Le Wang, Teemu Likonen, help-gn...@gnu.org
> Teemu, one bug in the code is that you need to call (require 'repeat)
> at the beginning, otherwise when it gets autoloaded later
> `repeat-message-function' doesn't get initialized properly because
> of the "(let ..." binding.

Yes, repeat.el needs to be loaded.

Teemu presumably got the code from my prior message, where the repeatable
command `incremental-tab' does indeed call (require 'repeat). He neglected to
copy that part. You've pointed out one reason it's needed.


Stefan Monnier

unread,
Mar 7, 2011, 11:09:02 AM3/7/11
to
> I found that feature quite useful so I wrote a proper version. I bind it
> to "C-x TAB" since this pretty much supersedes indent-rigidly. See the

Indeed, it sounds like a good improvement to the behavior of C-x TAB.
Maybe you could propose it for inclusion via M-x report-emacs-bug.


Stefan

Teemu Likonen

unread,
Mar 7, 2011, 12:02:45 PM3/7/11
to Stefan Monnier, help-gn...@gnu.org

Indeed, I will. Others may find it useful too.

Perry Smith

unread,
Mar 7, 2011, 4:58:31 PM3/7/11
to GNU Emacs List

On Mar 6, 2011, at 3:42 PM, Drew Adams wrote:

> Better to discuss such things in a bug-report thread than
> here. This list is for helping and getting help.

I've enjoyed and learned about at least two commands
from this thread so this thread *is* helping others.

Its amazing to me... I've used emacs starting with Gosling's
(CCA) emacs and moving to GNU when it was first released
and I bet I know (or am aware of) far less than half of
what emacs can do out of the box.

pedz


Drew Adams

unread,
Mar 7, 2011, 5:14:05 PM3/7/11
to Perry Smith, GNU Emacs List
> > Better to discuss such things in a bug-report thread than
> > here. This list is for helping and getting help.
>
> I've enjoyed and learned about at least two commands
> from this thread so this thread *is* helping others.

Yes, of course. I meant only that the discussion of the bug itself is
appropriate for the bug list. As proof, note that the bug as finally reported
did not mention the particular doc section that is problematic etc., so the bug
thread eventually pointed to this help-gnu-emacs thread for clarification.

> Its amazing to me... I've used emacs starting with Gosling's
> (CCA) emacs and moving to GNU when it was first released
> and I bet I know (or am aware of) far less than half of
> what emacs can do out of the box.

Me too, on all accounts. We are all newbies wrt some things.


0 new messages