I'm going to do this using the newer functions from keymap.el, as I feel they are more intuitive. They also don't require use of kbd to normalize key sequences.
First, let's look at this outside the context of Evil-mode.
You're trying to create a prefix-key in global-map. In other words, the key will be bound to another keymap.
Emacs lets you bind keys to commands, other keymaps, or keyboard macros.
When you open Emacs, C-a is bound to the command move-beginning-of-line. But you are then free to bind it to something else, a keymap, command, or a keyboard macro. That's what you did when you evaluated (global-set-key (kbd "C-a") (kbd "yi(")). You simply replaced the binding of C-a with a keyboard macro that acts as if you pressed yi(.
- How to bind CTRL+A followed by a ( (without having to hold the CTRL key) to this sequence of evil commands: yi(?
(keymap-global-unset "C-a") (keymap-global-set "C-a (" "y i (")
Or, using the older keybinding functions...
(global-unset-key (kbd "C-a")) (global-set-key (kbd "C-a (") (kbd "yi("))
- Why my attempt 1.2.1. fails?
The reason that (global-set-key (kbd "C-a (") (kbd "yi(")) doesn't work without first unsetting C-a is explained in the error message you received:
Key sequence C-a ( starts with non-prefix key C-a
When you bind to a sequence of keys (like C-a (), you're really telling Emacs to create a keybinding for ( in whatever keymap is bound to the C-a key. But as Emacs advises you, that key is already bound to something else, which is not a keymap.
If there were no binding at all for C-a, Emacs would happily bind an empty keymap to it and then bind ( in that keymap. So we solve this problem by first un-binding C-a and then binding ( underneath C-a.
If you wanted to be more explicit about what you were doing, you could actually create the keymap first, then bind it to C-a, and then you'd also be able to bind the same keymap to other keys.
(defvar-keymap my/macro-keys "(" "y i (") (keymap-global-set "C-a" my/macro-keys) ;; same keymap on another prefix (keymap-global-set "C-c m" my/macro-keys)
- Why my attempt 1.2.2. fails?
I don't have any way to test this, because I don't have General installed. So the following only discusses the error you're getting. If there are other problems with how you're using General, I wouldn't know.
Again, let's look at the error message.
CTRL+A : command-execute: Wrong type argument: commandp, (kbd "yi(")
This is saying that Emacs called a function, command-execute. In doing so, Emacs checked whether one of the arguments satisfied the predicate commandp, which checks that the argument is a command. But the argument failed that check, because it is not a command. The argument was (kbd "yi(").
Emacs is assuming that the object bound to C-a should be a command and attempting to execute it. So why is Emacs assuming that? Well, there are two other things it could be, a keymap, or a key sequence (keyboard macro).
If the object were a keymap, it would be a list that begins with the symbol keymap. In fact, the object (kbd "yi(") is a list. But it does not begin with the keymap symbol, so it is definitely not a keymap.
You intended for the object to be a key sequence, but instead it is only a list that begins with kbd. That's because when you passed the argument, it was inside of a quoted list.
(testkey "a" '((kbd "yi)") :wk "Yank in ()"))
Normally, when you use kbd, you simply pass the form to a function. But since the form (kbd "yi)") is inside of a quoted list, every item in that list gets passed as-is, without being evaluated. That's why the error message tells you the argument is (kbd "yi(") and not just "yi(" (which is what that form evaluates to).
There are a few different ways you could write this to get around the error.
One is you could switch to using a backquoted list, which allows you to select which items get evaluated by prefixing them with commas.
(testkey "a" `(,(kbd "yi)") :wk "Yank in ()"))
This should cause the kbd form to be evaluated while still preventing the other forms from being evaluated.
Since the other two elements are a keyword :wk and a string, both of which will always evaluate to themselves anyway, you could just return a list without quoting it.
(testkey "a" (list (kbd "yi)") :wk "Yank in ()"))
Or you could just pass the thing that (kbd "yi)") evaluates to, which is the string "yi)".
(testkey "a" '("yi)" :wk "Yank in ()"))
Any of these will result in the same thing being passed to your testkey definer. But as I wrote above, I have no way to test that the other parts of it are written correctly.
[prefix-keys]. See [Prefix Keys]()gnu.org/software/emacs/manual/html_node/elisp/Prefix-Keys.html.