diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d772a97c..18cbb1a4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - [#3832](https://github.com/clojure-emacs/cider/issues/3832): Fix nrepl--eval-request sending duplicate info. - [#3837](https://github.com/clojure-emacs/cider/issues/3837): Fix broken stacktrace response when C-c C-p throws an exception. +- [#3834](https://github.com/clojure-emacs/cider/issues/3834): Fix cider-ns-refresh throwing an error when a clojure REPL exists, but cider-current-repl does not support the required operations. ## 1.19.0 (2025-07-10) diff --git a/cider-client.el b/cider-client.el index 97bd02a4d..7771b42d2 100644 --- a/cider-client.el +++ b/cider-client.el @@ -175,10 +175,10 @@ Skip check if repl is active if SKIP-ENSURE is non nil." nil 'ensure))))) -(defun cider-ensure-op-supported (op) - "Check for support of middleware op OP. +(defun cider-ensure-op-supported (op &optional connection) + "Check for support of middleware op OP for CONNECTION. Signal an error if it is not supported." - (unless (cider-nrepl-op-supported-p op) + (unless (cider-nrepl-op-supported-p op connection) (user-error "`%s' requires the nREPL op \"%s\" (provided by cider-nrepl)" this-command op))) (defun cider-nrepl-send-request (request callback &optional connection tooling) @@ -623,12 +623,12 @@ Optional arguments include SEARCH-NS, DOCS-P, PRIVATES-P, CASE-SENSITIVE-P." (user-error "Invalid regexp: %s" (nrepl-dict-get response "error-msg")) (nrepl-dict-get response "apropos-matches")))) -(defun cider-sync-request:classpath () - "Return a list of classpath entries." - (cider-ensure-op-supported "classpath") +(defun cider-sync-request:classpath (&optional connection) + "Return a list of classpath entries for CONNECTION." + (cider-ensure-op-supported "classpath" connection) (thread-first '("op" "classpath") - (cider-nrepl-send-sync-request) + (cider-nrepl-send-sync-request connection) (nrepl-dict-get "classpath"))) (defun cider--get-abs-path (path project) @@ -652,11 +652,11 @@ resolve those to absolute paths." (project (clojure-project-dir))) (mapcar (lambda (path) (cider--get-abs-path path project)) classpath)))) -(defun cider-classpath-entries () - "Return a list of classpath entries." +(defun cider-classpath-entries (&optional connection) + "Return a list of classpath entries for CONNECTION." (seq-map #'expand-file-name ; normalize filenames for e.g. Windows - (if (cider-nrepl-op-supported-p "classpath") - (cider-sync-request:classpath) + (if (cider-nrepl-op-supported-p "classpath" connection) + (cider-sync-request:classpath connection) (cider-fallback-eval:classpath)))) (defun cider-sync-request:completion (prefix) diff --git a/cider-connection.el b/cider-connection.el index f4181330e..da9483b92 100644 --- a/cider-connection.el +++ b/cider-connection.el @@ -1015,11 +1015,12 @@ Returns a list of the form ((session1 host1) (session2 host2) ...)." sessions :initial-value '())) -(defun cider-repls (&optional type ensure) +(defun cider-repls (&optional type ensure ops-to-support) "Return cider REPLs of TYPE from the current session. If TYPE is nil or multi, return all REPLs. If TYPE is a list of types, return only REPLs of type contained in the list. If ENSURE is non-nil, -throw an error if no linked session exists." +throw an error if no linked session exists. If OPS-TO-SUPPORT is non-nil, +filters out all the REPLs that do not support the designated ops." (let ((type (cond ((listp type) (mapcar #'cider-maybe-intern type)) @@ -1045,7 +1046,10 @@ throw an error if no linked session exists." (or (seq-filter (lambda (b) (unless (cider-cljs-pending-p b) - (cider--match-repl-type type b))) + (and (cider--match-repl-type type b) + (seq-every-p (lambda (op) + (nrepl-op-supported-p op b)) + ops-to-support)))) repls) (when ensure (cider--no-repls-user-error type))))) @@ -1053,8 +1057,9 @@ throw an error if no linked session exists." (defun cider-map-repls (which function) "Call FUNCTION once for each appropriate REPL as indicated by WHICH. The function is called with one argument, the REPL buffer. The appropriate -connections are found by inspecting the current buffer. WHICH is one of -the following keywords: +connections are found by inspecting the current buffer. WHICH is either one of +the following keywords or a list starting with one of them followed by names of +operations that the REPL is expected to support: :auto - Act on the connections whose type matches the current buffer. In `cljc' files, mapping happens over both types of REPLs. :clj (:cljs) - Map over clj (cljs)) REPLs only. @@ -1064,22 +1069,24 @@ the following keywords: Error is signaled if no REPL buffers of specified type exist in current session." (declare (indent 1)) - (let ((cur-type (cider-repl-type-for-buffer))) - (cl-case which + (let ((cur-type (cider-repl-type-for-buffer)) + (which-key (or (car-safe which) which)) + (ops-to-support (cdr-safe which))) + (cl-case which-key (:clj-strict (when (eq cur-type 'cljs) (user-error "Clojure-only operation requested in a ClojureScript buffer"))) (:cljs-strict (when (eq cur-type 'clj) (user-error "ClojureScript-only operation requested in a Clojure buffer")))) - (let* ((type (cl-case which + (let* ((type (cl-case which-key ((:clj :clj-strict) 'clj) ((:cljs :cljs-strict) 'cljs) (:auto (if (eq cur-type 'multi) '(clj cljs) cur-type)))) - (ensure (cl-case which + (ensure (cl-case which-key (:auto nil) (t 'ensure))) - (repls (cider-repls type ensure))) + (repls (cider-repls type ensure ops-to-support))) (mapcar function repls)))) ;; REPLs double as connections in CIDER, so it's useful to be able to refer to diff --git a/cider-ns.el b/cider-ns.el index 1f56c2099..e99e6a014 100644 --- a/cider-ns.el +++ b/cider-ns.el @@ -219,13 +219,13 @@ presenting the error message as an overlay." error) (cider-ns--present-error error)))) -(defun cider-ns-refresh--save-modified-buffers () - "Ensure any relevant modified buffers are saved before refreshing. +(defun cider-ns-refresh--save-modified-buffers (&optional connection) + "Ensure any relevant modified buffers for CONNECTION are saved before refreshing. Its behavior is controlled by `cider-ns-save-files-on-refresh' and `cider-ns-save-files-on-refresh-modes'." (when cider-ns-save-files-on-refresh (let ((dirs (seq-filter #'file-directory-p - (cider-classpath-entries)))) + (cider-classpath-entries connection)))) (save-some-buffers (not (eq cider-ns-save-files-on-refresh 'prompt)) (lambda () @@ -297,14 +297,12 @@ refresh functions (defined in `cider-ns-refresh-before-fn' and `cider-ns-refresh-after-fn') from being invoked." (interactive "p") (cider-ensure-connected) - (cider-ensure-op-supported "refresh") - (cider-ensure-op-supported "cider.clj-reload/reload") - (cider-ns-refresh--save-modified-buffers) (let ((clear? (member mode '(clear 16))) (all? (member mode '(refresh-all 4))) (inhibit-refresh-fns (member mode '(inhibit-fns -1)))) - (cider-map-repls :clj + (cider-map-repls '(:clj "refresh" "cider.clj-reload/reload") (lambda (conn) + (cider-ns-refresh--save-modified-buffers conn) ;; Inside the lambda, so the buffer is not created if we error out. (let ((log-buffer (or (get-buffer cider-ns-refresh-log-buffer) (cider-make-popup-buffer cider-ns-refresh-log-buffer)))) diff --git a/cider-tracing.el b/cider-tracing.el index bccaea407..3efe0a7cf 100644 --- a/cider-tracing.el +++ b/cider-tracing.el @@ -72,10 +72,9 @@ opposite of what that option dictates." "Toggle ns tracing. Defaults to the current ns. With prefix arg QUERY, prompts for a ns." (interactive "P") - (cider-map-repls :clj-strict + (cider-map-repls '(:clj-strict "toggle-trace-ns") (lambda (conn) (with-current-buffer conn - (cider-ensure-op-supported "toggle-trace-ns") (let ((ns (if query (completing-read "Toggle trace for ns: " (cider-sync-request:ns-list)) diff --git a/test/cider-connection-tests.el b/test/cider-connection-tests.el index 60a6765e2..99a4ac6c1 100644 --- a/test/cider-connection-tests.el +++ b/test/cider-connection-tests.el @@ -365,7 +365,8 @@ (expect (cider-repls) :to-have-same-items-as (list l1 l2))))))))) (describe "killed buffers" - (it "do not show up in it" + (it "do not show up in it +" (let ((default-directory (expand-file-name "/tmp/some-dir"))) (cider-test-with-buffers (a b) @@ -398,7 +399,25 @@ (append cider-connection-capabilities '(cljs)))) (expect (cider-repls) :to-equal (list a b)) - (sesman-unregister 'CIDER session))))))) + (sesman-unregister 'CIDER session)))))) + + (describe "when ops-to-support is not nil" + :var (nrepl-ops) + (it "only returns the repls that support the given ops" + (let ((proj-dir (expand-file-name "/tmp/proj-dir"))) + (let ((default-directory proj-dir)) + (with-repl-buffer ses-name 'clj b1 + (setq nrepl-ops (nrepl-dict "refresh" 't)) + (with-repl-buffer ses-name 'clj b2 + (with-repl-buffer ses-name 'cljs b3 + (expect (cider-repls nil nil '("refresh")) :to-equal (list b1)))))))) + (it "raises a user error when ensure is not nil and no repl that supports the ops exist" + (let ((proj-dir (expand-file-name "/tmp/proj-dir"))) + (let ((default-directory proj-dir)) + (with-repl-buffer ses-name 'clj b1 + (with-repl-buffer ses-name 'cljs b2 + (expect (cider-repls nil 't '("refresh")) :to-throw 'user-error)))))))) + (describe "cider--connection-info" (before-each