Programatically insert text into command that normally blocks event loop - emacs

I'd like to implement a command that types the first few characters into an existing command and lets me type the rest.
For example, a variant of icicle-execute-extended-command that starts with "icicle-" already entered.
I have tried:
keyboard macros
fail (even on simple things like M-x i c i c l e s) for no apparent reason.
functions
calling icicle-execute-extended-command block the command sequence
How would I go about doing this in a generalized manner?

Nice question.
Here's something generic you can try:
(defun no-mondays ()
(interactive)
(minibuffer-with-setup-hook
(lambda()
(insert "monday"))
(call-interactively 'query-replace)))
And here's a refactoring:
(defun with-initial-minibuffer (str fun)
`(lambda ()
(interactive)
(minibuffer-with-setup-hook
(lambda ()
(insert ,str))
(call-interactively ',fun))))
(defalias 'no-weekends
(with-initial-minibuffer
"\\(?:satur\\|sun\\)day"
'query-replace-regexp))

If you are calling completing-read yourself in your command definition, then just pass the text to insert as the INITIAL-INPUT argument. That's what it's for.
If you use icicle-define-command or icicle-define-file-command (so that your command will be a multi-command), then same thing: pass the INITIAL-INPUT arg.
If you use such a macro, be sure to put something like this in the file that defines the command, so the macro definition is available a byte-compilation time:
(eval-when-compile
(or (condition-case nil
(load-library "icicles-mac") ; Use load-library to ensure latest .elc.
(error nil))
(require 'icicles-mac)))

Related

Emacs lisp, How `interactive' reads buffer?

For example there is a function:
(defun testb (buf)
(interactive "bTest: ")
buf)
The question is how emacs internally reads a buffer for such interactive form?
Looks like it doesn't use read-buffer(or it calls the read-buffer as a C function(and doesn't look at symbol-function)?).
(flet ((read-buffer (&rest args) (current-buffer)))
(call-interactively #'testb))
It uses Lisp function read-buffer. The interactive spec you show is equivalent to this one:
(interactive (list (read-buffer "Test: " nil t)))
See the Elisp manual, node Using Interactive.
I guess you're referring to the fact that you got this error, or similar, which you get when you try to use flet on a built-in function. And yes, read-buffer is a subr, i.e., implemented in C. (symbol-function 'read-buffer) returns the built-in function #<subr read-buffer>.
Use ‘labels’, not ‘flet’, to rebind macro names

How can I jump to a definition without being queried in Emacs?

I have a problem when using Etags in Emacs. Everytime I tap \M+. to jump to a difinition point, a query is always popping up, like:
Find tag (default function_name):
And I have to tap 'Enter' to make sure of it.
But in most cases, I find I can choose the default one. So is there any method with which I can surpress this message?
I found the reason is because:
(defun find-tag (tagname &optional next-p regexp-p)
(interactive (find-tag-interactive "Find tag: "))
...
)
Why do I have to choose a tag? Why can not the default one just be the word under the point? Can I just remove this line? (interactive), or is there a good solution?
Going shortly through a couple of defuns in the etags sources via Emacs's awesome C-h f, one can find that the default tag to search is determined via a function named find-tag-default.
This means you could just define the following function:
(defun find-tag-under-point ()
(interactive)
(find-tag (find-tag-default)))
Then you can bind this to whatever key you want via define-key or global-set-key or local-set-key.
(The interactive form is always necessary if you want a function to be a "command" which can be called with M-x or bound to a key.)
You can write your own functionality over the find-tag (or any interactive function likewise)
(defun find-tag-under-point (&optional arg)
(interactive "P")
(cond ((eq arg 9)
(let ((current-prefix-arg nil))
(call-interactively 'find-tag)))
(arg
(call-interactively 'find-tag))
(t
(find-tag (find-tag-default)))))
(global-set-key (kbd "M-.") 'find-tag-under-point)
Then hotkey C-9M-. calls find-tag (old function) as usual, but the behaviour of find-tag-under-point (new-function) by default is what you want.

Get list of interactive functions in Elisp/Emacs

I have a bunch of my interactive functions with a prefix, say *zb/" (e.g. "zb/create-temp-buffer"). I am a bit tired every time to type in M-x interaction this prefix of a command I like to run.
To automate this I'd like to retrieve a list of all my interactive functions and show them through ido-completing-read (btw, possibly there are other alternative and modern ways to create input with predefined items and autocompletion?). But I did not manage to find how to retrieve a such list. Could you please give me a cue how to achieve this?
List of all available interactive functions will be enough; to filter is not an issue.
Thanks.
You can use this function for selection
(defun eab/select-zb/ ()
(interactive)
(call-interactively
(intern
(ido-completing-read "M-x zb/"
(mapcar 'symbol-name (apropos-internal "^zb/"))))))
Maybe give Smex a try?
Smex is a M-x enhancement for Emacs. Built on top of Ido, it provides a convenient interface to your recently and most frequently used commands. And to all the other commands, too.
You say "possibly there are other alternative and modern ways to create input with predefined items and autocompletion?".
Use Icicles and just bind icicle-must-match-regexp:
(defun zb/ ()
(interactive)
(let ((icicle-must-match-regexp "^zb/"))
(call-interactively (intern (completing-read "zb/ command: " obarray 'commandp t)))))
You can also do it with vanilla Emacs and without Ido:
(defun zb/ ()
(interactive)
(call-interactively
(intern (completing-read
"zb/ command: "
obarray
(lambda (cmd)
(and (commandp cmd) (string-match-p "^zb/" (symbol-name cmd))))
t))))
Or do as #artscan suggested: use apropos-internal to match the regexp. IOW, either let completing-read do the matching or match first using apropos-internal. You can pass the commandp predicate to apropos-internal as well.

Emacs custom command line argument

From the documentation I can see I can access command line arguments (command-line-args).
I'd like to add my own arguments but Emacs complains at start up that it doesn't recognize them.
E.g.
emacs -my_argument
I get:
command-line-1: Unknown option `-my_argument'
What's a proper way to define my custom arguments and provide information to my Emacs session?
Is there a way to pop an argument from a command line?
Add something like this to your ~/.emacs, ~/.emacs.el, or ~/.emacs.d/init.el file:
(defun my-argument-fn (switch)
(message "i was passed -my_argument"))
(add-to-list 'command-switch-alist '("-my_argument" . my-argument-fn))
Then you can execute emacs -my_argument and it should print i was passed -my_argument to the minibuffer. You can find more information in the GNU elisp reference.
As stated in another post you can add your custom switches to command-switch-alist and emacs will call the handler function for any matching switch passed in on the command line. However, this operation is done after your .emacs file has been evaluated. This is fine for most cases but you may wish for a command line argument to alter the execution path or behaviour of your .emacs evaluation; I often do this to enable/disable configuration chunks (mainly for debugging).
To achieve this you can read command-line-args and check for your switch manually and then delete it from the list, this will stop emacs complaining about an unknown argument.
(setq my-switch-found (member "-myswitch" command-line-args))
(setq command-line-args (delete "-myswitch" command-line-args))
Which can alter your .emacs evaluation like so:
(unless my-switch-found
(message "Didn't find inhibit switch, loading some config.")
...)
And you could build this into a single step:
;; This was written in SO text-box, not been tested.
(defun found-custom-arg (switch)
(let ((found-switch (member switch command-line-args)))
(setq command-line-args (delete switch command-line-args))
found-switch))
(unless (found-custom-arg "-myswitch")
(message "Loading config...")
...)
For those who are interested, here is a code snip to show how to process custom arguments in Emacs lisp. In this case, I am processing an argument --suffix / -S to variable _suffix.
I pulled the idea from a BSD-Lite Script Emacs script.
(setq _suffix nil)
;; Process cli args
(while command-line-args-left
(setq k (car command-line-args-left))
(setq command-line-args-left (cdr command-line-args-left))
(setq command-line-args (delete k command-line-args))
(cond
(or (string-equal k "--cs-suffix")
(string-equal k "-S"))
(setq _suffix (intern (car command-line-args-left)))
(setq command-line-args-left (cdr command-line-args-left))
(setq command-line-args (delete _suffix command-line-args))
)))
This will roll through command-line-args-left and remove them all from command-line-args which will prevent Emacs from complaining.

Define an emacs command that calls another emacs command (preserving interactive stuff)

How can I define an emacs command X that does something and then calls another emacs command Y and also copying the interactive interface of the command Y too?
I want to define an altenative version of query-replace with temporarilly toggled value of case-fold-search:
(defun alt-query-replace (a b c d e)
(interactive)
(let ((case-fold-search (not case-fold-search))
(query-replace a b c d e)))
This doesn't work. When I call alt-query-replace, it says "wrong number of arguments". I want the interactive interface of alt-query-replace to be the same as query-replace. Do I need to inspect the source code of query-replace or is there a general approach?
You may advise the original function, if you want to modify its behavior instead of calling a separate function.
From chapter 17.3 Around-Advice of the GNU Emacs Lisp Reference Manual:
Around-advice lets you “wrap” a Lisp
expression “around” the original
function definition.
(defadvice foo (around foo-around)
"Ignore case in `foo'."
(let ((case-fold-search t))
ad-do-it))
In your case, you can write:
(defadvice query-replace (around alt-query-replace (from-string to-string &optional delimited start end))
(let ((case-fold-search (not case-fold-search)))
ad-do-it))
(ad-activate 'query-replace)
Use call-interactively:
(defun alt-query-replace ()
(interactive)
(let ((case-fold-search (not case-fold-search)))
(call-interactively 'query-replace)))