help-gnu-emacs
[Top][All Lists]
Advanced

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

Re: How to write the "interactive" form for a command acting on a region


From: Marcin Borkowski
Subject: Re: How to write the "interactive" form for a command acting on a region
Date: Wed, 14 Jan 2015 00:06:27 +0100

On 2015-01-13, at 23:38, Pascal J. Bourguignon <pjb@informatimago.com> wrote:

> Marcin Borkowski <mbork@wmi.amu.edu.pl> writes:
>
>> Hi all,
>>
>> so I want to have a function which should do something on the region.
>> If no region is active, I want it to act on the whole buffer.  If called
>> from Lisp code, I want to be able to supply "begin" and/or "end"
>> parameters, which (if nil) should default to (point-min) and
>> (point-max).  Finally, I want my command to behave differently depending
>> on whether it was called interactively or programmatically.  
>
> If you want a different behavior, then you should have different
> functions:

Why?  In many Emacs functions/commands it works like what I want to
have.  What's wrong with this approach?  And in fact, I /don't/ want
different behavior: I want both the function and the command to
(essentially) do the same, with the (minor) difference that the function
will return a value and the command will print a message.

>     (defun my-FUNCTION (…)
>        …)
>
>     (defun my-COMMAND (…)
>        (interactive …)
>
>        (my-function …)
>        …)
>
> (defun my-command (start end)
>    (interactive "r")
>    (message "start=%s end=%s" start end))
>
> A region is always defined, whether transient-mark-mode is on or off,
> and whether the region is active or not.

Yes, of course.  (Incidentally, I didn't notice your snippet above at
first, and just to make sure, I wrote an identical one, differing only
in the names of the parameters and the text of the message;-).)

> Therefore interactive "r" will always give you start and end points.
> You could have a command such as:
>
>     (defun my-command (start end)
>        (interactive "r")
>        (if (use-region-p) ; region is active
>           (my-function start end)
>           (my-function (point-min) (point-max))))

This does not seem very lispy to me, though most probably have much less
experience than you...

> Otherwise, if the behavior of your command and your function was the
> same, you could write a single command, using (require 'cl) to deal with
> the default values.  

I'll have to check cl (I use it anyway for (incf)), but again: what's
wrong with (or start (point-min))?

> But since you want to force the arguments when it's called interactively
> without an active region, you will have to duplicate some code.

This I don't understand.  (Though I /do/ have some duplication, see
below.)

> Separating the function and command is probablyh preferable in your
> situation.
>
>     (require 'cl)
>     (defun* my-command (&optional (start (point-min)) (end (point-max)))
>        (interactive "r")
>        (when (and (called-interactively-p)
>                   (not (use-region-p)))
>           (setf start (point-min)
>                 end   (point-max)))
>        …)

No offence, but this seems plain ugly for me, especially the setf part.

IMHO, using the (interactive) form to define default arguments is more
elegant, though of course I also have some duplicate code (point-min and
point-max appear twice - though for different reasons, so to speak -
which I don't like).  I can't see why your proposal is better - I would
prefer to use defun and not defun*, and the Emacs manual says it's
better to use the interactive form and not called-interactively-p (and
I can see the reason).

Regards,

-- 
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Faculty of Mathematics and Computer Science
Adam Mickiewicz University



reply via email to

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