1

I am having difficulty seeing how to properly use function arguments with the interactive command.

Suppose I have a function with three arguments myfunc (arg1 &optional arg2 arg3), the last two being optional. In what circumstances does one need the interactive part to fill the values for arg1, arg2 and arg3?

In the case of the prefix argument, does one need to include the prefix argument as a function argument?

It looks to me that besides make a function into interactive command, the interactive expression provides a mechanism for passing arguments to the function when called interactively.

(defun change-theme (theme)
  (interactive "a Theme Name: ")
  ...)

(defun history (&optional prefix)
  (interactive "P"))

But then one can use things like completing-read and read-from-minibuffer that can be saved to a variable. This gives the same utility as interactive does for the user to enter some input.

(defun cursor-setting ()
  (interactive)
  (let* ( (cseq '("bar" "hbar" "hollow" "box"))
          (csel  (completing-read "Cursor: " cseq nil t "box")) ))

But then I can also do

(interactive
 (let ((string (read-string "Foo: " nil 'my-history)))
   (list (region-beginning) (region-end) string)))

where read-string is called inside the interactive command.

One can also use a list as here

(interactive
 (list 
    (read-string "Remote host: ")
    (read-string "Remote filename: ")))

I am finding the interactive command as one of the most complicated to use.

The following is an important example. I would think that although the example works, the implementation is quite bad. Because whilst one can use it interactively, it is not advisable to use it in a non-interactive way because of the call to read-from-minibuffer, even though the function would still work.

I wonder whether it is a requirement for all interactive functions to always allow a non-interactive call.

(defun workbench (&optional prefix)
  "Make new temporary buffer manually using user input."

  (interactive "P")

  (cond

   ;; -------------------------------------------------
   ((equal current-prefix-arg nil)   ; no C-u

    (message "no C-u")
    (setq thote 1))

   ;; -------------------------------------------------
   ((equal current-prefix-arg '(4))  ; C-u

    (message "no C-u")
    (arktika-automated-workbench))

   ;; -------------------------------------------------
   ((equal current-prefix-arg 1)     ; C-u 1

    (message "C-u 1")
    (let* ( (name (read-from-minibuffer " Name: ")) )
      (arktika-automated-workbench name))))
7
  • 1
    Which part is confusing, and what have you tried so far?
    – phils
    Commented Jul 3, 2022 at 8:52
  • It is not really important what I have tried. What is important is to know some general rules to follow. Will put some detail.
    – Dilna
    Commented Jul 3, 2022 at 8:59
  • For instance, suppose I use the prefix argument (interactive "P"), would I need to provide an function argument for the prefix? What would be the difference whether the argument is optional or not?
    – Dilna
    Commented Jul 3, 2022 at 9:20
  • 1
    I have provided an answer to your related other question here. I think that answer mostly answers this question also. But it will probably help to note again that you should consider that interactive function (i.e. commands) can also be called non-interactively. So think about what would be the behavior in that case. Considering this option combined with the info in the other answer, I guess you should be able to figure out what is the best way to go. So just try writing your functions and with time/experience you will find the best way. Commented Jul 3, 2022 at 9:54
  • 2
    "It is not really important what I have tried" -- You are expected to show what you know so far, and your efforts to date. You have asked a lot of questions in recent times, so at this point it is only reasonable for you to have made some efforts to solve your problems, and to show what you have tried. Please refer to emacs.stackexchange.com/help/how-to-ask and make sure you are providing the information you know so far.
    – phils
    Commented Jul 3, 2022 at 11:07

1 Answer 1

2

In your case, the interactive form only needs to pass one argument.

For example:

(defun my-func-one (arg1 &optional arg2 arg3)
  (interactive "P")
  (message "%s %s %s" arg1 arg2 arg3))

In the my-func-one case, the interactive form only fills in the arg1 argument. Argument arg2 and arg3 will be set to nil. For example, calling C-u M-x my-func-one RET yields (4) nil nil.

(defun my-func-three (arg1 &optional arg2 arg3)
  (interactive "P\nd\nm")
  (message "%s %s %s" arg1 arg2 arg3))

For my-func-three, the interactive clause pass three arguments, P pass the raw universal argument value, d is the value of the point and m the mark. C-u M-x my-func-three RET could yield (4) 1630 1440.

Some side comments:

  • You use interactive to make a function into a command. However, you can still call it as a function.

  • If you want to read arguments regardless if you call it as a command or as a function, you could read the arguments in the body of the function. However, in most cases, you would like to design the function so that it gets its input via its arguments. In this case, the interactive clause is only used to read the arguments when the called as a command.

  • You can use the code form of interactive when the string form isn's powerful enough. For example, (interactive "d\nm") is equivalent to (interactive (list (point) (mark))). However, in the code form you can use code anyway you want, e.g. read values using auto completion the string form can't handle.

9
  • You have mentioned something I have been struggling with. The fact that one can read arguments in the body of the function rather than inside an interactive expression. I have found that there are endless ways of handling user input. Because even if the function is called non-interactively, one can still call interactive functions that accept user input from the minibuffer.
    – Dilna
    Commented Jul 3, 2022 at 18:10
  • 1
    True, but as I said, the common way it to make the function only read arguments when called as a command not as a function. However, Emacs lisp allows you do implement this any way you want. Commented Jul 3, 2022 at 19:48
  • This would mean that calling read-from-minibuffer in the body could make sense. For instance, I made a function that uses the value of current-prefix-arg to determine what user-defined variables get asked in the minibuffer.
    – Dilna
    Commented Jul 3, 2022 at 19:55
  • 1
    One way to find out what makes sense is to read the code that emacs distributes (you can read the code of external packages as well, but there might be less quality control). E.g looking at Org mode which is a fairly substantial package, there are ten calls to read-from-minibuffer in about 130K lines of code. On average, 1 call per 13000 lines of code: not very common. You should also read the functions that do use read-from-minibuffer and figure out why they needed to do so. That will improve your understanding far more than any number of repetitive, siimple-minded tests that you cook up.
    – NickD
    Commented Jul 3, 2022 at 20:10
  • 1
    To summarize: learn to read code in order to write better code.
    – NickD
    Commented Jul 3, 2022 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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