[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