0

I'm having to replace the configurations of keymaps in my use-package with define-key expressions and thought I'd use that to get more proficient with using regexp-replace. The situation is this:

(:map cdlatex-mode-map
            ("<kp-right>" . cdlatex-tab)
            ("\"" . cdlatex-math-modify)
            ("§" . cdlatex-math-modify)
            ("Ђ" . cdlatex-text)
            ("њ" . cdlatex-mathit)
            ("M-ℕ" . change-mathvar)
            ("C-M-ℕ" . change-mathvar-withinstring)
            ("M-]" . remove-environment)
            ("M-t" . cdlatex-item)
            )

Here, I would like to rewrite each tuple like

("M-t" . cdlatex-item)

Into a string like

(define-key cdlatex-mode-map (kbd "M-t") #'cdlatex-item)

And do that not just for cdlatex-mode-map but for other mode-map configurations as well. I thought the first step would be to find a regexp that could match the :map code block above, and I did:

(:map[ ]+?\([^ ]*\).*
\( *("\(.*\)" *\. *\(.*\))
\)* *)

This matches the blocks. But I'm confused about how I can put the first regexp-subexpression, corresponding in the above block to cdlatex-mode-map, and the third and fourth, corresponding to the shortcut and command, into something like

(define-key \1 (kbd "\3") #'\4)

But this only works for the last item in the block. Is there a way I can make such a nested replacement work?

4
  • Not really clear whether you just want an answer (such as @NickD provided) for how to rewrite the tuples etc. or you want to see how to do that using regexp search, e.g., "to get more proficient with using regexp-replace". Is the question about using regexps, as the title and tags suggest, or are you looking for how to replace stuff in your (:map...) sexp. Please clarify.
    – Drew
    Jan 4 at 2:27
  • @Drew I like NickD's answer because it highlights a different way of solving the problem, but I would like to know if and how it works with regexps. Jan 4 at 4:18
  • Consider splitting your question in two in that case, and adjust the tags accordingly. E.g., rephrase this question to not ask about using regexps, so NickD's answer answers the update, and pose the regexp question separately. Just a suggestion.
    – Drew
    Jan 4 at 4:40
  • IMO, regexps are the wrong way to solve this problem: you might be able to do it, but it will be so convoluted that it would be unreadable. In general, regexps should only be used for lexical analysis (basically recognizing tokens that a parser can use - in particular, using regexps for parsing even the simplest context-dependent grammars should be avoided) and very simple transformations. Regexp engines have been accruing "features" for many years allowing the regexp hammer to be swung indiscriminately against brads and nails, but also screws: using it that way can hurt you.
    – NickD
    Jan 4 at 11:12

1 Answer 1

2

Why use regexps at all? You have a nice data structure and you can pick and choose pieces out of it and munge them in whatever form you want, using a bit of Lisp. For example, you can get the three pieces that you need (the keymap, the string representation of the key and the symbol representing the function) like this:

(setq ds '(:map cdlatex-mode-map
            ("<kp-right>" . cdlatex-tab)
            ("\"" . cdlatex-math-modify)
            ("§" . cdlatex-math-modify)
            ("Ђ" . cdlatex-text)
            ("њ" . cdlatex-mathit)
            ("M-ℕ" . change-mathvar)
            ("C-M-ℕ" . change-mathvar-withinstring)
            ("M-]" . remove-environment)
            ("M-t" . cdlatex-item)
            ))

(defun munge (ds)
   (let ((kmap (nth 1 ds))
          (pairs (cddr ds)))
      (mapcar (lambda (pair) (list kmap (car pair) (cdr pair))) pairs)))

munge munges the original data structure to produce a list of three-element lists, each with the symbol representing the keymap, the string representation of the key and the symbol representing the command. If you evaluate (munge ds), you should get the following result:

((cdlatex-mode-map "<kp-right>" cdlatex-tab)
 (cdlatex-mode-map "\"" cdlatex-math-modify)
 (cdlatex-mode-map "§" cdlatex-math-modify)
 (cdlatex-mode-map "Ђ" cdlatex-text)
 (cdlatex-mode-map "њ" cdlatex-mathit)
 (cdlatex-mode-map "M-ℕ" change-mathvar)
 (cdlatex-mode-map "C-M-ℕ" change-mathvar-withinstring)
 (cdlatex-mode-map "M-]" remove-environment)
 (cdlatex-mode-map "M-t" cdlatex-item))

The nice thing about this is that each three-element list is self-sufficient: it contains all the information that you need to pass to define-key.

You can define another function to take the above result as input and do all the define-keys:

(defun map-define-key (l)
  (mapcar (lambda (x) (define-key (symbol-value (nth 0 x)) (kbd (nth 1 x)) (nth 2 x))) l))

The only subtlety is that define-key takes a keymap as first argument, not the symbol that represents the keymap, so we use symbol-value on the symbol to produce the value.

You can then combine the two function calls:

(map-define-key (munge ds))

IMO, this is much more readable than anything you could come up with using regexps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.