Skip to content

Commit d980ec3

Browse files
committed
make popup more informative
1 parent 7a213e7 commit d980ec3

File tree

8 files changed

+544
-78
lines changed

8 files changed

+544
-78
lines changed

extensions/transient/demo.lisp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
(in-package :transient)
2+
3+
(define-transient *demo-keymap*
4+
:display-style :row
5+
(:keymap
6+
:display-style :column
7+
:description "file operations"
8+
(:key "o" :suffix demo-open :description "demo open")
9+
(:key "s" :suffix demo-save :description "demo save (disabled)" :active-p nil)
10+
(:key "w" :suffix demo-write :description "demo write")
11+
(:key "x"
12+
:suffix (:keymap
13+
(:key "p" :suffix demo-pdf :description "pdf")
14+
(:key "h" :suffix demo-html :description "html")
15+
(:key "m" :suffix demo-md :description "markdown"))
16+
:description "export format"))
17+
(:keymap
18+
:display-style :column
19+
:description "edit operations"
20+
(:key "c" :suffix demo-copy)
21+
(:key "v" :suffix demo-paste)
22+
(:key "u" :suffix demo-undo))
23+
(:key "f"
24+
:suffix (:keymap
25+
(:key "g" :suffix demo-grep :description "grep")
26+
(:key "f" :suffix demo-find :description "find")
27+
(:key "r" :suffix demo-replace :description "replace"))
28+
:description "search menu")
29+
(:key "t"
30+
:suffix (:keymap
31+
:display-style :row
32+
(:keymap
33+
:description "languages"
34+
(:key "l"
35+
:type :choice
36+
:choices ("lisp" "python" "js")
37+
:description "mode"))
38+
(:keymap
39+
:description "editor"
40+
(:key "v"
41+
:type :choice
42+
:choices ("vim" "emacs")
43+
:description "keys")))
44+
:description "langs demo")
45+
(:key "d"
46+
:type :choice
47+
:choices ("on" "off")
48+
:description "debug toggle"))
49+
50+
(define-key *global-keymap* "C-c t" *demo-keymap*)

extensions/transient/keymap.lisp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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

Comments
 (0)