Just call the :define-key
method from a keymap object, and pass the command's name with its arguments in a tuple:
(def keymap (:new-keymap (in jwno/context :key-manager))) # Create a new keymap
(:define-key keymap "Win + ," [:split-frame :horizontal 2]
"Split current frame horizontally")
Here :split-frame
is the name of our command. :horizontal
and 2
are its arguments. If a command takes no argument, you can pass only the name, without putting it in a tuple:
(:define-key keymap "Win + Shift + Q" :quit
"Tell Jwno to exit")
The code above is equivalent to:
(:define-key keymap "Win + Shift + Q" [:quit]
"Tell Jwno to exit")
About Function Arguments Passed to a Command
Some commands can accept function arguments, to carry out complex user-defined operations. But due to some limitations of Jwno's current threading model, functions passed to a command should not access mutable states outside of its own scope.
For example, this won't work as expected:
(var my-flag false)
(defn my-fn [& args]
(if my-flag
:do-this
# else
:do-that))
(:define-key my-keymap "Win + ," [:split-frame :horizontal 2 nil my-fn]
"Split current frame horizontally, then call my-fn.")
(:set-keymap (in jwno/context :key-manager) my-keymap)
...
# Try to set my-flag to change my-fn's behavior at some point
(set my-flag true)
One would expect that the :do-this
branch will get executed after setting my-flag
, but the code will keep running :do-that
instead, since the mutable state of my-flag
will be lost after the :set-keymap
call.
To preserve your sanity, the simplest rule is, in functions passed to commands, only access their arguments, and nothing else. In the example above, you can safely access the args
argument variable in my-fn
, and things will work as expected.
If you're curious about the lower-level details, here's a hint: Jwno is completely lock-free despite being multi-threaded, and to achieve that, it will "freeze" all mutable states and marshal them, before sending them between threads.