background
I had elisp code (in this very small git
repo) like
(defun bulk-replace-file (filepath)
(interactive "FPath to file to bulk-replace: ")
(bulk-replace-file-non-interactive filepath)
)
That worked. Then I decided to parameterize the prompt, producing code like
(defconst BULK-REPLACE-FILEPATH-PROMPT "Path to file to bulk-replace: ")
(defun bulk-replace-file (filepath)
; (interactive "FPath to file to bulk-replace: ") ; should always work
(interactive (concat "F" BULK-REPLACE-FILEPATH-PROMPT))
(bulk-replace-file-non-interactive filepath)
)
However that fails with (in *Messages*
)
command-execute: Wrong type argument: listp, "FPath to file to bulk-replace: "
Which frankly stuns me, esp since I'm positive this code formerly worked, but that's why one does regression testing :-(
.
questions
- How is
(interactive)
getting a list from"FPath to file to bulk-replace: "
, given that the latter surely looks like a string? Am I missing something? - Why is
(interactive)
not getting a list from(concat "F" BULK-REPLACE-FILEPATH-PROMPT)
, given that(concat "F" BULK-REPLACE-FILEPATH-PROMPT)
returns a string (I have checked with(type-of)
)(concat "F" BULK-REPLACE-FILEPATH-PROMPT)
=="FPath to file to bulk-replace: "
(per the error message above)(interactive "FPath to file to bulk-replace: ")
works (see first code snippet)
- What's "the right way" to parameterize a prompt used for
(interactive)
?
über-answer
Given that, as Drew points out, (interactive)
is quite demanding, an easier (and working) way to achieve the desired functionality avoids prompting via (interactive)
:
(defconst BULK-REPLACE-FILEPATH-PROMPT "Path to file to bulk-replace: ")
(defun bulk-replace-file ()
(interactive) ; Purely to enable `M-x`: let `read-file-name` get the filepath
(bulk-replace-file-non-interactive
(read-file-name BULK-REPLACE-FILEPATH-PROMPT)))
)