help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Eval keymapp in a macros


From: Arthur Miller
Subject: Re: Eval keymapp in a macros
Date: Thu, 05 Aug 2021 18:04:30 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> (defmacro with-key-map (mapname &rest body)
>>   `(let ((map (eval-and-compile (if (string-match-p "-map$" (symbol-name 
>> ',mapname))
>>                                  (symbol-name ',mapname)
>>                                (concat (symbol-name ',mapname) "-map"))))
>>       (defs '(,@body)))
>>      (dolist (def defs)
>>        (define-key (symbol-value (intern map))
>>       (if (vectorp (car def)) (car def)
>>         (read-kbd-macro (car def)))
>>          (cdr def)))))
>
> Your `map` variable above has a misleading name since it won't hold
> a map but a string

yes, I know, that was just me being lazy, that wasn't ment for other
people, so I used shorter name for the variable that I would type later
on :).
> PS: Personally I'd recommend against the `string-match-p` dance, since
>     all it saves you is the typing of `-map` but in exchange it prevents
>     you from using your macro with keymaps that have a name that doesn't
>     end in `-map` and it "obfuscates" the code a little, preventing
>     things like ElDoc and Xref from understanding what's going on.

And same reason explains -map obfuscation :). I thought from the
beginning it was cool to omit it but after a while realized it looked a
bit dumb, so now when I am changing to ordinary list instead of cons, I
planned to drop that. I agree it obscures the code with not much of
repetitive typing removed.

>     (defun my--with-key-map (map defs)
>       (dolist (def defs)
>         (let ((key (car def)))
>           (define-key map
>                       (if (vectorp key) key (read-kbd-macro key))
>                       (cdr def)))))
>     
>     (defmacro my-with-key-map (mapname &rest body)
>       `(my--with-key-map ,(if (string-match-p "-map\\'" (symbol-name mapname))
>                               mapname
>                             (intern (format "%s-map" mapname)))
>                          ',body))
>
> Look ma!  No `eval-and-compile` and no `symbol-value`.

When I said I would write it differently, I was thinking in different
direction indeed. This is simpler than what I had in mind. However :-)
... if we drop the -map suffix thing, we have:

(defun my--with-key-map (map defs)
(dolist (def defs)
  (let ((key (car def)))
    (define-key map
      (if (vectorp key) key (read-kbd-macro key))
      (cdr def)))))

(defmacro with-key-map (mapname &rest body)
  `(my--with-key-map ,mapname ',body))

This still does not handle the case with indirect keymap:

(setq pkg-ops-map
      (let ((map (make-sparse-keymap "Packages")))
        (with-key-map map
                      ("h" . '("describe" . describe-package))
                      ("a" . '("autoremove" . package-autoremove))
                      ("d" . '("delete" . package-delete))
                      ("i" . '("install" . package-install))
                      ("s" . '("selected" . package-install-selected-packages))
                      ("r" . '("refresh" . package-refresh-contents))
                      ("l" . '("list" . list-packages)))
        map))

(with-key-map global-map ("C-c p" . pkg-ops-map))

The last line will eval, but at runtime gives error: Wrong type
argument: commandp, pkg-ops-map.

The "evals" came to fix that case.

I tried with keymmapp in my--with-key-map but it still won't work
without eval, I think for the reasons as Michael summarized.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]