mmiri-ifuru · 2022-04-20 20:41
Hi,
I have the following code to generate two keybindings:
```
(general-create-definer map-to-leader
:keymaps 'override
:prefix "SPC"
"" '(:ignore t :wk "leader-key"))
(map-to-leader
:states '(normal visual motion)
:keymaps 'override
"d" '(:wk "dired")
"d d" '((lambda () (interactive)
(dired "~/Documents"))
:wk "docs")
"d p" '((lambda () (interactive)
(dired "~/Pictures"))
:wk "pics"))
```
I would to declare a variable like:
```
(setq bms '(("d" "~/Documents/" "docs")
("p" "~/Pictures/" "pics" )))
```
And then populate the `map-to-leader` call by iterating through `bms`. For instance:
```
(defun bms-entries-map-to-leader ()
(interactive)
(let ((binding))
(dolist (bm bms binding)
(setq
binding (cons
`(,(concat "d " (nth 0 bm))
,`((lambda () (interactive)
(dired ,(nth 1 bm))) :wk ,(nth 2 bm)))
binding)))))
```
But I cannot use this function in `map-to-leader`. Any help or suggestions would be very welcome. Thank you!
usaoc · 2022-04-21 03:15
1. [`setq` is a *setter*](https://www.gnu.org/software/emacs/manual/html_node/elisp/Setting-Variables.html). It’s *not* for variable declarations. For variable declarations, use [`defvar` and friends for global variables](https://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Variables.html) and [`let` and friends for local variables](https://www.gnu.org/software/emacs/manual/html_node/elisp/Local-Variables.html). Also, there’s no reason to [*close over* the value of `bms` inside the function](https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html) instead of passing it as an argument.
2. It doesn’t work because [the definer `map-to-leader` is a macro](https://github.com/noctuid/general.el/blob/9651024e7f40a8ac5c3f31f8675d3ebe2b667344/general.el#L1358). [Macros have their own syntax for good reason](https://www.gnu.org/software/emacs/manual/html_node/elisp/Eval-During-Expansion.html). I suggest that you [think of what the problem actually is before solving it](https://en.wikipedia.org/wiki/XY_problem).
mmiri-ifuru · 2022-04-21 06:31
Hi, thanks for the tips. I think the main problem here is that I can't figure out how can send inputs to a macro programatically. My current attempt is:
```
;; Specify keybindings
(setq +/kbs '(("d" "~/Documents/" "documents")
("p" "~/Pictures/" "pictures")))
;; Create input for map-to-leader
;; The output of this function looks ok,
;; but does not work with map-to-leader below
;; This is what I can't figure out...
(defun +/test-mapping ()
(interactive)
(let ((bindings))
(push :states bindings)
(push `'(normal visual motion) bindings)
(push :keymaps bindings)
(push `'override bindings)
(dolist (kb +/kbs bindings)
(push (concat "d " (nth 0 kb)) bindings)
(push `'((lambda () (interactive) (dired ,(format "%S" (nth 1 kb)))) :wk ,(format "%S" (nth 2 kb))) bindings))
(setq bindings (nreverse bindings))))
;; map to leader call
(+/UIX/map-to-leader
(+/test-mapping))
```
I think the problem is two-fold. 1. I don't know if programmatically specifying keybindings in `map-to-leader` is possible. 2. I am assuming it is, and in this case, I can't seem to figure out what format they should be in...
I am sort of new to elisp and although I have read through the pages you pointed to and tried to use my understanding to create the `+/test-mapping`, I still can't figure out what needs to be done.
usaoc · 2022-04-21 06:46
You don’t. Macros and functions have their effects at different stages, namely [macro-expansion time](https://www.gnu.org/software/emacs/manual/html_node/elisp/Macro-Forms.html) vs. [runtime](https://www.gnu.org/software/emacs/manual/html_node/elisp/Function-Forms.html). They should never be mixed together in this way. Instead, try defining a new macro, or better yet, a plain-old function (since we’re just dealing with a list and no new syntax is needed) that does the job.
mmiri-ifuru · 2022-04-21 07:37
Right. The way I understand it is that if I go the macro-way, the idea is to create a macro that operates on the `map-to-leader` macro, right?
And if I got the function-way? I'm not sure what you meant by plain-old-function. You meant a function that makes repeated calls to `map-to-leader` to set up the keybindings?
usaoc · 2022-04-21 07:52
The function approach: Pass the alist as an argument, iterate over the alist, destructure the elements using [Common Lisp’s destructuring facility](https://www.gnu.org/software/emacs/manual/html_node/cl/Macros.html) or [pattern matching](https://www.gnu.org/software/emacs/manual/html_node/elisp/Pattern_002dMatching-Conditional.html), then write the macro forms as the body.
The macro approach: Expand into the same code as the function (remember that the values of the arguments are *not* known when the macro forms are expanded). With this approach, the macro is really nothing more than an [inline function](https://www.gnu.org/software/emacs/manual/html_node/elisp/Inline-Functions.html), so it’s unnecessary.
mmiri-ifuru · 2022-04-21 08:05
This is fantastic. Thank you for the patience and the detailed responses. I am going to play around with these ideas for a couple of days and report back. Thank you!!
mmiri-ifuru · 2022-04-26 17:05
Update: I followed the function-based approach instead of extending the macro and it worked out very nicely. Thanks for all the pointers!
graduale · 2022-10-26 13:12
Did you ever figure this out? If so, would you mind posting your solution? Trying to do something similar for defining bindings for each of my `org-agenda-custom-commands`...