reddit / emacs

how to bind a command with a prefix to a key

dm_g · 2022-06-25 19:45
I am sorry if this is a stupid question, but I am having trouble finding an answer. I have a command I want to bind to a key, let us call it do-something do-something can be called with a prefix: one ctrl-u and two ctrl-u, it then changes its behaviour I want to avoid having to type the ctrl-u(s). How do I do it? I guess I can a lambda that calls do-something with the prefix. But I do not know how to programmatically call do-something as if it was called with a prefix. Any help would be appreciated.
kaushalmodi · 2022-06-25 20:33
It's called the `current-prefix-arg` ([ref](https://www.gnu.org/software/emacs/manual/html_node/elisp/Prefix-Command-Arguments.html)). You can let-bind that variable to `'(4)` to mimic `C-u` prefix, or `'(16)` for `C-u C-u`.
ieure · 2022-06-25 21:10
You can go that route, but most commands accept normal function arguments, for example: (defun beginning-of-defun (&optional arg) ... ) While you *could* do: (let ((current-prefix-arg '(16)) (beginning-of-defun)) It's much simpler (and clearer) to supply the argument explicitly: (beginning-of-defun 16) Most commands work this way, and it should be preferred over let-binding `current-prefix-arg` where possible (which is the vast majority of cases).
lastnamebird · 2022-06-25 22:38
Would it be more accurate to have `(beginning-of-define ‘(16))`? Is the prefix arg modified when read by a function? Also, since, as you say, only some commands accept the `prefix-arg`as a parameter, the let binding would still be more robust, working in all cases.
dm_g · 2022-06-25 23:48
Thank you both the responses, but it seems to be more complicate that this. The function I am trying to wrap has one parameter and two optional parameters (its source is attached below, from the web-search package, see below) . \- If the function does not get a query it asks for one. \- the c-u is used to prompt from a list of predefined values (the providers). c-u c-u does the same from predefined tags. I can't call it with the optional parameter, because it will complain that I am missing the query parameter. I tried to wrap it: (defun web-search-all () (interactive) (let ((current-prefix-arg '(4))) (web-search))) I get the same error "wrong number of arguments". what I want is to avoid having to type C-u C-u before calling web-search, and instead having a new function that I can call directly without the extra (one or two extra c-u). (defun web-search (query &optional providers tag) "Search for QUERY on website(s). Without prefix argument, search on `web-search-default-provider'. One C-u, choose a provider. Two C-u, choose a tag (notes that a tag can match multiple providers)." (interactive (let* ((providers (if (equal current-prefix-arg '(4)) ; One C-u (let* ((default web-search-default-provider) (prompt (format "Provider (default %s): " default)) (completion-ignore-case t)) (list (completing-read prompt web-search-providers nil t nil nil default))) (list web-search-default-provider))) (tag (when (equal current-prefix-arg '(16)) ; Two C-u (completing-read "Tag: " (web-search--tags)))) (query (let ((initial (if (use-region-p) (buffer-substring-no-properties (region-beginning) (region-end)) (current-word))) (prompt (format "Search %s: " (if tag (mapconcat #'identity (mapcar #'car (web-search--find-providers tag)) ", ") (mapconcat #'identity providers ", "))))) (read-string prompt initial)))) (list query providers tag))) (setq providers (or (and tag (web-search--find-providers tag)) providers (list web-search-default-provider))) (mapc #'browse-url (web-search--format-urls query providers)))
ieure · 2022-06-26 00:00
> Would it be more accurate to have (beginning-of-define ‘(16))? No, that would signal an error. Commands can specify that they want a raw prefix argument, which passes the cons-cell `'(16)` form, or that they want it converted to a number, which passes `16`. The `beginning-of-defun` command specifies that it wants a number, so you must pass it a number when calling. Specifying the raw prefix lets commands distinguish between a `C-u` prefix and a `C-4` prefix. Most don't need that. > Is the prefix arg modified when read by a function? I don't really understand what you're asking. > Also, since, as you say, only some commands accept the prefix-argas a parameter, the let binding would still be more robust, working in all cases. The overwhelming majority accept arguments normally, and commands are *generally* intended to be invoked by a key binding, not called from other functions, so in practice, it isn't a problem. There's no need to use a weird calling convention for 100% of calls when it's only needed for 0.01%.
ieure · 2022-06-26 00:04
The function *requires* a `query` argument, which you aren't providing; that's why you get the error. When you invoke it with a keybinding, the forms inside `(interactive …)` are evaluated (which prompts you), and the list it returns is used as the argument list. It doesn't get evaluated when invoking as a function. Try this: (defun web-search-all () (interactive) (let ((current-prefix-arg '(4))) (call-interactively #'web-search)))
kaushalmodi · 2022-06-26 00:43
You'll need to do `(call-interactively #'web-search)`, not a plain elisp call. **Update** nevermind, I saw that /u/ieure got that covered :)
dpoggio · 2022-06-26 03:26
I haven’t read all of the comments, but it seems many of you think about prefix as a parameter. It’s not. Call the function with regular parameters, and change the VARIABLE called current-prefix-arg.
lastnamebird · 2022-06-26 03:33
I was confused by your initial example which does not actually work. `beginning-of-defun` doesn't seem to read the `current-prefix-arg` at all if called programmatically. To your point, most interactive commands don't read the `current-prefix-arg` variable if not called interactively, so passing a direct value is the only way to get them to work. I appreciate the info, I did learn something new and useful going forward. `
ieure · 2022-06-26 03:46
You're right, it should have been: (let ((current-prefix-arg '(16))) (call-interactively #'beginning-of-defun))
dm_g · 2022-06-26 19:39
>Specifying the raw prefix lets commands distinguish between a > >C-u > > prefix and a > >C-4 > > prefix. Most don't need that. Thank you ierure, and everybody elese. This thread has been very educational.