dotemacs

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

cider-resolve.el (5971B)


      1 ;;; cider-resolve.el --- Resolve clojure symbols according to current nREPL connection  -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright © 2015-2023 Bozhidar Batsov, Artur Malabarba and CIDER contributors
      4 
      5 ;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
      6 
      7 ;; This program is free software; you can redistribute it and/or modify
      8 ;; it under the terms of the GNU General Public License as published by
      9 ;; the Free Software Foundation, either version 3 of the License, or
     10 ;; (at your option) any later version.
     11 
     12 ;; This program is distributed in the hope that it will be useful,
     13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 ;; GNU General Public License for more details.
     16 
     17 ;; You should have received a copy of the GNU General Public License
     18 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
     19 
     20 ;;; Commentary:
     21 
     22 ;; The ns cache is a dict of namespaces stored in the connection buffer.  This
     23 ;; file offers functions to easily get information about variables from this
     24 ;; cache, given the variable's name and the file's namespace.  This
     25 ;; functionality is similar to that offered by the `cider-var-info' function
     26 ;; (and others).  The difference is that all functions in this file operate
     27 ;; without contacting the server (they still rely on an active connection
     28 ;; buffer, but no messages are actually exchanged).
     29 
     30 ;; For this reason, the functions here are well suited for very
     31 ;; performance-sentitive operations, such as font-locking or
     32 ;; indentation.  Meanwhile, operations like code-jumping are better off
     33 ;; communicating with the middleware, just in the off chance that the cache is
     34 ;; outdated.
     35 
     36 ;; Below is a typical entry on this cache dict.  Note that clojure.core symbols
     37 ;; are excluded from the refers to save space.
     38 
     39 ;; "cider.nrepl.middleware.track-state"
     40 ;; (dict "aliases"
     41 ;;       (dict "cljs" "cider.nrepl.middleware.util.cljs"
     42 ;;             "misc" "cider.nrepl.middleware.util.misc"
     43 ;;             "set" "clojure.set")
     44 ;;       "interns" (dict a
     45 ;;                       "assoc-state"    (dict "arglists"
     46 ;;                                              (("response"
     47 ;;                                                (dict "as" "msg" "keys"
     48 ;;                                                      ("session")))))
     49 ;;                       "filter-core"    (dict "arglists"
     50 ;;                                              (("refers")))
     51 ;;                       "make-transport" (dict "arglists"
     52 ;;                                              (((dict "as" "msg" "keys"
     53 ;;                                                      ("transport")))))
     54 ;;                       "ns-as-map"      (dict "arglists"
     55 ;;                                              (("ns")))
     56 ;;                       "ns-cache"       (dict)
     57 ;;                       "relevant-meta"  (dict "arglists"
     58 ;;                                              (("var")))
     59 ;;                       "update-vals"    (dict "arglists"
     60 ;;                                              (("m" "f")))
     61 ;;                       "wrap-tracker"   (dict "arglists"
     62 ;;                                              (("handler"))))
     63 ;;       "refers" (dict "set-descriptor!" "#'nrepl.middleware/set-descriptor!"))
     64 
     65 ;;; Code:
     66 
     67 (require 'cider-client)
     68 (require 'nrepl-dict)
     69 (require 'cider-util)
     70 
     71 (defvar cider-repl-ns-cache)
     72 
     73 (defun cider-resolve--get-in (&rest keys)
     74   "Return (nrepl-dict-get-in cider-repl-ns-cache KEYS)."
     75   (when-let* ((conn (cider-current-repl)))
     76     (with-current-buffer conn
     77       (nrepl-dict-get-in cider-repl-ns-cache keys))))
     78 
     79 (defun cider-resolve-alias (ns alias)
     80   "Return the namespace that ALIAS refers to in namespace NS.
     81 If it doesn't point anywhere, returns ALIAS."
     82   (or (cider-resolve--get-in ns "aliases" alias)
     83       alias))
     84 
     85 (defconst cider-resolve--prefix-regexp "\\`\\(?:#'\\)?\\([^/]+\\)/")
     86 
     87 (defun cider-resolve-var (ns var)
     88   "Return a dict of the metadata of a clojure var VAR in namespace NS.
     89 VAR is a string.
     90 Return nil only if VAR cannot be resolved."
     91   (let* ((var-ns (when (string-match cider-resolve--prefix-regexp var)
     92                    (cider-resolve-alias ns (match-string 1 var))))
     93          (name (replace-regexp-in-string cider-resolve--prefix-regexp "" var)))
     94     (or
     95      (cider-resolve--get-in (or var-ns ns) "interns" name)
     96      (unless var-ns
     97        ;; If the var had no prefix, it might be referred.
     98        (if-let* ((referral (cider-resolve--get-in ns "refers" name)))
     99            (cider-resolve-var ns referral)
    100          ;; Or it might be from core.
    101          (unless (equal ns "clojure.core")
    102            (cider-resolve-var "clojure.core" name)))))))
    103 
    104 (defun cider-resolve-core-ns ()
    105   "Return a dict of the core namespace for current connection.
    106 This will be clojure.core or cljs.core depending on the return value of the
    107 function `cider-repl-type'."
    108   (when-let* ((repl (cider-current-repl)))
    109     (with-current-buffer repl
    110       (cider-resolve--get-in (if (eq cider-repl-type 'cljs)
    111                                  "cljs.core"
    112                                "clojure.core")))))
    113 
    114 (defun cider-resolve-ns-symbols (ns)
    115   "Return a plist of all valid symbols in NS.
    116 Each entry's value is the metadata of the var that the symbol refers to.
    117 NS can be the namespace name, or a dict of the namespace itself."
    118   (when-let* ((dict (if (stringp ns)
    119                         (cider-resolve--get-in ns)
    120                       ns)))
    121     (nrepl-dbind-response dict (interns _refers aliases)
    122       (append (cdr interns)
    123               (nrepl-dict-flat-map (lambda (alias namespace)
    124                                      (nrepl-dict-flat-map (lambda (sym meta)
    125                                                             (list (concat alias "/" sym) meta))
    126                                                           (cider-resolve--get-in namespace "interns")))
    127                                    aliases)))))
    128 
    129 (provide 'cider-resolve)
    130 ;;; cider-resolve.el ends here