diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml new file mode 100644 index 0000000..37a97df --- /dev/null +++ b/.markdownlint-cli2.yaml @@ -0,0 +1,14 @@ +config: + default: true + + line-length: + line_length: 100 + code_blocks: false + tables: false + + no-duplicate-heading: + allow_different_nesting: true + + no-inline-html: false + + first-line-heading: false diff --git a/CHANGELOG.md b/CHANGELOG.md index bd02bee..e70467e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ # Changelog + + + ## 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). +- Use refactor-nrepl's namespaced op names (`refactor/find-symbol`, `refactor/clean-ns`, …) when the middleware advertises them (refactor-nrepl 3.13.0+, the injected version is now 3.14.0), falling back to the bare names on older versions. refactor-nrepl treats the namespaced forms as canonical and plans to drop the bare names, and namespacing avoids op-name collisions with other middleware. +- Don't error out of `cider-connected-hook` when the refactor-nrepl middleware is missing: the connect-time version probe now degrades to the existing "out of sync" warning instead of aborting the startup checks with a cryptic error (visible with CIDER 2.0, whose senders reject unsupported ops client-side). - `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). @@ -64,39 +69,39 @@ ## 3.11.2 - [Upgrade refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.9.1/CHANGELOG.md#391). - - Fixes https://github.com/clojure-emacs/clj-refactor.el/issues/556 + - Fixes ## 3.11.1 -* [#555](https://github.com/clojure-emacs/clj-refactor.el/pull/555): expand default `cljr-magic-require-namespaces` aliases. -* [#555](https://github.com/clojure-emacs/clj-refactor.el/pull/555): Handle an edge case for `cljr-slash`. +- [#555](https://github.com/clojure-emacs/clj-refactor.el/pull/555): expand default `cljr-magic-require-namespaces` aliases. +- [#555](https://github.com/clojure-emacs/clj-refactor.el/pull/555): Handle an edge case for `cljr-slash`. ## 3.11.0 -* [#554](https://github.com/clojure-emacs/clj-refactor.el/pull/554): Enable `cljr-slash-uses-suggest-libspec` by default. +- [#554](https://github.com/clojure-emacs/clj-refactor.el/pull/554): Enable `cljr-slash-uses-suggest-libspec` by default. ## 3.10.0 -* [#552](https://github.com/clojure-emacs/clj-refactor.el/issues/552): support TRAMP connections. +- [#552](https://github.com/clojure-emacs/clj-refactor.el/issues/552): support TRAMP connections. ## 3.9.4 -* Fix `cljr-version`. +- Fix `cljr-version`. ## 3.9.3 -* Internal: avoid the use of deprecated Elisp functions. +- Internal: avoid the use of deprecated Elisp functions. ## 3.9.2 -* [#523](https://github.com/clojure-emacs/clj-refactor.el/issues/523): Increase `js/` namespace detection accuracy for .cljc files. -* [#517](https://github.com/clojure-emacs/clj-refactor.el/issues/517): Remove `pkg-info` dependency. +- [#523](https://github.com/clojure-emacs/clj-refactor.el/issues/523): Increase `js/` namespace detection accuracy for .cljc files. +- [#517](https://github.com/clojure-emacs/clj-refactor.el/issues/517): Remove `pkg-info` dependency. ## 3.9.1 -* [#430](https://github.com/clojure-emacs/clj-refactor.el/issues/430) `cljr-add-missing-libspec`: produce more friendly prompts. -* `cljr-add-missing-libspec`: don't suggest members that are already interned into the current namespace. - * e.g. the class `Thread` or the var `+` are already interned by default in Clojure namespaces, so they are redundant to suggest or insert into the `ns` form. +- [#430](https://github.com/clojure-emacs/clj-refactor.el/issues/430) `cljr-add-missing-libspec`: produce more friendly prompts. +- `cljr-add-missing-libspec`: don't suggest members that are already interned into the current namespace. + - e.g. the class `Thread` or the var `+` are already interned by default in Clojure namespaces, so they are redundant to suggest or insert into the `ns` form. ## 3.9.0 @@ -127,33 +132,33 @@ ## 3.5.6 -* [Upgrade refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.5/CHANGELOG.md#355). +- [Upgrade refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.5/CHANGELOG.md#355). ## 3.5.5 -* [Upgrade refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.4/CHANGELOG.md#354). +- [Upgrade refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.4/CHANGELOG.md#354). ## 3.5.4 -* [Upgrade refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.3/CHANGELOG.md#353). +- [Upgrade refactor-nrepl](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.3/CHANGELOG.md#353). ## 3.5.3 -* Upgrade `cider`, `parseedn` and `inflections` dependencies. +- Upgrade `cider`, `parseedn` and `inflections` dependencies. ## 3.5.2 -* Use refactor-nrepl [3.5.2](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.2/CHANGELOG.md#352). +- Use refactor-nrepl [3.5.2](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.2/CHANGELOG.md#352). ## 3.5.1 -* Use refactor-nrepl [3.5.1](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.1/CHANGELOG.md#351). +- Use refactor-nrepl [3.5.1](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.1/CHANGELOG.md#351). ## 3.5.0 -* Use refactor-nrepl [3.5.0](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.0/CHANGELOG.md#350). -* Improve integration with Clojure 1.11's new `:as-alias` namespace directive. - * Closes [#515](https://github.com/clojure-emacs/clj-refactor.el/issues/515), [#516](https://github.com/clojure-emacs/clj-refactor.el/issues/516) +- Use refactor-nrepl [3.5.0](https://github.com/clojure-emacs/refactor-nrepl/blob/v3.5.0/CHANGELOG.md#350). +- Improve integration with Clojure 1.11's new `:as-alias` namespace directive. + - Closes [#515](https://github.com/clojure-emacs/clj-refactor.el/issues/515), [#516](https://github.com/clojure-emacs/clj-refactor.el/issues/516) ## 3.4.3 diff --git a/README.md b/README.md index 06a4d6d..89c552c 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.13.0+ | 1.11+ | 1.10+ | 8+ | +4.0.0+ | 3.x (3.13.0+ recommended) | 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 2ffd8a1..1b0d97d 100644 --- a/clj-refactor.el +++ b/clj-refactor.el @@ -1010,15 +1010,29 @@ with those of other middleware.") "Return refactor-nrepl op OP as its canonical namespaced name." (concat cljr--middleware-op-prefix op)) +(defun cljr--resolve-op (op) + "Resolve the bare refactor-nrepl OP name against the current connection. +Prefer the canonical namespaced form (see `cljr--middleware-op'), but fall +back to the bare name when only that is advertised - refactor-nrepl older +than 3.13.0 doesn't know the namespaced ops. When there's no connection to +consult, or neither form is supported, return the namespaced form so error +messages show the canonical name." + (let ((namespaced (cljr--middleware-op op))) + (cond ((not (cider-connected-p)) namespaced) + ((cider-nrepl-op-supported-p namespaced) namespaced) + ((cider-nrepl-op-supported-p op) op) + (t namespaced)))) + (defun cljr--create-msg (op &rest kvs) "Create a msg for the middleware for OP and optionally include the kv pairs KVS. -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." +OP is given as its bare refactor-nrepl name and is resolved to the form the +connected middleware supports (see `cljr--resolve-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" (cljr--middleware-op op) + "op" (cljr--resolve-op op) "prefix-rewriting" (if cljr-favor-prefix-notation @@ -1245,14 +1259,16 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-rename-file-or-d (defun cljr--op-supported-p (op) "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." +Checks the canonical namespaced form (see `cljr--middleware-op') as well as +the bare one, so old middleware that only advertises the bare names counts +as support too - matching the op resolution `cljr--create-msg' performs." ;; 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 (cljr--middleware-op op)))) + (or (cider-nrepl-op-supported-p (cljr--middleware-op op)) + (cider-nrepl-op-supported-p op)))) (defun cljr--assert-middleware () (unless (featurep 'cider) @@ -3889,7 +3905,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" (cljr--middleware-op "extract-definition") + "op" (cljr--resolve-op "extract-definition") "ns" ns "dir" dir "file" filename @@ -3942,7 +3958,17 @@ for avoiding a warning that would be irrelevant for this case." :package-version "3.0.0") (defun cljr--middleware-version () - (cljr--call-middleware-sync (cljr--create-msg "version") "version")) + "Return the version of the connected refactor-nrepl, or nil. +A failed probe returns nil (with the error reported as a message) +instead of signaling: CIDER 2.0's senders reject unsupported ops +client-side, and this probe runs from `cider-connected-hook' where an +error would abort the rest of the startup checks - including the +out-of-sync warning itself." + (condition-case err + (cljr--call-middleware-sync (cljr--create-msg "version") "version") + (error (message "clj-refactor: middleware version probe failed: %s" + (error-message-string err)) + nil))) (defun cljr--check-middleware-version () "Check whether clj-refactor and nrepl-refactor versions are the same." @@ -3968,7 +3994,7 @@ warning by customizing `cljr-suppress-no-project-warning'.)")))) (interactive) (message "clj-refactor %s, refactor-nrepl %s" (cljr--version) - (or (ignore-errors (cljr--middleware-version)) + (or (cljr--middleware-version) "is unreachable"))) ;;;###autoload diff --git a/tests/unit-test.el b/tests/unit-test.el index cde9e44..c54e08b 100644 --- a/tests/unit-test.el +++ b/tests/unit-test.el @@ -424,7 +424,45 @@ str/")))) (describe "cljr--op-supported-p" (it "returns nil (rather than erroring) when no REPL is connected" (spy-on 'cider-connected-p :and-return-value nil) - (expect (cljr--op-supported-p "clean-ns") :to-be nil))) + (expect (cljr--op-supported-p "clean-ns") :to-be nil)) + (it "counts middleware that only advertises the bare op names as support" + (spy-on 'cider-connected-p :and-return-value t) + (spy-on 'cider-nrepl-op-supported-p :and-call-fake + (lambda (op) (member op '("clean-ns")))) + (expect (cljr--op-supported-p "clean-ns") :to-be-truthy))) + +(describe "cljr--resolve-op" + ;; refactor-nrepl >= 3.13.0 advertises every op under both its bare name + ;; and the namespaced `refactor/' form; older versions only know the bare + ;; names. We prefer the canonical namespaced form but must keep working + ;; against the old middleware. + (it "prefers the namespaced form when the middleware advertises it" + (spy-on 'cider-connected-p :and-return-value t) + (spy-on 'cider-nrepl-op-supported-p :and-call-fake + (lambda (op) (member op '("refactor/clean-ns" "clean-ns")))) + (expect (cljr--resolve-op "clean-ns") :to-equal "refactor/clean-ns")) + (it "falls back to the bare name on old middleware" + (spy-on 'cider-connected-p :and-return-value t) + (spy-on 'cider-nrepl-op-supported-p :and-call-fake + (lambda (op) (member op '("clean-ns")))) + (expect (cljr--resolve-op "clean-ns") :to-equal "clean-ns") + (expect (cadr (cljr--create-msg "clean-ns")) :to-equal "clean-ns")) + (it "returns the namespaced form when disconnected" + (spy-on 'cider-connected-p :and-return-value nil) + (expect (cljr--resolve-op "clean-ns") :to-equal "refactor/clean-ns")) + (it "returns the namespaced form when neither form is supported" + (spy-on 'cider-connected-p :and-return-value t) + (spy-on 'cider-nrepl-op-supported-p :and-return-value nil) + (expect (cljr--resolve-op "clean-ns") :to-equal "refactor/clean-ns"))) + +(describe "cljr--middleware-version" + (it "returns nil (rather than erroring) when the version probe fails" + ;; CIDER 2.0's senders signal a `user-error' client-side for unsupported + ;; ops; this probe runs from `cider-connected-hook', where an error would + ;; abort the startup checks - including the out-of-sync warning itself. + (spy-on 'cljr--call-middleware-sync :and-call-fake + (lambda (&rest _) (user-error "unsupported op"))) + (expect (cljr--middleware-version) :to-be nil))) (describe "cljr-clean-ns offline fallback" ;; Drive the real `cljr--op-supported-p' by faking a disconnected REPL,