branch: elpa/cider
commit db1d6b98df0122646a873668e95d2e06b7ac80db
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>
Fall back to runtime xref references outside a project
`cider-xref-references-mode' defaults to `source', which scans the
project's files. `cider-xref--project-source-files' returns nothing when
`project-current' is nil (a standalone file, a non-VC project), so
`xref-find-references' reported "No references" even when a connected
REPL could answer via `cider/fn-refs'.
When the source search can't run for lack of a project, fall back to the
runtime op if a REPL is connected, so the query still returns something
useful instead of a misleading empty result.
---
lisp/cider-xref-backend.el | 19 ++++++++++++++++---
test/cider-xref-backend-tests.el | 32 ++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/lisp/cider-xref-backend.el b/lisp/cider-xref-backend.el
index 7360dddc9c..08412f3a09 100644
--- a/lisp/cider-xref-backend.el
+++ b/lisp/cider-xref-backend.el
@@ -123,7 +123,11 @@ The value selects which of the two run:
In `both' mode the source matches lead, and runtime hits for files the source
search already scanned are dropped (they would only duplicate the precise
occurrences at a coarser granularity). What survives is mainly references the
-compiler generated from macros, which leave no textual trace for the scan."
+compiler generated from macros, which leave no textual trace for the scan.
+
+When `source' is selected but the buffer isn't inside a project (so there are
+no files to scan), CIDER falls back to the runtime search if a REPL is
+connected, rather than reporting no references."
:type '(choice (const :tag "Source matches only" source)
(const :tag "Runtime references only" runtime)
(const :tag "Runtime and source matches combined" both))
@@ -198,9 +202,18 @@ The runtime side (the `fn-refs' op) only sees loaded
namespaces; the source
side covers code on disk that hasn't been evaluated yet. In `both' mode the
two are combined, with runtime hits the source search already covers dropped."
(let* ((ns (cider-current-ns))
- (source (when (memq cider-xref-references-mode '(source both))
+ ;; With no project.el project there are no files to scan, so a
`source'
+ ;; search can't run - fall back to the runtime op (when a REPL is
+ ;; connected) so it still answers, instead of falsely reporting "No
+ ;; references".
+ (mode (if (and (eq cider-xref-references-mode 'source)
+ (not (project-current))
+ (cider-connected-p))
+ 'runtime
+ cider-xref-references-mode))
+ (source (when (memq mode '(source both))
(cider-xref--var-source-references var)))
- (runtime (when (memq cider-xref-references-mode '(runtime both))
+ (runtime (when (memq mode '(runtime both))
(cider--fn-refs-xrefs ns var))))
(when (and source runtime)
(setq runtime (cider--xref-reject-runtime-overlap runtime source)))
diff --git a/test/cider-xref-backend-tests.el b/test/cider-xref-backend-tests.el
index 81e63e37de..fe694e278d 100644
--- a/test/cider-xref-backend-tests.el
+++ b/test/cider-xref-backend-tests.el
@@ -50,6 +50,38 @@
(kept (cider--xref-reject-runtime-overlap runtime source)))
(expect (length kept) :to-equal 1)))))
+(describe "xref-backend-references reference-mode selection"
+ (before-each
+ (spy-on 'cider-current-ns :and-return-value "user")
+ (spy-on 'cider-xref--var-source-references :and-return-value nil)
+ (spy-on 'cider--fn-refs-xrefs :and-return-value nil))
+
+ (describe "in `source' mode with no project"
+ (it "falls back to the runtime search when a REPL is connected"
+ (let ((cider-xref-references-mode 'source))
+ (spy-on 'project-current :and-return-value nil)
+ (spy-on 'cider-connected-p :and-return-value t)
+ (xref-backend-references 'cider "foo")
+ (expect 'cider--fn-refs-xrefs :to-have-been-called)
+ (expect 'cider-xref--var-source-references :not :to-have-been-called)))
+
+ (it "does not fall back when no REPL is connected"
+ (let ((cider-xref-references-mode 'source))
+ (spy-on 'project-current :and-return-value nil)
+ (spy-on 'cider-connected-p :and-return-value nil)
+ (xref-backend-references 'cider "foo")
+ (expect 'cider--fn-refs-xrefs :not :to-have-been-called)
+ (expect 'cider-xref--var-source-references :to-have-been-called))))
+
+ (describe "in `source' mode inside a project"
+ (it "uses the source search, not the runtime fallback"
+ (let ((cider-xref-references-mode 'source))
+ (spy-on 'project-current :and-return-value '(vc Git "/tmp/proj/"))
+ (spy-on 'cider-connected-p :and-return-value t)
+ (xref-backend-references 'cider "foo")
+ (expect 'cider-xref--var-source-references :to-have-been-called)
+ (expect 'cider--fn-refs-xrefs :not :to-have-been-called)))))
+
(provide 'cider-xref-backend-tests)
;;; cider-xref-backend-tests.el ends here