1+ (in-package :transient )
2+
3+ (defmethod keymap-activate ((keymap keymap))
4+ (log :info " keymap ~A activated" keymap)
5+ (show-transient keymap))
6+
7+ (defmacro add-dynamic-property (class-name properties-accessor property-name &optional default-value)
8+ " define <CLASS-NAME>-<PROPERTY-NAME> getter and setter methods.
9+
10+ the getter retrieves from PROPERTIES-ACCESSOR using :PROPERTY-NAME as key.
11+ if the value is a function, it funcalls it. the setter stores directly.
12+ if DEFAULT-VALUE is provided and non-nil, it is used as the default for getf."
13+ (let* ((keyword (intern (symbol-name property-name) :keyword ))
14+ (getter-name (intern (format nil " ~A -~A " class-name property-name)))
15+ (obj-sym (gensym " OBJ" )))
16+ ` (progn
17+ (defmethod , getter-name ((, obj-sym , class-name))
18+ (let ((prop , (if default-value
19+ ` (getf (, properties-accessor , obj-sym) , keyword , default-value)
20+ ` (getf (, properties-accessor , obj-sym) , keyword))))
21+ (if (functionp prop)
22+ (funcall prop)
23+ prop)))
24+ (defmethod (setf , getter-name ) (val (, obj-sym , class-name))
25+ (setf (getf (, properties-accessor , obj-sym) , keyword) val)))))
26+
27+ (add-dynamic-property keymap keymap-properties show-p t )
28+ (add-dynamic-property prefix prefix-properties show-p t )
29+
30+ (defgeneric prefix-render (prefix)
31+ (:documentation " render prefix into a layout item. returns nil to use default rendering." ))
32+
33+ ; ; should return :row or :column
34+ (defmethod keymap-display-style ((keymap keymap))
35+ (getf (keymap-properties keymap) :display-style :row ))
36+
37+ (defmethod (setf keymap-display-style ) (val (keymap keymap))
38+ (setf (getf (keymap-properties keymap) :display-style ) val))
39+
40+ (defclass choice (prefix)
41+ ((choices
42+ :accessor prefix-choices)))
43+
44+ (defmacro define-transient (name &body bindings)
45+ ` (defparameter , name (parse-transient ' ,bindings)))
46+
47+ (defun parse-transient (bindings)
48+ (let ((keymap (make-keymap)))
49+ (loop for tail = bindings then (cdr tail)
50+ while tail
51+ do (let ((binding (car tail)))
52+ (cond
53+ ; ; inline property
54+ ((keywordp binding)
55+ (let ((val (second tail)))
56+ (setf (getf (keymap-properties keymap) binding) val))
57+ ; ; advance another cell because we're already consumed it (second tail)
58+ (setf tail (cdr tail)))
59+ ; ; direct child keymap (:keymap ...)
60+ ((eq (car binding) :keymap )
61+ (let ((sub-map (parse-transient (cdr binding))))
62+ (keymap-add-child keymap sub-map t )))
63+ ; ; key binding (:key ...)
64+ ((eq (car binding) :key )
65+ (let* ((key (second binding))
66+ ; ; prefix-class depends on the first cell in the :suffix value (if its a list at all)
67+ (prefix-type (intern (symbol-name (getf binding :type ' prefix))))
68+ (prefix (make-instance prefix-type)))
69+ (setf (prefix-key prefix) (car (parse-keyspec key)))
70+ ; ; sometimes the suffix will not be set (e.g. prefix-type is :choice). we
71+ ; ; initialize it to nil to avoid unbound errors.
72+ (setf (prefix-suffix prefix) nil )
73+ (loop for (key value) on (cddr binding) by ' cddr
74+ ; ; key-method is used for (setf prefix-<key-method> <value>)
75+ for key-method = (intern (format nil " PREFIX-~A " (string key)))
76+ do (let ((setf-expr ` (setf (, key-method prefix) value))
77+ (final-value)
78+ (should-set t ))
79+ (cond
80+ ; ; if the suffix is a keymap we need to parse recursively
81+ ((and (listp value) (eq (car value) :keymap ))
82+ (setf final-value (parse-transient value)))
83+ ((eq key :type )
84+ (setf should-set nil ))
85+ (t
86+ (setf final-value value)))
87+ (when should-set
88+ (funcall (fdefinition (list ' setf key-method))
89+ final-value
90+ prefix))))
91+ (keymap-add-prefix keymap prefix t ))))))
92+ keymap))
0 commit comments