Skip to content

Commit d000c62

Browse files
xiongtxbbatsov
authored andcommitted
Use different modes for spec list, specs, and examples
Fixes #2035 and fixes #2036. - `cider-browse-spec` now has its own major mode, `cider-browse-spec-view-mode`, which derives from `help-mode` and has forward/back xrefs. - `cider-browse-spec--print-curr-spec-example` now puts examples in a buffer with `cider-browse-spec-example-mode`. This allows using `revert-buffer` to generate new examples. - The `cider-browse-spec-navigation` stack variable and related functionality are removed. - `cider-browse-spec-view-mode` now derives from `help-mode`, which maintains its own stack variables. Future improvements: - Allow using `TAB` and `<backtab>` in `cider-browse-spec-view-mode` to invoke `cider-browse-spec--next-spec` and `cider-browse-spec--prev-spec` respectively.
1 parent 04cad13 commit d000c62

File tree

1 file changed

+96
-76
lines changed

1 file changed

+96
-76
lines changed

cider-browse-spec.el

Lines changed: 96 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
;;
2626
;; Display a spec description you can browse.
2727
;; Pressing <enter> over a sub spec will take you to the description of that sub spec.
28-
;; Pressing ^ will take you up in the navigation stack.
28+
;; Pressing ^ takes you to the list of all specs.
2929

3030
;; M-x cider-browse-spec-all
3131
;;
@@ -47,12 +47,6 @@
4747
(defconst cider-browse-spec-buffer "*cider-spec-browser*")
4848
(add-to-list 'cider-ancillary-buffers cider-browse-spec-buffer)
4949

50-
(defvar cider-browse-spec-navigation '()
51-
"Keeps the cider spec browser navigation stack.
52-
A list of strings which are specs or specs searches.
53-
First of the list is the top of the stack.
54-
Specs searches are encoded as (search \"regex\")
55-
For example: (\":ring.request/header-name\" \":ring.request/headers\" \":ring/request\" (search \"ring.+\"))")
5650
(defconst cider-browse-spec-example-buffer "*cider-spec-example*")
5751
(add-to-list 'cider-ancillary-buffers cider-browse-spec-example-buffer)
5852

@@ -62,11 +56,10 @@ For example: (\":ring.request/header-name\" \":ring.request/headers\" \":ring/re
6256
(let ((map (make-sparse-keymap)))
6357
(set-keymap-parent map cider-popup-buffer-mode-map)
6458
(define-key map (kbd "RET") #'cider-browse-spec--browse-at-point)
65-
(define-key map "^" #'cider-browse-spec--navigate-back)
6659
(define-key map "n" #'cider-browse-spec--next-spec)
6760
(define-key map "p" #'cider-browse-spec--prev-spec)
68-
(define-key map "e" #'cider-browse-spec--print-curr-spec-example)
69-
map))
61+
map)
62+
"Keymap for `cider-browse-spec-mode'.")
7063

7164
(defvar cider-browse-spec-mouse-map
7265
(let ((map (make-sparse-keymap)))
@@ -81,11 +74,47 @@ For example: (\":ring.request/header-name\" \":ring.request/headers\" \":ring/re
8174
(when cider-special-mode-truncate-lines
8275
(setq-local truncate-lines t)))
8376

84-
;; Non interactive functions
77+
(defvar cider-browse-spec--current-spec nil)
78+
79+
(defvar cider-browse-spec-view-mode-map
80+
(let ((map (make-sparse-keymap)))
81+
(set-keymap-parent map help-mode-map)
82+
(define-key map (kbd "RET") #'cider-browse-spec--browse-at-point)
83+
(define-key map "^" #'cider-browse-spec-all)
84+
(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)
87+
map)
88+
"Keymap for `cider-browse-spec-view-mode'.")
8589

86-
(defun cider-browse-spec--clear-nav-history ()
87-
"Clears `cider-browse-spec-navigation'."
88-
(setq cider-browse-spec-navigation '()))
90+
(define-derived-mode cider-browse-spec-view-mode help-mode "Spec view"
91+
"Major mode for displaying CIDER spec.
92+
93+
\\{cider-browse-spec-view-mode-map}"
94+
(setq-local cider-browse-spec--current-spec nil)
95+
(setq-local electric-indent-chars nil)
96+
(when cider-special-mode-truncate-lines
97+
(setq-local truncate-lines t)))
98+
99+
(defvar cider-browse-spec-example-mode-map
100+
(let ((map (make-sparse-keymap)))
101+
(set-keymap-parent map cider-popup-buffer-mode-map)
102+
(define-key map "^" #'cider-browse-spec-all)
103+
(define-key map "e" #'cider-browse-spec--print-curr-spec-example)
104+
(define-key map "g" #'revert-buffer)
105+
map)
106+
"Keymap for `cider-browse-spec-example-mode'.")
107+
108+
(define-derived-mode cider-browse-spec-example-mode special-mode "Example"
109+
"Major mode for Clojure spec examples.
110+
111+
\\{cider-browse-spec-example-mode-map}"
112+
(setq-local electric-indent-chars nil)
113+
(setq-local revert-buffer-function #'cider-browse-spec--example-revert-buffer-function)
114+
(when cider-special-mode-truncate-lines
115+
(setq-local truncate-lines t)))
116+
117+
;; Non interactive functions
89118

90119
(defun cider-browse-spec--propertize-keyword (kw)
91120
"Add properties to KW text needed by the spec browser."
@@ -220,8 +249,8 @@ Display TITLE at the top and SPECS are indented underneath."
220249
(format "(s/fspec \n %s)")))
221250
;; every other with no special management
222251
(t (format "(%s %s)"
223-
(cider-browse-spec--pprint form-tag)
224-
(string-join (mapcar #'cider-browse-spec--pprint (cl-rest form)) " "))))))
252+
(cider-browse-spec--pprint form-tag)
253+
(string-join (mapcar #'cider-browse-spec--pprint (cl-rest form)) " "))))))
225254
(t (format "%s" form))))
226255

227256
(defun cider-browse-spec--draw-spec-buffer (buffer spec spec-form)
@@ -230,8 +259,7 @@ Display SPEC as a title and uses `cider-browse-spec--pprint' to display
230259
a more user friendly representation of SPEC-FORM."
231260
(with-current-buffer buffer
232261
(let ((inhibit-read-only t))
233-
(cider-browse-spec-mode)
234-
(erase-buffer)
262+
(cider--help-setup-xref (list #'cider-browse-spec spec) nil buffer)
235263
(goto-char (point-max))
236264
(insert (cider-font-lock-as-clojure spec) "\n\n")
237265
(insert (with-temp-buffer
@@ -240,25 +268,21 @@ a more user friendly representation of SPEC-FORM."
240268
(indent-region (point-min) (point-max))
241269
(font-lock-ensure)
242270
(buffer-string)))
243-
(insert "\n\n")
244-
(insert-text-button "[Back]"
245-
'action (lambda (b) (call-interactively 'cider-browse-spec--navigate-back))
246-
'follow-link t)
247-
(goto-char (point-min)))))
271+
(cider--make-back-forward-xrefs)
272+
(current-buffer))))
248273

249274
(defun cider-browse-spec--browse (spec)
250-
"Browse SPEC pushing it into `cider-browse-spec-navigation'."
275+
"Browse SPEC."
276+
(cider-ensure-connected)
277+
(cider-ensure-op-supported "spec-form")
251278
(with-current-buffer (cider-popup-buffer cider-browse-spec-buffer t)
252-
(push spec cider-browse-spec-navigation)
279+
(cider-browse-spec-view-mode)
280+
(setq-local cider-browse-spec--current-spec spec)
253281
(cider-browse-spec--draw-spec-buffer (current-buffer)
254-
spec
255-
(cider-sync-request:spec-form spec))))
256-
257-
(defun cider-browse-spec--is-nav-searchp (str-filter)
258-
"Return non nil if STR-FILTER is a filter term."
259-
(and (listp str-filter)
260-
(eq (car str-filter) 'search)))
261-
282+
spec
283+
(cider-sync-request:spec-form spec))
284+
(goto-char (point-min))
285+
(current-buffer)))
262286

263287
;; Interactive Functions
264288

@@ -267,7 +291,7 @@ a more user friendly representation of SPEC-FORM."
267291
(interactive)
268292
(goto-char (next-single-property-change (point) 'spec-name))
269293
(unless (get-text-property (point) 'spec-name)
270-
(goto-char (next-single-property-change (point) 'spec-name))))
294+
(goto-char (next-single-property-change (point) 'spec-name))))
271295

272296
(defun cider-browse-spec--prev-spec ()
273297
"Move to the previous spec in the buffer."
@@ -277,66 +301,62 @@ a more user friendly representation of SPEC-FORM."
277301
(goto-char (previous-single-property-change (point) 'spec-name))))
278302

279303
(defun cider-browse-spec--print-curr-spec-example ()
280-
"Generate and print a spec example of the current spec in `cider-browse-spec-navigation'."
304+
"Generate and print an example of the current spec."
281305
(interactive)
282-
(when cider-browse-spec-navigation
283-
(let* ((spec (cl-first cider-browse-spec-navigation))
284-
(example (cider-sync-request:spec-example spec)))
285-
(with-current-buffer (cider-popup-buffer cider-browse-spec-example-buffer t)
286-
(cider-browse-spec-mode)
287-
(let ((inhibit-read-only t))
288-
(erase-buffer)
289-
(goto-char (point-max))
290-
(insert (cider-propertize (concat "Example of: " spec) 'emph) "\n\n")
291-
(insert example)
292-
(goto-char (point-min)))))))
306+
(cider-ensure-connected)
307+
(cider-ensure-op-supported "spec-example")
308+
(if-let ((spec cider-browse-spec--current-spec))
309+
(if-let ((example (cider-sync-request:spec-example spec)))
310+
(with-current-buffer (cider-popup-buffer cider-browse-spec-example-buffer t)
311+
(cider-browse-spec-example-mode)
312+
(setq-local cider-browse-spec--current-spec spec)
313+
(let ((inhibit-read-only t))
314+
(insert "Example of " (cider-font-lock-as-clojure spec))
315+
(insert "\n\n")
316+
(insert (cider-font-lock-as-clojure example))
317+
(goto-char (point-min))))
318+
(error (format "No example for spec %s" spec)))
319+
(error "No current spec")))
320+
321+
(defun cider-browse-spec--example-revert-buffer-function (&rest _)
322+
"`revert-buffer' function for `cider-browse-spec-example-mode'.
323+
324+
Generates a new example for the current spec."
325+
(cider-browse-spec--print-curr-spec-example))
293326

294327
;;;###autoload
295328
(defun cider-browse-spec (spec)
296-
"Start a new navigation and browse to SPEC definition."
329+
"Browse SPEC definition."
297330
(interactive (list (completing-read "Browse spec: "
298331
(cider-sync-request:spec-list)
299332
nil nil
300333
(cider-symbol-at-point))))
301-
(cider-browse-spec--clear-nav-history)
302334
(cider-browse-spec--browse spec))
303335

304-
305336
;;;###autoload
306-
(defun cider-browse-spec-all (&optional filter-regex)
307-
"List all loaded specs in BUFFER filtered by FILTER-REGEX.
308-
309-
Optional argument FILTER-REGEX is a regexp string matching spec names. The
310-
default value, \"\", matches all specs in the registry."
311-
(interactive (list (read-string "Filter regex: ")))
312-
(with-current-buffer (cider-popup-buffer cider-browse-spec-buffer t)
313-
(let ((specs (cider-sync-request:spec-list filter-regex)))
314-
(cider-browse-spec--clear-nav-history)
315-
(push `(search ,filter-regex) cider-browse-spec-navigation)
316-
(cider-browse-spec--draw-list-buffer (current-buffer)
317-
(if (string-empty-p filter-regex)
318-
"All specs in registry"
319-
(format "All specs matching regex `%s' in registry" filter-regex))
320-
specs))))
337+
(defun cider-browse-spec-all (&optional arg)
338+
"Open list of specs in a popup buffer.
339+
340+
With a prefix argument ARG, prompts for a regexp to filter specs.
341+
No filter applied if the regexp is the empty string."
342+
(interactive "P")
343+
(cider-ensure-connected)
344+
(cider-ensure-op-supported "spec-list")
345+
(let ((filter-regex (if arg (read-string "Filter regex: ") "")))
346+
(with-current-buffer (cider-popup-buffer cider-browse-spec-buffer t)
347+
(let ((specs (cider-sync-request:spec-list filter-regex)))
348+
(cider-browse-spec--draw-list-buffer (current-buffer)
349+
(if (string-empty-p filter-regex)
350+
"All specs in registry"
351+
(format "All specs matching regex `%s' in registry" filter-regex))
352+
specs)))))
321353

322354
(defun cider-browse-spec--browse-at-point ()
323355
"Go to the definition of the spec at point inside `cider-browse-spec-buffer'."
324356
(interactive)
325357
(when-let ((spec (get-text-property (point) 'spec-name)))
326358
(cider-browse-spec--browse spec)))
327359

328-
(defun cider-browse-spec--navigate-back ()
329-
"Move the browser back in `cider-browse-spec-navigation'."
330-
(interactive)
331-
(if (> (length cider-browse-spec-navigation) 1)
332-
(progn
333-
(pop cider-browse-spec-navigation) ;; discard current
334-
(if (cider-browse-spec--is-nav-searchp (cl-first cider-browse-spec-navigation))
335-
(cider-browse-spec-all (cl-second (pop cider-browse-spec-navigation)))
336-
(cider-browse-spec--browse (pop cider-browse-spec-navigation))))
337-
(unless (cider-browse-spec--is-nav-searchp (cl-first cider-browse-spec-navigation))
338-
(cider-browse-spec-all))))
339-
340360
(defun cider-browse-spec-handle-mouse (event)
341361
"Handle mouse click EVENT."
342362
(interactive "e")

0 commit comments

Comments
 (0)