4

I have a pattern like this scattered all over my .emacs:

(defun my/function ()
   (interactive)
   (....stuff)
)

I would like to write a idefun macro so I could write as following instead:

(idefun my/function () 
   (... stuff)
)

So far, based on my previous ilambda macro post, I tried this business:

   (defmacro idefun (name para &rest body) 
       `(defun ,name ,para (interactive) ,body))


   (idefun my/idefun-test ()
            (message "defun function"))

   ;I would like it to translate to:
   ;(defun my/idefun-test ()
   ;         (interactive)
   ;         (message "defun function")
   ;  )

Now 'my/idefun-test' is listed under M-x, but when running it tells me 'invalid function'.

I have two questions/requests:
1) Does anyone know how to get the above to work?
2) Would it be possible to implement a version that conditionally inserts function documentation if the first item is a string? (like in the lambda post)I.e:

(idefun my/test () "function docu" (message "MEH"))
Should translate to:
(define my/test () "function docu" (interactive) (message "MEH"))

[EDIT SOLUTION]
NOTE: It is not reccomended to use a macro like this in a public package/library as it may lead to confusion. But for a personal .emacs it might just about prevent rsi.

Based on the answer below, I pieced together the following working macro:

(defmacro idefun (name para docOrBody &rest body)
  (if (and (stringp docOrBody) body) ;if first arg is a string type
  ;then
  `(defun ,name ,para
     ,docOrBody ;this is the function documentation string in this case.
     (interactive)
     ,@body)
  ;else
  `(defun ,name ,para
     (interactive)
     ,docOrBody ,@body)) ;otherwise it is the body.
  )

;-------
;Examples follow
;-------
(idefun my/id2 ()
         (message "it works"))
(idefun my/id2-with-docu ()
         "Function documentation"
         (message "it works with docu"))

(idefun my/id2-args (a)
        (message a))

(idefun my/hello-moto ()
    "Function docu :-D!"
    (message "Hello moto"))

(global-unset-key (kbd "<f8>"))
(global-set-key (kbd "<f8>") 'my/hello-moto)

;This is funny if read out loud.
(idefun u () (message "I am your father"))
  • 1
    You should not do this, unless it keeps you from writing a massive amount of boilerplate. Avoiding to write (interactive) is not worth it. Also those reading your code do know what (interactive) means but have no idea what idefun does. – tarsius Mar 27 '15 at 0:34
  • Well, this is primarily for my personal .emacs file, not for public libraries. My .emacs file isn't that popular among folks and those who do care to read it will see the macro at the top of the document :-). I have something like 100 (defun .. (interactive) in my .emacs, time to consolidate things. – Leo Ufimtsev Mar 27 '15 at 1:11
  • I.e, I do agree that a macro like this should not be used in public libraries/plugins. But for personal .emacs hacking it should be ok I think. – Leo Ufimtsev Mar 27 '15 at 1:12
  • @tarsius thank you for your feedback in any case. – Leo Ufimtsev Mar 27 '15 at 1:12
  • 1
    Well yes, nobody forbids that you do this of course :-) – tarsius Mar 27 '15 at 1:15
5

1) Does anyone know how to get the above to work?

macroexpand-1 is your friend. Let's se what we get by running it:

(macroexpand-1 '(idefun my/test () (message "MEH")))
;; => (defun my/test nil (interactive) ((message "MEH")))

Do you see the problem with that? There's an extra pair of parentheses around the message call. That's because the &rest body argument is a list of all arguments passed (besides the first two, of course).

You need to splice that list into the body of the defun (note the extra @):

(defmacro idefun (name para &rest body) 
  `(defun ,name ,para
     (interactive)
     ,@body))

2) Would it be possible to implement a version that conditionally inserts function documentation if the first item is a string? (like in the lambda post)I.e:

Yes, you can do it the same way as in this answer to the question you linked. A defun is not that different from a lambda. The same technique should work.

  • :-D! Thank you for the explanation of my error oh wise elisp master Malabarba. With your feedback I got the macro to work. (I edited my question). – Leo Ufimtsev Mar 27 '15 at 1:10
  • You should probably rename para to arglist. – tarsius Mar 27 '15 at 1:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.