;;; cider-resolve.el --- Resolve clojure symbols according to current nREPL connection ;; Copyright © 2015-2019 Bozhidar Batsov, Artur Malabarba and CIDER contributors ;; Author: Artur Malabarba ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; The ns cache is a dict of namespaces stored in the connection buffer. This ;; file offers functions to easily get information about variables from this ;; cache, given the variable's name and the file's namespace. This ;; functionality is similar to that offered by the `cider-var-info' function ;; (and others). The difference is that all functions in this file operate ;; without contacting the server (they still rely on an active connection ;; buffer, but no messages are actually exchanged). ;; For this reason, the functions here are well suited for very ;; performance-sentitive operations, such as font-locking or ;; indentation. Meanwhile, operations like code-jumping are better off ;; communicating with the middleware, just in the off chance that the cache is ;; outdated. ;; Below is a typical entry on this cache dict. Note that clojure.core symbols ;; are excluded from the refers to save space. ;; "cider.nrepl.middleware.track-state" ;; (dict "aliases" ;; (dict "cljs" "cider.nrepl.middleware.util.cljs" ;; "misc" "cider.nrepl.middleware.util.misc" ;; "set" "clojure.set") ;; "interns" (dict a ;; "assoc-state" (dict "arglists" ;; (("response" ;; (dict "as" "msg" "keys" ;; ("session"))))) ;; "filter-core" (dict "arglists" ;; (("refers"))) ;; "make-transport" (dict "arglists" ;; (((dict "as" "msg" "keys" ;; ("transport"))))) ;; "ns-as-map" (dict "arglists" ;; (("ns"))) ;; "ns-cache" (dict) ;; "relevant-meta" (dict "arglists" ;; (("var"))) ;; "update-vals" (dict "arglists" ;; (("m" "f"))) ;; "wrap-tracker" (dict "arglists" ;; (("handler")))) ;; "refers" (dict "set-descriptor!" "#'nrepl.middleware/set-descriptor!")) ;;; Code: (require 'cider-client) (require 'nrepl-dict) (require 'cider-util) (defvar cider-repl-ns-cache) (defun cider-resolve--get-in (&rest keys) "Return (nrepl-dict-get-in cider-repl-ns-cache KEYS)." (when-let* ((conn (cider-current-repl))) (with-current-buffer conn (nrepl-dict-get-in cider-repl-ns-cache keys)))) (defun cider-resolve-alias (ns alias) "Return the namespace that ALIAS refers to in namespace NS. If it doesn't point anywhere, returns ALIAS." (or (cider-resolve--get-in ns "aliases" alias) alias)) (defconst cider-resolve--prefix-regexp "\\`\\(?:#'\\)?\\([^/]+\\)/") (defun cider-resolve-var (ns var) "Return a dict of the metadata of a clojure var VAR in namespace NS. VAR is a string. Return nil only if VAR cannot be resolved." (let* ((var-ns (when (string-match cider-resolve--prefix-regexp var) (cider-resolve-alias ns (match-string 1 var)))) (name (replace-regexp-in-string cider-resolve--prefix-regexp "" var))) (or (cider-resolve--get-in (or var-ns ns) "interns" name) (unless var-ns ;; If the var had no prefix, it might be referred. (if-let* ((referal (cider-resolve--get-in ns "refers" name))) (cider-resolve-var ns referal) ;; Or it might be from core. (unless (equal ns "clojure.core") (cider-resolve-var "clojure.core" name))))))) (defun cider-resolve-core-ns () "Return a dict of the core namespace for current connection. This will be clojure.core or cljs.core depending on the return value of the function `cider-repl-type'." (when-let* ((repl (cider-current-repl))) (with-current-buffer repl (cider-resolve--get-in (if (eq cider-repl-type 'cljs) "cljs.core" "clojure.core"))))) (defun cider-resolve-ns-symbols (ns) "Return a plist of all valid symbols in NS. Each entry's value is the metadata of the var that the symbol refers to. NS can be the namespace name, or a dict of the namespace itself." (when-let* ((dict (if (stringp ns) (cider-resolve--get-in ns) ns))) (nrepl-dbind-response dict (interns refers aliases) (append (cdr interns) (nrepl-dict-flat-map (lambda (alias namespace) (nrepl-dict-flat-map (lambda (sym meta) (list (concat alias "/" sym) meta)) (cider-resolve--get-in namespace "interns"))) aliases))))) (provide 'cider-resolve) ;;; cider-resolve.el ends here