From ed7619221e20f7ffc606e6ab7a363c804a0db911 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sun, 12 Jul 2026 17:21:00 +0300 Subject: [PATCH] Use namespaced middleware ops; tidy two request params Three improvements found while auditing the middleware request/response shapes: - Use refactor-nrepl's namespaced op names (refactor/find-symbol, etc.) instead of the bare ones. refactor-nrepl registers every op under both forms, treats the namespaced one as canonical, and plans to drop the bare names; namespacing also avoids op-name collisions with other middleware. Prefixing is centralized in cljr--create-msg and cljr--op-supported-p (plus the one inline extract-definition request). Requires refactor-nrepl 3.13.0+; the injected version is now 3.14.0. - Send an explicit "false" for ignore-errors when cljr-ignore-analyzer-errors is nil, instead of a nil value that nREPL drops (leaving the middleware on its lenient default). The strict behavior the option documents now actually takes effect. - Drop the obsolete language-context param from the suggest-libspecs request; refactor-nrepl has read buffer-language-context / input-language-context since 3.7.0. Validated live against refactor-nrepl 3.14.0: op-support, version, rename, clean-ns and suggest-libspecs all work under the namespaced ops. --- CHANGELOG.md | 4 ++++ README.md | 2 +- clj-refactor.el | 33 ++++++++++++++++++++++++--------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ec4cfa..bd02bee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +- **(Breaking)** Use refactor-nrepl's namespaced op names (`refactor/find-symbol`, `refactor/clean-ns`, …) instead of the bare ones. refactor-nrepl treats the namespaced forms as canonical and plans to drop the bare names, and namespacing avoids op-name collisions with other middleware. This requires refactor-nrepl 3.13.0+ (the injected version is now 3.14.0). +- `cljr-rename-symbol`, `cljr-find-usages`, `cljr-inline-symbol` and `cljr-change-function-signature` now send an explicit `ignore-errors` value that matches `cljr-ignore-analyzer-errors`, instead of a nil value that was dropped on the wire. With the default (nil) this means the strict behavior the option documents actually takes effect - a project with an unanalyzable namespace now surfaces a warning rather than silently skipping it. +- `cljr-slash` no longer sends the obsolete `language-context` parameter to the `suggest-libspecs` op (superseded by `buffer-language-context`/`input-language-context` in refactor-nrepl 3.7.0). + - The asynchronous refactorings (`cljr-rename-symbol`, `cljr-change-function-signature`, `cljr-rename-file-or-dir`) now show a mode-line spinner while the middleware is working, so it's clear the operation is still running. Uses CIDER's spinner, so it honors `cider-show-spinner` and friends. - `cljr-rename-symbol` and `cljr-change-function-signature` now find their occurrences asynchronously. Locating every occurrence analyses the whole project, which on a cold cache or a large project could freeze Emacs for a long time; now the command returns immediately and the rename (or the change-signature edit buffer) happens once the search finishes, so Emacs stays responsive meanwhile. As a side effect they now also honor `cljr-middleware-ignored-paths`. diff --git a/README.md b/README.md index 93a4cae..06a4d6d 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ clj-refactor | refactor-nrepl | CIDER | Clojure | Java | 2.4.0 | 2.4.0 | 0.17, 0.18 | 1.7+ | 8+ | 2.5.0 | 2.5.0 | 0.24 | 1.8+ | 8+ | 3.0.0+ | 3.0.0+ | 1.0 | 1.9+ | 11+ | -4.0.0+ | 3.x | 1.11+ | 1.10+ | 8+ | +4.0.0+ | 3.13.0+ | 1.11+ | 1.10+ | 8+ | clj-refactor 4.0.0+ requires Emacs 28.1 or newer. diff --git a/clj-refactor.el b/clj-refactor.el index 3b38690..2ffd8a1 100644 --- a/clj-refactor.el +++ b/clj-refactor.el @@ -997,14 +997,28 @@ if the point is currently placed at the opening parentheses of an anonymous func v) v)))) +(defconst cljr--middleware-op-prefix "refactor/" + "Namespace prefix for refactor-nrepl's op names. +refactor-nrepl registers every op under both its bare name (e.g. +`clean-ns') and this namespaced form (e.g. `refactor/clean-ns'), and +treats the namespaced form as canonical - the bare names are slated for +removal in a future refactor-nrepl major release. We use the namespaced +form (available since refactor-nrepl 3.13.0) so op names can't collide +with those of other middleware.") + +(defun cljr--middleware-op (op) + "Return refactor-nrepl op OP as its canonical namespaced name." + (concat cljr--middleware-op-prefix op)) + (defun cljr--create-msg (op &rest kvs) "Create a msg for the middleware for OP and optionally include the kv pairs KVS. -All config settings are included in the created msg." +OP is given as its bare refactor-nrepl name and is namespaced here (see +`cljr--middleware-op'). All config settings are included in the created msg." (cl-assert (cl-evenp (length kvs)) nil "Can't create msg to send to the middleware.\ Received an uneven number of kv pairs: %s " kvs) (apply #'list - "op" op + "op" (cljr--middleware-op op) "prefix-rewriting" (if cljr-favor-prefix-notation @@ -1230,13 +1244,15 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-rename-file-or-d (cljr-rename-file-or-dir (buffer-file-name) new-path)) (defun cljr--op-supported-p (op) - "Is the OP we require provided by the current middleware stack?" + "Is the refactor-nrepl OP (bare name) provided by the current middleware? +OP is namespaced (see `cljr--middleware-op') so this checks for the +canonical op, matching what `cljr--create-msg' actually sends." ;; Guard on the connection first: `cider-nrepl-op-supported-p' resolves the ;; REPL with the `ensure' flag and signals `No linked CIDER sessions' when ;; nothing is connected. We want a plain nil there, so the offline fallbacks ;; that gate on this predicate (`cljr-slash', `cljr-clean-ns', ...) can kick in. (and (cider-connected-p) - (cider-nrepl-op-supported-p op))) + (cider-nrepl-op-supported-p (cljr--middleware-op op)))) (defun cljr--assert-middleware () (unless (featurep 'cider) @@ -2229,7 +2245,6 @@ Results are cached per alias and language context (see (thread-first "cljr-suggest-libspecs" cljr--ensure-op-supported (cljr--create-msg "lib-prefix" alias-ref - "language-context" buffer-context "buffer-language-context" buffer-context "input-language-context" (or point-context buffer-context) "preferred-aliases" (let ((print-length nil) ;; prevent large lists from being serialized with `...`, which would cause issues @@ -3030,7 +3045,7 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-promote-function "name" symbol "ignore-paths" cljr-middleware-ignored-paths "ignore-errors" - (when cljr-ignore-analyzer-errors "true")))) + (if cljr-ignore-analyzer-errors "true" "false")))) (with-current-buffer (cider-current-repl) (setq cljr--occurrence-count 0) (setq cljr--num-syms -1) @@ -3874,7 +3889,7 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-inline-symbol" (ns (or (nrepl-dict-get var-info "ns") (cider-current-ns))) (symbol-name (or (nrepl-dict-get var-info "name") symbol)) (extract-definition-request (list - "op" "extract-definition" + "op" (cljr--middleware-op "extract-definition") "ns" ns "dir" dir "file" filename @@ -3882,7 +3897,7 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-inline-symbol" "column" column "name" symbol-name "ignore-errors" - (when cljr-ignore-analyzer-errors "true"))) + (if cljr-ignore-analyzer-errors "true" "false"))) (response (parseedn-read-str (cljr--call-middleware-sync extract-definition-request "definition"))) (definition (gethash :definition response)) @@ -3914,7 +3929,7 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-inline-symbol" ;; We used to derive the version out of `(cljr--version)`, ;; but now prefer a fixed version to fully decouple things and prevent unforeseen behavior. ;; This suits better our current pace of development. -(defcustom cljr-injected-middleware-version "3.11.0" +(defcustom cljr-injected-middleware-version "3.14.0" "The refactor-nrepl version to be injected. You can customize this in order to try out new releases.