reddit / emacs

programmatically defining general.el bindings

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`...