I'll preface this question with the fact that I'm very new to writing macros, I usually avoid them when I can. I'm trying to write a little emacs widget and thought I found the perfect situation to use them.
I want to generate a bunch of toggle widgets with slightly different notify functions. (the idea is to use them as a bit field to allow the user to toggle them and calculate the hex number)
The macro in question is this:
(defmacro bw/gen-bit-toggle (index)
`(widget-create 'toggle
:on "1"
:off "0"
:format "%[%v%]"
:notify (lambda (this-widget changed-widget &optional change-event)
(let ((this-bit-index ,index))
(message (format "Bit Index Changing: %d" this-bit-index))
(message (format "Current Hex Value %d" (string-to-number
(widget-value bw/hex-value) 16)))
(if (equal (widget-value this-widget) t)
(widget-value-set bw/hex-value
(format "%x"
(logior (string-to-number
(widget-value bw/hex-value) 16)
(lsh 1 this-bit-index))))
(widget-value-set bw/hex-value
(format "%x"
(logand (string-to-number
(widget-value bw/hex-value) 16)
(lognot
(lsh 1 this-bit-index)))))
))
(widget-setup)
))
)
It should generate a toggle widget that shows "1" for on and "0" for off. The notify function will then take that bit, create a bit mask and either set or clear the bit in another variable that is displayed elsewhere in the widget.
This works if I basically take the expanded macro code and manually use it. However, I want to have up to 64 of these widgets. I feel like this is a great use case for macros.
I want to have essentially a list of these widgets that I can access by indexing their element in the list.When I expand the macro in ielm it looks like this:
ELISP> (macroexpand '(bw/gen-bit-toggle 1))
(widget-create 'toggle :on "1" :off "0" :format "%[%v%]" :notify
(lambda
(this-widget changed-widget &optional change-event)
(let
((this-bit-index 1))
(message
(format "This Widget: %s"
(widget-value this-widget)))
(message
(format "Bit Index Changing: %d" this-bit-index))
(message
(format "Current Hex Value %d"
(string-to-number
(widget-value bw/hex-value)
16)))
(if
(equal
(widget-value this-widget)
t)
(widget-value-set bw/hex-value
(format "%x"
(logior
(string-to-number
(widget-value bw/hex-value)
16)
(lsh 1 this-bit-index))))
(widget-value-set bw/hex-value
(format "%x"
(logand
(string-to-number
(widget-value bw/hex-value)
16)
(lognot
(lsh 1 this-bit-index)))))))
(widget-setup)))
The "this-bit-index" variable in the let binding is really the only part that is different from each widget notify function.
When I "call" (probably not the correct term, invoke?) the macro it looks like this:
ELISP> (bw/gen-bit-toggle 1)
(toggle :on "1" :off "0" :format "%[%v%]" :notify
(closure
(t)
(this-widget changed-widget &optional change-event)
(let
((this-bit-index 1))
(message
(format "Bit Index Changing: %d" this-bit-index))
(message
(format "Current Hex Value %d"
(string-to-number
(widget-value bw/hex-value)
16)))
(if
(equal
(widget-value this-widget)
t)
(widget-value-set bw/hex-value
(format "%x"
(logior
(string-to-number
(widget-value bw/hex-value)
16)
(lsh 1 this-bit-index))))
(widget-value-set bw/hex-value
(format "%x"
(logand
(string-to-number
(widget-value bw/hex-value)
16)
(lognot
(lsh 1 this-bit-index)))))))
(widget-setup))
The expanded macro looks like what I want. However, when it is called it takes a different form and seems to lop off the "widget-create" function call. The intention is to use this macro multiple times to have a list of these widget objects. I feel like I'm really close but I'm at the point where I'm randomly adding quotes, backticks, and commas and getting nowhere. Does anyone see issues with the macro definition?