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?
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).
I am trying to find a way to automatically accept the first proposal from the minibuffer.
(defun find-file-at-point-without-prompt ()
(interactive )
(find-file-at-point)
)
Calling results in the prompt: "Find file or URL: ......". I just want an automatic "yes".
Passing arguments does not work. It might be interesting for other cases as well. I used a macro before that would just call find-file-at-point followed by a RET.
It seems there is no variable to automatically accept the prompt.
You can redefine a function ffap-read-file-or-url by removing a part which is doing the prompt. It remains something like this
(defun ffap-read-file-or-url (prompt guess)
"Read file or URL from minibuffer, with PROMPT and initial GUESS."
(or guess (setq guess default-directory))
(let (dir)
;; Tricky: guess may have or be a local directory, like "w3/w3.elc"
;; or "w3/" or "../el/ffap.el" or "../../../"
(or (ffap-url-p guess)
(progn
(or (ffap-file-remote-p guess)
(setq guess
(abbreviate-file-name (expand-file-name guess))
))
(setq dir (file-name-directory guess))))
;; Do file substitution like (interactive "F"), suggested by MCOOK.
(or (ffap-url-p guess) (setq guess (substitute-in-file-name guess)))
;; Should not do it on url's, where $ is a common (VMS?) character.
;; Note: upcoming url.el package ought to handle this automatically.
guess))
(defun search-for-what-is-just-killed ()
(interactive)
(search-forward latestkillringvariable? nil t)
)
How to use "yank" in an emacs lisp function?
You can access directly the kill-ring list to access the latest kill:
(substring-no-properties (car kill-ring))
The substring-no-properties bit is important since text is kept in the kill ring with additional properties (like fontification specific to a particular mode and you'll probably want to strip those).
I am playing around with a small Vim function that will highlight whitespace.
But the execute command is behaving differently than when its called directly.
So the function looks like this:
function! ShowWhitespace()
execute "/\\s\\+$"
endfunction
And it is mapped as:
command! SW call ShowWhitespace()
When :SW is executed it simply searches and gets the cursor to where whitespace exists.
However, when I do this in the command line:
:exe "/\\s\\+$"
It highlights correctly the whitespace. I am also making sure that highlightsearch is always on, so this is not an issue of having it on or off.
As a side note, I need to have this in a function because I want to have other things that have not yet been added to it for flexibility (like toggling for example).
Why would this behave differently in a function than executing it directly? I've written a wealth of functions in Vim and never seen this work different.
EDIT & Solution:
So it seems Vim doesn't like having functions altering searches. As soon as a function exits the search patterns are cleared (as pointed out by :help function-search-undo.
This might look ugly but does what I was looking to do in the first place:
command! -bang Ws let orig_line = line('.') | exe ((<bang>0)?":set hls!":":set hls") | exe '/\s\+$' | exe orig_line
Explained bit by bit:
Maps the (bang-accepting) Ws command to the following actions:
saves the original line where cursor is located
depending on bang or no bang (e.g. :Ws! or :Ws) it sets highlightsearch
Executes the search to find whitespace
Goes back to the original line if it changed
If you don't wish to move the cursor (and never do it), just set #/ to the correct search pattern, i.e.:
let #/ = '\s\+$'
NB: the function should have moved the cursor.
A lot of my work involves searching and deleting unnecessary lines of code. So I create a macro, and then select all lines (C-x h) and then run the command (apply-macro-to-region-lines). I managed to save that command and placed it in my .emacs file; I called it cut_it_now. But now my function is not a macro anymore, so I can't use the (apply-macro-to-region-lines) function anymore.
Do you know if there is (apply-function-to-region-lines) implemented somewhere?
Many thanks,
D
The following function should do what you want:
(defun apply-function-to-region-lines (fn)
(interactive "aFunction to apply to lines in region: ")
(save-excursion
(goto-char (region-end))
(let ((end-marker (copy-marker (point-marker)))
next-line-marker)
(goto-char (region-beginning))
(if (not (bolp))
(forward-line 1))
(setq next-line-marker (point-marker))
(while (< next-line-marker end-marker)
(let ((start nil)
(end nil))
(goto-char next-line-marker)
(save-excursion
(setq start (point))
(forward-line 1)
(set-marker next-line-marker (point))
(setq end (point)))
(save-excursion
(let ((mark-active nil))
(narrow-to-region start end)
(funcall fn)
(widen)))))
(set-marker end-marker nil)
(set-marker next-line-marker nil))))
So, if you have the following function that you want to apply against lines in a buffer:
(defun test()
(insert "> "))
And, if your buffer contains the following contents:
Line 1: blah, blah
Line 2: blah, blah
Line 3: blah, blah
Line 4: blah, blah
If you select a region enclosing just lines 2 & 3, enter "M-x apply-function-to-region-lines", and enter "test" as the function name when prompted, you will get the following result in your buffer:
Line 1: blah, blah
> Line 2: blah, blah
> Line 3: blah, blah
Line 4: blah, blah
Note that you can still use apply-macro-to-region-lines with a macro generated from code, provided the macro is defined as a vector or string. With a custom apply-named-macro-to-region-lines[2], you can select the macro to use interactively.
Emacs has two ways of generating code from a keyboard macro, depending upon the method used to name it.
If you use kmacro-name-last-macro (bound to C-xC-kn), then Emacs generates a function from the macro, which is not directly useful for this particular purpose [1].
If you use name-last-kbd-macro to name your macro, it will be generated as a vector or string.
In either case, you then use insert-kbd-macro to obtain the code.
In fact the vector/string format is the default, so you could bypass the naming step and immediately ask for the code (typing RET at the name prompt to indicate the most recently-defined macro), and then manually edit the default name of the inserted code.
[1]: The vector form does appear to simply be embedded in the function definition, so you should be able to extract that from the code to manually re-define a macro function in vector format.
[2]: When I originally wrote this reply, I'd forgotten that this was a custom function. Sorry about that.
(defun apply-named-macro-to-region-lines (top bottom)
"Apply named keyboard macro to all lines in the region."
(interactive "r")
(let ((macro (intern
(completing-read "kbd macro (name): "
obarray
(lambda (elt)
(and (fboundp elt)
(or (stringp (symbol-function elt))
(vectorp (symbol-function elt))
(get elt 'kmacro))))
t))))
(apply-macro-to-region-lines top bottom macro)))
A simple solution is to define a macro that calls your function then use the good ol' apply-macro-to-region-lines.
Apart from that, I think that you could write a loop in a few lines of elisp that does exactly what you ask for. If you would like to be fancy, you can even prompt the user for the name of the function. I think this is a good exercise for elisp, I can help you with some pointers if you feel like you would like to try it yourself.
I agree with #Lindydancer's answer, and I'd also add that there might be an easier way to accomplish your goal. e.g. the built-in function delete-matching-lines. :-)
You could always copy the source to apply-macro-to-region-lines and tweak it to call a passed in function, and thus make your own version.