From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: "Pascal J. Bourguignon" Newsgroups: gmane.emacs.help Subject: Re: How to write the "interactive" form for a command acting on a region Date: Wed, 14 Jan 2015 03:04:41 +0100 Organization: Informatimago Message-ID: <87lhl6w212.fsf@kuiper.lan.informatimago.com> References: <87twzuwbk7.fsf@kuiper.lan.informatimago.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: ger.gmane.org 1421201725 14995 80.91.229.3 (14 Jan 2015 02:15:25 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 14 Jan 2015 02:15:25 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Wed Jan 14 03:15:21 2015 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1YBDUP-00042S-04 for geh-help-gnu-emacs@m.gmane.org; Wed, 14 Jan 2015 03:15:21 +0100 Original-Received: from localhost ([::1]:42190 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YBDUO-0001wL-Ab for geh-help-gnu-emacs@m.gmane.org; Tue, 13 Jan 2015 21:15:20 -0500 Original-Path: usenet.stanford.edu!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 139 Original-X-Trace: individual.net iH9ruOQEkbgNu6kBJq/qSgnVSJJXrv5RlFTAazFOlDqdFtyXvg Cancel-Lock: sha1:ZDU5ZDhhOThiZTk0ZjQzMjkzOTRhODA1NDk3YTMwZmE4OWFiMWYwYQ== sha1:UKtX9SfBpzO6dno8l5Ia3gX30P0= Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) Original-Xref: usenet.stanford.edu gnu.emacs.help:209780 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:102059 Archived-At: Marcin Borkowski writes: > On 2015-01-13, at 23:38, Pascal J. Bourguignon wrote: > >> 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. Indeed, the question is how you define _different_ behavior, and whether you really have a different behavior or not. Usually you need just to be able to run the function interactively easily. (You can always use M-: to call a function interactively, eg.: M-: (my-function (point-min) (point-max)) RET if you don't have a command to do that. >> 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... Notice how short this command is (it's always good to write short functions and commands). But more importantly, I feel that emacs lisp code would benefit in using a more abstracted and layered approach. The requirements of a functional API are not the same as of a user interface command set. This is why you could want to define a set of data structures and functions, and later add a command layer calling those functions, with variants such as in this my-command example. We could assume that my-function could be used also by other functions or other commands. In any case, if the code of my-function was put inside my-command, instead of being factored out, it would become much harder to use my-command from other functions or commands (perhaps those other commands or functions really want to work on the whole buffer even when there's an active region). When you see a command in emacs that has hundreds of lines of code (and where the best "abstraction" they can do is: (defun bad-command (…) (interactive …) … hundreds of lines … (bad-command-1 …)) (defun bad-command-1 (…) … hundreds of lines … (bad-command-2 …)) (defun bad-command-2 (…) … hundreds of lines …) and there are more than one such bad examples :-(, well, this is not good at all. >> 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))? Nothing wrong. Just that (interactive "r") will never pass nil for start or end. Notice that you can also just use (interactive) and (region-beginning) and (region-end) inside the command. But then one might worry about commands that don't declare with interactive the parameters they use and require from the user. If you can declare them with interactive, it's better. >> 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.) In this case, the duplication is minime, since it's only the (setf start (point-min) end (point-max)) in the code, and hidden in the lambda list. >> 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. Absolutely. This works better when you don't need this called-interactive-p case. > 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). I hope we all do. -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk