|
;;; cider-resolve.el --- Resolve clojure symbols according to current nREPL connection
|
|
|
|
;; Copyright © 2015-2019 Bozhidar Batsov, Artur Malabarba and CIDER contributors
|
|
|
|
;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
|
|
|
|
;; 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 <http://www.gnu.org/licenses/>.
|
|
|
|
;;; 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* ((referral (cider-resolve--get-in ns "refers" name)))
|
|
(cider-resolve-var ns referral)
|
|
;; 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
|