dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

cider-inspector.el (22551B)


      1 ;;; cider-inspector.el --- Object inspector -*- lexical-binding: t -*-
      2 
      3 ;; Copyright © 2013-2014 Vital Reactor, LLC
      4 ;; Copyright © 2014-2023  Bozhidar Batsov and CIDER contributors
      5 
      6 ;; Author: Ian Eslick <ian@vitalreactor.com>
      7 ;;         Bozhidar Batsov <bozhidar@batsov.dev>
      8 
      9 ;; This program is free software: you can redistribute it and/or modify
     10 ;; it under the terms of the GNU General Public License as published by
     11 ;; the Free Software Foundation, either version 3 of the License, or
     12 ;; (at your option) any later version.
     13 
     14 ;; This program is distributed in the hope that it will be useful,
     15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 ;; GNU General Public License for more details.
     18 
     19 ;; You should have received a copy of the GNU General Public License
     20 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 ;; This file is not part of GNU Emacs.
     23 
     24 ;;; Commentary:
     25 
     26 ;; Clojure object inspector inspired by SLIME.
     27 
     28 ;;; Code:
     29 
     30 (require 'cl-lib)
     31 (require 'easymenu)
     32 (require 'seq)
     33 (require 'cider-eval)
     34 
     35 ;; ===================================
     36 ;; Inspector Key Map and Derived Mode
     37 ;; ===================================
     38 
     39 (defconst cider-inspector-buffer "*cider-inspect*")
     40 
     41 ;;; Customization
     42 (defgroup cider-inspector nil
     43   "Presentation and behavior of the CIDER value inspector."
     44   :prefix "cider-inspector-"
     45   :group 'cider
     46   :package-version '(cider . "0.10.0"))
     47 
     48 (defcustom cider-inspector-page-size 32
     49   "Default page size in paginated inspector view.
     50 The page size can be also changed interactively within the inspector."
     51   :type '(integer :tag "Page size" 32)
     52   :package-version '(cider . "0.10.0"))
     53 
     54 (defcustom cider-inspector-max-atom-length 150
     55   "Default max length of nested atoms before they are truncated.
     56 'Atom' here means any collection member that satisfies (complement coll?).
     57 The max length can be also changed interactively within the inspector."
     58   :type '(integer :tag "Max atom length" 150)
     59   :package-version '(cider . "1.1.0"))
     60 
     61 (defcustom cider-inspector-max-coll-size 5
     62   "Default number of nested collection members to display before truncating.
     63 The max size can be also changed interactively within the inspector."
     64   :type '(integer :tag "Max collection size" 5)
     65   :package-version '(cider . "1.1.0"))
     66 
     67 (defcustom cider-inspector-fill-frame nil
     68   "Controls whether the CIDER inspector window fills its frame."
     69   :type 'boolean
     70   :package-version '(cider . "0.15.0"))
     71 
     72 (defcustom cider-inspector-skip-uninteresting t
     73   "Controls whether to skip over uninteresting values in the inspector.
     74 Only applies to navigation with `cider-inspector-prev-inspectable-object'
     75 and `cider-inspector-next-inspectable-object', values are still inspectable
     76 by clicking or navigating to them by other means."
     77   :type 'boolean
     78   :package-version '(cider . "0.25.0"))
     79 
     80 (defcustom cider-inspector-auto-select-buffer t
     81   "Determines if the inspector buffer should be auto selected."
     82   :type 'boolean
     83   :package-version '(cider . "0.27.0"))
     84 
     85 (defvar cider-inspector-uninteresting-regexp
     86   (concat "nil"                      ; nils are not interesting
     87           "\\|:" clojure--sym-regexp ; nor keywords
     88           ;; FIXME: This range also matches ",", is it on purpose?
     89           "\\|[+-.0-9]+")            ; nor numbers. Note: BigInts, ratios etc. are interesting
     90   "Regexp of uninteresting and skippable values.")
     91 
     92 (defvar cider-inspector-mode-map
     93   (let ((map (make-sparse-keymap)))
     94     (set-keymap-parent map cider-popup-buffer-mode-map)
     95     (define-key map (kbd "RET") #'cider-inspector-operate-on-point)
     96     (define-key map [mouse-1] #'cider-inspector-operate-on-click)
     97     (define-key map "l" #'cider-inspector-pop)
     98     (define-key map "g" #'cider-inspector-refresh)
     99     ;; Page-up/down
    100     (define-key map [next] #'cider-inspector-next-page)
    101     (define-key map [prior] #'cider-inspector-prev-page)
    102     (define-key map " " #'cider-inspector-next-page)
    103     (define-key map (kbd "M-SPC") #'cider-inspector-prev-page)
    104     (define-key map (kbd "S-SPC") #'cider-inspector-prev-page)
    105     (define-key map "s" #'cider-inspector-set-page-size)
    106     (define-key map "a" #'cider-inspector-set-max-atom-length)
    107     (define-key map "c" #'cider-inspector-set-max-coll-size)
    108     (define-key map "d" #'cider-inspector-def-current-val)
    109     (define-key map [tab] #'cider-inspector-next-inspectable-object)
    110     (define-key map "\C-i" #'cider-inspector-next-inspectable-object)
    111     (define-key map "n" #'cider-inspector-next-inspectable-object)
    112     (define-key map [(shift tab)] #'cider-inspector-previous-inspectable-object)
    113     (define-key map "p" #'cider-inspector-previous-inspectable-object)
    114     (define-key map "f" #'forward-char)
    115     (define-key map "b" #'backward-char)
    116     ;; Emacs translates S-TAB to BACKTAB on X.
    117     (define-key map [backtab] #'cider-inspector-previous-inspectable-object)
    118     (easy-menu-define cider-inspector-mode-menu map
    119       "Menu for CIDER's inspector."
    120       `("CIDER Inspector"
    121         ["Inspect" cider-inspector-operate-on-point]
    122         ["Pop" cider-inspector-pop]
    123         ["Refresh" cider-inspector-refresh]
    124         "--"
    125         ["Next Inspectable Object" cider-inspector-next-inspectable-object]
    126         ["Previous Inspectable Object" cider-inspector-previous-inspectable-object]
    127         "--"
    128         ["Next Page" cider-inspector-next-page]
    129         ["Previous Page" cider-inspector-prev-page]
    130         ["Set Page Size" cider-inspector-set-page-size]
    131         ["Set Max Atom Length" cider-inspector-set-max-atom-length]
    132         ["Set Max Collection Size" cider-inspector-set-max-coll-size]
    133         ["Define Var" cider-inspector-def-current-val]
    134         "--"
    135         ["Quit" cider-popup-buffer-quit-function]
    136         ))
    137     map))
    138 
    139 (define-derived-mode cider-inspector-mode special-mode "Inspector"
    140   "Major mode for inspecting Clojure data structures.
    141 
    142 \\{cider-inspector-mode-map}"
    143   (set-syntax-table clojure-mode-syntax-table)
    144   (setq-local electric-indent-chars nil)
    145   (setq-local sesman-system 'CIDER)
    146   (visual-line-mode 1))
    147 
    148 ;;;###autoload
    149 (defun cider-inspect-last-sexp ()
    150   "Inspect the result of the the expression preceding point."
    151   (interactive)
    152   (cider-inspect-expr (cider-last-sexp) (cider-current-ns)))
    153 
    154 ;;;###autoload
    155 (defun cider-inspect-defun-at-point ()
    156   "Inspect the result of the \"top-level\" expression at point."
    157   (interactive)
    158   (cider-inspect-expr (cider-defun-at-point) (cider-current-ns)))
    159 
    160 ;;;###autoload
    161 (defun cider-inspect-last-result ()
    162   "Inspect the most recent eval result."
    163   (interactive)
    164   (cider-inspect-expr "*1" (cider-current-ns)))
    165 
    166 ;;;###autoload
    167 (defun cider-inspect (&optional arg)
    168   "Inspect the result of the preceding sexp.
    169 
    170 With a prefix argument ARG it inspects the result of the \"top-level\" form.
    171 With a second prefix argument it prompts for an expression to eval and inspect."
    172   (interactive "p")
    173   (pcase arg
    174     (1 (cider-inspect-last-sexp))
    175     (4 (cider-inspect-defun-at-point))
    176     (16 (call-interactively #'cider-inspect-expr))))
    177 
    178 (defvar cider-inspector-location-stack nil
    179   "A stack used to save point locations in inspector buffers.
    180 These locations are used to emulate `save-excursion' between
    181 `cider-inspector-push' and `cider-inspector-pop' operations.")
    182 
    183 (defvar cider-inspector-page-location-stack nil
    184   "A stack used to save point locations in inspector buffers.
    185 These locations are used to emulate `save-excursion' between
    186 `cider-inspector-next-page' and `cider-inspector-prev-page' operations.")
    187 
    188 (defvar cider-inspector-last-command nil
    189   "Contains the value of the most recently used `cider-inspector-*' command.
    190 This is used as an alternative to the built-in `last-command'.  Whenever we
    191 invoke any command through \\[execute-extended-command] and its variants,
    192 the value of `last-command' is not set to the command it invokes.")
    193 
    194 (defvar cider-inspector--current-repl nil
    195   "Contains the reference to the REPL where inspector was last invoked from.
    196 This is needed for internal inspector buffer operations (push,
    197 pop) to execute against the correct REPL session.")
    198 
    199 ;; Operations
    200 ;;;###autoload
    201 (defun cider-inspect-expr (expr ns)
    202   "Evaluate EXPR in NS and inspect its value.
    203 Interactively, EXPR is read from the minibuffer, and NS the
    204 current buffer's namespace."
    205   (interactive (list (cider-read-from-minibuffer "Inspect expression: " (cider-sexp-at-point))
    206                      (cider-current-ns)))
    207   (setq cider-inspector--current-repl (cider-current-repl))
    208   (when-let* ((value (cider-sync-request:inspect-expr
    209                       expr ns
    210                       cider-inspector-page-size
    211                       cider-inspector-max-atom-length
    212                       cider-inspector-max-coll-size)))
    213     (cider-inspector--render-value value)))
    214 
    215 (defun cider-inspector-pop ()
    216   "Pop the last value off the inspector stack and render it.
    217 See `cider-sync-request:inspect-pop' and `cider-inspector--render-value'."
    218   (interactive)
    219   (setq cider-inspector-last-command 'cider-inspector-pop)
    220   (when-let* ((value (cider-sync-request:inspect-pop)))
    221     (cider-inspector--render-value value)))
    222 
    223 (defun cider-inspector-push (idx)
    224   "Inspect the value at IDX in the inspector stack and render it.
    225 See `cider-sync-request:inspect-push' and `cider-inspector--render-value'"
    226   (push (point) cider-inspector-location-stack)
    227   (when-let* ((value (cider-sync-request:inspect-push idx)))
    228     (cider-inspector--render-value value)
    229     (cider-inspector-next-inspectable-object 1)))
    230 
    231 (defun cider-inspector-refresh ()
    232   "Re-render the currently inspected value.
    233 See `cider-sync-request:inspect-refresh' and `cider-inspector--render-value'"
    234   (interactive)
    235   (when-let* ((value (cider-sync-request:inspect-refresh)))
    236     (cider-inspector--render-value value)))
    237 
    238 (defun cider-inspector-next-page ()
    239   "Jump to the next page when inspecting a paginated sequence/map.
    240 
    241 Does nothing if already on the last page."
    242   (interactive)
    243   (push (point) cider-inspector-page-location-stack)
    244   (when-let* ((value (cider-sync-request:inspect-next-page)))
    245     (cider-inspector--render-value value)))
    246 
    247 (defun cider-inspector-prev-page ()
    248   "Jump to the previous page when expecting a paginated sequence/map.
    249 
    250 Does nothing if already on the first page."
    251   (interactive)
    252   (setq cider-inspector-last-command 'cider-inspector-prev-page)
    253   (when-let* ((value (cider-sync-request:inspect-prev-page)))
    254     (cider-inspector--render-value value)))
    255 
    256 (defun cider-inspector-set-page-size (page-size)
    257   "Set the page size in pagination mode to the specified PAGE-SIZE.
    258 
    259 Current page will be reset to zero."
    260   (interactive (list (read-number "Page size: " cider-inspector-page-size)))
    261   (when-let ((value (cider-sync-request:inspect-set-page-size page-size)))
    262     (cider-inspector--render-value value)))
    263 
    264 (defun cider-inspector-set-max-atom-length (max-length)
    265   "Set the max length of nested atoms to MAX-LENGTH."
    266   (interactive (list (read-number "Max atom length: " cider-inspector-max-atom-length)))
    267   (when-let ((value (cider-sync-request:inspect-set-max-atom-length max-length)))
    268     (cider-inspector--render-value value)))
    269 
    270 (defun cider-inspector-set-max-coll-size (max-size)
    271   "Set the number of nested collection members to display before truncating.
    272 MAX-SIZE is the new value."
    273   (interactive (list (read-number "Max collection size: " cider-inspector-max-coll-size)))
    274   (when-let ((value (cider-sync-request:inspect-set-max-coll-size max-size)))
    275     (cider-inspector--render-value value)))
    276 
    277 (defun cider-inspector-def-current-val (var-name ns)
    278   "Defines a var with VAR-NAME in current namespace.
    279 
    280 Doesn't modify current page.  When called interactively NS defaults to
    281 current-namespace."
    282   (interactive (let ((ns (cider-current-ns)))
    283                  (list (read-from-minibuffer (concat "Var name: " ns "/"))
    284                        ns)))
    285   (setq cider-inspector--current-repl (cider-current-repl))
    286   (when-let* ((value (cider-sync-request:inspect-def-current-val ns var-name)))
    287     (cider-inspector--render-value value)
    288     (message "%s#'%s/%s = %s" cider-eval-result-prefix ns var-name value)))
    289 
    290 ;; nREPL interactions
    291 (defun cider-sync-request:inspect-pop ()
    292   "Move one level up in the inspector stack."
    293   (thread-first '("op" "inspect-pop")
    294                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    295                 (nrepl-dict-get "value")))
    296 
    297 (defun cider-sync-request:inspect-push (idx)
    298   "Inspect the inside value specified by IDX."
    299   (thread-first `("op" "inspect-push"
    300                   "idx" ,idx)
    301                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    302                 (nrepl-dict-get "value")))
    303 
    304 (defun cider-sync-request:inspect-refresh ()
    305   "Re-render the currently inspected value."
    306   (thread-first '("op" "inspect-refresh")
    307                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    308                 (nrepl-dict-get "value")))
    309 
    310 (defun cider-sync-request:inspect-next-page ()
    311   "Jump to the next page in paginated collection view."
    312   (thread-first '("op" "inspect-next-page")
    313                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    314                 (nrepl-dict-get "value")))
    315 
    316 (defun cider-sync-request:inspect-prev-page ()
    317   "Jump to the previous page in paginated collection view."
    318   (thread-first '("op" "inspect-prev-page")
    319                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    320                 (nrepl-dict-get "value")))
    321 
    322 (defun cider-sync-request:inspect-set-page-size (page-size)
    323   "Set the page size in paginated view to PAGE-SIZE."
    324   (thread-first `("op" "inspect-set-page-size"
    325                   "page-size" ,page-size)
    326                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    327                 (nrepl-dict-get "value")))
    328 
    329 (defun cider-sync-request:inspect-set-max-atom-length (max-length)
    330   "Set the max length of nested atoms to MAX-LENGTH."
    331   (thread-first `("op" "inspect-set-max-atom-length"
    332                   "max-atom-length" ,max-length)
    333                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    334                 (nrepl-dict-get "value")))
    335 
    336 (defun cider-sync-request:inspect-set-max-coll-size (max-size)
    337   "Set the number of nested collection members to display before truncating.
    338 MAX-SIZE is the new value."
    339   (thread-first `("op" "inspect-set-max-coll-size"
    340                   "max-coll-size" ,max-size)
    341                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    342                 (nrepl-dict-get "value")))
    343 
    344 (defun cider-sync-request:inspect-def-current-val (ns var-name)
    345   "Defines a var with VAR-NAME in NS with the current inspector value."
    346   (thread-first `("op" "inspect-def-current-value"
    347                   "ns" ,ns
    348                   "var-name" ,var-name)
    349                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    350                 (nrepl-dict-get "value")))
    351 
    352 (defun cider-sync-request:inspect-expr (expr ns page-size max-atom-length max-coll-size)
    353   "Evaluate EXPR in context of NS and inspect its result.
    354 Set the page size in paginated view to PAGE-SIZE, maximum length of atomic
    355 collection members to MAX-ATOM-LENGTH, and maximum size of nested collections to
    356 MAX-COLL-SIZE if non nil."
    357   (thread-first (append (nrepl--eval-request expr ns)
    358                         `("inspect" "true"
    359                           ,@(when page-size
    360                               `("page-size" ,page-size))
    361                           ,@(when max-atom-length
    362                               `("max-atom-length" ,max-atom-length))
    363                           ,@(when max-coll-size
    364                               `("max-coll-size" ,max-coll-size))))
    365                 (cider-nrepl-send-sync-request cider-inspector--current-repl)
    366                 (nrepl-dict-get "value")))
    367 
    368 ;; Render Inspector from Structured Values
    369 (defun cider-inspector--render-value (value)
    370   "Render VALUE."
    371   (cider-make-popup-buffer cider-inspector-buffer 'cider-inspector-mode 'ancillary)
    372   (cider-inspector-render cider-inspector-buffer value)
    373   (cider-popup-buffer-display cider-inspector-buffer cider-inspector-auto-select-buffer)
    374   (when cider-inspector-fill-frame (delete-other-windows))
    375   (ignore-errors (cider-inspector-next-inspectable-object 1))
    376   (with-current-buffer cider-inspector-buffer
    377     (when (eq cider-inspector-last-command 'cider-inspector-pop)
    378       (setq cider-inspector-last-command nil)
    379       ;; Prevents error message being displayed when we try to pop
    380       ;; from the top-level of a data structure
    381       (when cider-inspector-location-stack
    382         (goto-char (pop cider-inspector-location-stack))))
    383 
    384     (when (eq cider-inspector-last-command 'cider-inspector-prev-page)
    385       (setq cider-inspector-last-command nil)
    386       ;; Prevents error message being displayed when we try to
    387       ;; go to a prev-page from the first page
    388       (when cider-inspector-page-location-stack
    389         (goto-char (pop cider-inspector-page-location-stack))))))
    390 
    391 (defun cider-inspector-render (buffer str)
    392   "Render STR in BUFFER."
    393   (with-current-buffer buffer
    394     (cider-inspector-mode)
    395     (let ((inhibit-read-only t))
    396       (condition-case nil
    397           (cider-inspector-render* (car (read-from-string str)))
    398         (error (insert "\nInspector error for: " str))))
    399     (goto-char (point-min))))
    400 
    401 (defun cider-inspector-render* (elements)
    402   "Render ELEMENTS."
    403   (dolist (el elements)
    404     (cider-inspector-render-el* el)))
    405 
    406 (defun cider-inspector-render-el* (el)
    407   "Render EL."
    408   (cond ((symbolp el) (insert (symbol-name el)))
    409         ((stringp el) (insert (propertize el 'font-lock-face 'font-lock-keyword-face)))
    410         ((and (consp el) (eq (car el) :newline))
    411          (insert "\n"))
    412         ((and (consp el) (eq (car el) :value))
    413          (cider-inspector-render-value (cadr el) (cl-caddr el)))
    414         (t (message "Unrecognized inspector object: %s" el))))
    415 
    416 (defun cider-inspector-render-value (value idx)
    417   "Render VALUE at IDX."
    418   (cider-propertize-region
    419       (list 'cider-value-idx idx
    420             'mouse-face 'highlight)
    421     (cider-inspector-render-el* (cider-font-lock-as-clojure value))))
    422 
    423 
    424 ;; ===================================================
    425 ;; Inspector Navigation (lifted from SLIME inspector)
    426 ;; ===================================================
    427 
    428 (defun cider-find-inspectable-object (direction limit)
    429   "Find the next/previous inspectable object.
    430 DIRECTION can be either 'next or 'prev.
    431 LIMIT is the maximum or minimum position in the current buffer.
    432 
    433 Return a list of two values: If an object could be found, the
    434 starting position of the found object and T is returned;
    435 otherwise LIMIT and NIL is returned."
    436   (let ((finder (cl-ecase direction
    437                   (next 'next-single-property-change)
    438                   (prev 'previous-single-property-change))))
    439     (let ((prop nil) (curpos (point)))
    440       (while (and (not prop) (not (= curpos limit)))
    441         (let ((newpos (funcall finder curpos 'cider-value-idx nil limit)))
    442           (setq prop (get-text-property newpos 'cider-value-idx))
    443           (setq curpos newpos)))
    444       (list curpos (and prop t)))))
    445 
    446 (defun cider-inspector-next-inspectable-object (arg)
    447   "Move point to the next inspectable object.
    448 With optional ARG, move across that many objects.
    449 If ARG is negative, move backwards."
    450   (interactive "p")
    451   (let ((maxpos (point-max)) (minpos (point-min))
    452         (previously-wrapped-p nil))
    453     ;; Forward.
    454     (while (> arg 0)
    455       (seq-let (pos foundp) (cider-find-inspectable-object 'next maxpos)
    456         (if foundp
    457             (progn (goto-char pos)
    458                    (unless (and cider-inspector-skip-uninteresting
    459                                 (looking-at-p cider-inspector-uninteresting-regexp))
    460                      (setq arg (1- arg))
    461                      (setq previously-wrapped-p nil)))
    462           (if (not previously-wrapped-p) ; cycle detection
    463               (progn (goto-char minpos) (setq previously-wrapped-p t))
    464             (error "No inspectable objects")))))
    465     ;; Backward.
    466     (while (< arg 0)
    467       (seq-let (pos foundp) (cider-find-inspectable-object 'prev minpos)
    468         ;; CIDER-OPEN-INSPECTOR inserts the title of an inspector page
    469         ;; as a presentation at the beginning of the buffer; skip
    470         ;; that.  (Notice how this problem can not arise in ``Forward.'')
    471         (if (and foundp (/= pos minpos))
    472             (progn (goto-char pos)
    473                    (unless (and cider-inspector-skip-uninteresting
    474                                 (looking-at-p cider-inspector-uninteresting-regexp))
    475                      (setq arg (1+ arg))
    476                      (setq previously-wrapped-p nil)))
    477           (if (not previously-wrapped-p) ; cycle detection
    478               (progn (goto-char maxpos) (setq previously-wrapped-p t))
    479             (error "No inspectable objects")))))))
    480 
    481 (defun cider-inspector-previous-inspectable-object (arg)
    482   "Move point to the previous inspectable object.
    483 With optional ARG, move across that many objects.
    484 If ARG is negative, move forwards."
    485   (interactive "p")
    486   (cider-inspector-next-inspectable-object (- arg)))
    487 
    488 (defun cider-inspector-property-at-point ()
    489   "Return property at point."
    490   (let* ((properties '(cider-value-idx cider-range-button
    491                                        cider-action-number))
    492          (find-property
    493           (lambda (point)
    494             (cl-loop for property in properties
    495                      for value = (get-text-property point property)
    496                      when value
    497                      return (list property value)))))
    498     (or (funcall find-property (point))
    499         (funcall find-property (max (point-min) (1- (point)))))))
    500 
    501 (defun cider-inspector-operate-on-point ()
    502   "Invoke the command for the text at point.
    503 1. If point is on a value then recursively call the inspector on
    504 that value.
    505 2. If point is on an action then call that action.
    506 3. If point is on a range-button fetch and insert the range."
    507   (interactive)
    508   (seq-let (property value) (cider-inspector-property-at-point)
    509     (cl-case property
    510       (cider-value-idx
    511        (cider-inspector-push value))
    512       ;; TODO: range and action handlers
    513       (t (error "No object at point")))))
    514 
    515 (defun cider-inspector-operate-on-click (event)
    516   "Move to EVENT's position and operate the part."
    517   (interactive "@e")
    518   (let ((point (posn-point (event-end event))))
    519     (cond ((and point
    520                 (or (get-text-property point 'cider-value-idx)))
    521            (goto-char point)
    522            (cider-inspector-operate-on-point))
    523           (t
    524            (error "No clickable part here")))))
    525 
    526 (provide 'cider-inspector)
    527 
    528 ;;; cider-inspector.el ends here