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