Skip to content

Commit f2a5e27

Browse files
xiongtxbbatsov
authored andcommitted
Use buttons in spec browser buffers
Fixes #2053. Replace custom text properties with buttons. This gives us highlights, clicks, and navigation for free.
1 parent baa9986 commit f2a5e27

File tree

1 file changed

+33
-62
lines changed

1 file changed

+33
-62
lines changed

cider-browse-spec.el

Lines changed: 33 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,14 @@
5454

5555
(defvar cider-browse-spec-mode-map
5656
(let ((map (make-sparse-keymap)))
57-
(set-keymap-parent map cider-popup-buffer-mode-map)
58-
(define-key map (kbd "RET") #'cider-browse-spec--browse-at-point)
59-
(define-key map "n" #'cider-browse-spec--next-spec)
60-
(define-key map "p" #'cider-browse-spec--prev-spec)
57+
(set-keymap-parent map (make-composed-keymap button-buffer-map
58+
cider-popup-buffer-mode-map))
59+
(define-key map (kbd "RET") #'cider-browse-spec--browse-at)
60+
(define-key map "n" #'forward-button)
61+
(define-key map "p" #'backward-button)
6162
map)
6263
"Keymap for `cider-browse-spec-mode'.")
6364

64-
(defvar cider-browse-spec-mouse-map
65-
(let ((map (make-sparse-keymap)))
66-
(define-key map [mouse-1] #'cider-browse-spec-handle-mouse)
67-
map))
68-
6965
(define-derived-mode cider-browse-spec-mode special-mode "Specs"
7066
"Major mode for browsing Clojure specs.
7167
@@ -79,11 +75,11 @@
7975
(defvar cider-browse-spec-view-mode-map
8076
(let ((map (make-sparse-keymap)))
8177
(set-keymap-parent map help-mode-map)
82-
(define-key map (kbd "RET") #'cider-browse-spec--browse-at-point)
78+
(define-key map (kbd "RET") #'cider-browse-spec--browse-at)
8379
(define-key map "^" #'cider-browse-spec-all)
8480
(define-key map "e" #'cider-browse-spec--print-curr-spec-example)
85-
(define-key map "n" #'cider-browse-spec--next-spec)
86-
(define-key map "p" #'cider-browse-spec--prev-spec)
81+
(define-key map "n" #'forward-button)
82+
(define-key map "p" #'backward-button)
8783
map)
8884
"Keymap for `cider-browse-spec-view-mode'.")
8985

@@ -116,20 +112,11 @@
116112

117113
;; Non interactive functions
118114

119-
(defun cider-browse-spec--propertize-keyword (kw)
120-
"Add properties to KW text needed by the spec browser."
121-
(propertize (cider-font-lock-as-clojure kw)
122-
'spec-name kw
123-
'mouse-face 'highlight
124-
'keymap cider-browse-spec-mouse-map))
125-
126-
(defun cider-browse-spec--propertize-fn (fname)
127-
"Add properties to FNAME symbol text needed by the spec browser."
128-
(propertize fname
129-
'font-lock-face 'font-lock-function-name-face
130-
'spec-name fname
131-
'mouse-face 'highlight
132-
'keymap cider-browse-spec-mouse-map))
115+
(define-button-type 'cider-browse-spec--spec
116+
'action #'cider-browse-spec--browse-at
117+
'face nil
118+
'follow-link t
119+
'help-echo "View spec")
133120

134121
(defun cider-browse-spec--draw-list-buffer (buffer title specs)
135122
"Reset contents of BUFFER.
@@ -141,12 +128,11 @@ Display TITLE at the top and SPECS are indented underneath."
141128
(goto-char (point-max))
142129
(insert (cider-propertize title 'emph) "\n")
143130
(dolist (spec-name specs)
144-
(let ((propertize-fn (if (char-equal (elt spec-name 0) ?:)
145-
#'cider-browse-spec--propertize-keyword
146-
#'cider-browse-spec--propertize-fn)))
147-
(thread-first (concat " " (funcall propertize-fn spec-name) "\n")
148-
(propertize 'spec-name spec-name)
149-
insert)))
131+
(insert (propertize " " 'spec-name spec-name))
132+
(thread-first (cider-font-lock-as-clojure spec-name)
133+
(insert-text-button 'type 'cider-browse-spec--spec)
134+
(button-put 'spec-name spec-name))
135+
(insert (propertize "\n" 'spec-name spec-name)))
150136
(goto-char (point-min)))))
151137

152138
(defun cider--qualified-keyword-p (str)
@@ -161,7 +147,11 @@ Display TITLE at the top and SPECS are indented underneath."
161147
"Given a spec FORM builds a multi line string with a pretty render of that FORM."
162148
(cond ((stringp form)
163149
(if (cider--qualified-keyword-p form)
164-
(cider-browse-spec--propertize-keyword form)
150+
(with-temp-buffer
151+
(thread-first form
152+
(insert-text-button 'type 'cider-browse-spec--spec)
153+
(button-put 'spec-name form))
154+
(buffer-string))
165155
;; to make it easier to read replace all clojure.spec ns with s/
166156
;; and remove all clojure.core ns
167157
(thread-last form
@@ -284,25 +274,18 @@ a more user friendly representation of SPEC-FORM."
284274
(goto-char (point-min))
285275
(current-buffer)))
286276

287-
;; Interactive Functions
277+
(defun cider-browse-spec--browse-at (&optional pos)
278+
"View the definition of a spec.
288279
289-
(defun cider-browse-spec--next-spec ()
290-
"Move to the next spec in the buffer."
291-
(interactive)
292-
(when-let ((pos (next-single-property-change (point) 'spec-name)))
293-
(if (get-text-property (point) 'spec-name)
294-
(when-let ((next-pos (next-single-property-change pos 'spec-name)))
295-
(goto-char next-pos))
296-
(goto-char pos))))
297-
298-
(defun cider-browse-spec--prev-spec ()
299-
"Move to the previous spec in the buffer."
280+
Optional argument POS is the position of a spec, defaulting to point. POS
281+
may also be a button, so this function can be used a the button's `action'
282+
property."
300283
(interactive)
301-
(when-let ((pos (previous-single-property-change (point) 'spec-name)))
302-
(if (get-text-property (point) 'spec-name)
303-
(when-let ((prev-pos (previous-single-property-change pos 'spec-name)))
304-
(goto-char prev-pos))
305-
(goto-char pos))))
284+
(let ((pos (or pos (point))))
285+
(when-let ((spec (button-get pos 'spec-name)))
286+
(cider-browse-spec--browse spec))))
287+
288+
;; Interactive Functions
306289

307290
(defun cider-browse-spec--print-curr-spec-example ()
308291
"Generate and print an example of the current spec."
@@ -355,18 +338,6 @@ No filter applied if the regexp is the empty string."
355338
(format "All specs matching regex `%s' in registry" filter-regex))
356339
specs)))))
357340

358-
(defun cider-browse-spec--browse-at-point ()
359-
"Go to the definition of the spec at point inside `cider-browse-spec-buffer'."
360-
(interactive)
361-
(when-let ((spec (get-text-property (point) 'spec-name)))
362-
(cider-browse-spec--browse spec)))
363-
364-
(defun cider-browse-spec-handle-mouse (event)
365-
"Handle mouse click EVENT."
366-
(interactive "e")
367-
(when (eq 'highlight (get-text-property (point) 'mouse-face))
368-
(cider-browse-spec--browse-at-point)))
369-
370341
(provide 'cider-browse-spec)
371342

372343
;;; cider-browse-spec.el ends here

0 commit comments

Comments
 (0)