The issue with the code turns out to be a facet of how macros work. This macro accepts a parameter num
, but based on macro eval rules, num
itself is actually the original symbol you passed into the function since macro arguments are never evaluated before they are given to the macro body.
With backquoting you can extract the actual value of num
, but you won’t be able to do it for the intern
call because it’s being evaluated in the macro expansion pass (no access to the value of num
). You would need to pass a number literal in for num
for this to work, and that’s why your manual invocations were working.
(defmacro ct/tab-bar-select-action-define (num)
`(defun ,(intern (format "ct/tab-bar-select-%d" num)) ()
,(format "Select tab %d by its absolute number." num)
(interactive)
(tab-bar-select-tab ,num)))
In this part of the code, the only problem is that %i
was used, but %d
is the appropriate specifier for integers:
(let (tab-number)
(dotimes (i 9)
(setq tab-number (+ 1 i))
(message (format ">%d" tab-number))
(ct/tab-bar-select-action-define tab-number)))
There’s still the problem that ct/tab-bar-select-action-define
receives tab-number
the symbol and not the value. The solution here is to make this macro actually take the number of actions to define and do the loop internally.
The final catch is that dotimes
returns nil
but a macro needs to return the expression(s) that it expands into, so I’m using mapcar
and number-sequence
to replicate the dotimes
behavior and then wrap it in a progn
so that the macro returns a single evaluatable expression:
(defmacro ct/tab-bar-select-action-define (num)
`(progn
,@(mapcar (lambda (i)
`(defun ,(intern (format "ct/tab-bar-select-%d" i)) ()
,(format "Select tab %d by its absolute number." i)
(interactive)
(tab-bar-select-tab ,i)))
(number-sequence 0 9))))
;; Defines actions 0 to 9
(ct/tab-bar-select-action-define 9)
Thanks for checking this out!
Since passing in a parameter is so much trouble, inlining the
defun
into the loop probably is easiest, based on your changed here: