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; ;
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
230259a 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