3

In ELISP, the documentation for interactive codes mentions:

P -- Prefix arg in raw form. Does not do I/O. ... s -- Arbitrary text, read in the minibuffer and returned as a string ... Prompt.

I presumed that I could write a function with an optional prefix argument, as in:

(defun some-function (&optional prefix)
    (interactive "P")
    ...
)

or a function with user input, as in:

(defun some-function (user-argument)
  (interactive "sProvide an argument: ")
  ...
)

but not both. Then I found the Org-mode function org-match-sparse-tree, which I can call with C-u C-c \, where the prefix argument restricts the match to open org-mode headings and I am still prompted for a match. The source code is below and I cannot find how the variable match is assigned:

(defun org-match-sparse-tree (&optional todo-only match)
  "..."
  (interactive "P")
  (org-agenda-prepare-buffers (list (current-buffer)))
  (let ((org--matcher-tags-todo-only todo-only))
    (org-scan-tags 'sparse-tree (cdr (org-make-tags-matcher match))
           org--matcher-tags-todo-only)))

How does this function take both prefix argument and user input?

1 Answer 1

5

How does this function [interactively] take both prefix argument and user input?

It doesn't -- the match argument is not obtained, and is therefore nil. What you're seeing is the effect of the subsequent call to (org-make-tags-matcher match) with that nil value as the argument:

(defun org-make-tags-matcher (match)
  "..."
  (unless match
    ;; Get a new match request, with completion against the global
    ;; tags table and the local tags in current buffer.
    (let ((org-last-tags-completion-table
           (org-tag-add-to-alist
            (org-get-buffer-tags)
            (org-global-tags-completion-table))))
      (setq match
            (completing-read
             "Match: "
             'org-tags-completion-function nil nil nil 'org-tags-history))))
  ...)

Functions can take multiple interactive arguments, though.

See C-hf interactive

To pass several arguments to the command, concatenate the individual strings, separating them by newline characters.

The very first example in that help demonstrates this:

(defun foo (arg buf) "Doc string" (interactive "P\nbbuffer: ") .... )

This is elaborated upon at (elisp)Using Interactive -- up one level in the documentation you'd linked to:

It may be a string; its contents are a sequence of elements
separated by newlines, one for each argument(1).  Each element
consists of a code character (*note Interactive Codes::) optionally
followed by a prompt (which some code characters use and some
ignore).  Here is an example:

     (interactive "P\nbFrobnicate buffer: ")

The code letter ‘P’ sets the command’s first argument to the raw
command prefix (*note Prefix Command Arguments::).  ‘bFrobnicate
buffer: ’ prompts the user with ‘Frobnicate buffer: ’ to enter the
name of an existing buffer, which becomes the second and final
argument.

You should read that documentation fully, though -- there are more sophisticated things you can do, including writing arbitrary elisp to produce the interactive arguments (which may or may not involve prompting the user).

Sign up to request clarification or add additional context in comments.

1 Comment

Well done. I had mistaken the part about multiple arguments separated by newlines, and that No I/O applies only to the prefix argument, not the other arguments.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.