From 084d4c0a28ed02847ac9a711c020ac8c22ca91b3 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Thu, 16 Jul 2026 18:03:29 +0300 Subject: [PATCH] Fix the offline ns sort doing nothing in clojure-ts-mode clojure-ts-mode installs a tree-sitter forward-sexp-function, which turns clojure-sort-ns's syntax-table-based walk into a silent no-op: cljr-clean-ns without a REPL reported success while leaving the ns form untouched (same for cljr-auto-sort-ns). Force the default sexp movement around the sort. The proper fix belongs in clojure-sort-ns itself; this shields our two call sites until that lands. --- CHANGELOG.md | 1 + clj-refactor.el | 13 +++++++++++-- tests/unit-test.el | 16 +++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e70467e..df6c5ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - 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). +- Fix the offline ns-form sort (`cljr-clean-ns` and `cljr-auto-sort-ns` without a REPL) silently doing nothing in `clojure-ts-mode` buffers, where the tree-sitter `forward-sexp-function` broke `clojure-sort-ns`. - `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). diff --git a/clj-refactor.el b/clj-refactor.el index 1b0d97d..9cfc5a5 100644 --- a/clj-refactor.el +++ b/clj-refactor.el @@ -1511,6 +1511,15 @@ word test in it and whether the file lives under the test/ directory." (remove-hook 'yas-after-exit-snippet-hook 'cljr--maybe-eval-ns-form-and-remove-hook :local)) +(defun cljr--sort-ns () + "Sort the ns form syntactically via `clojure-sort-ns'. +`clojure-sort-ns' walks the form with `forward-sexp' assuming +syntax-table-based movement; under clojure-ts-mode's tree-sitter-based +`forward-sexp-function' the sort silently does nothing, so force the +default movement here." + (let ((forward-sexp-function nil)) + (clojure-sort-ns))) + (defun cljr--maybe-sort-ns () (when cljr-auto-sort-ns (if (and (cider-connected-p) (cljr--op-supported-p "clean-ns")) @@ -1518,7 +1527,7 @@ word test in it and whether the file lives under the test/ directory." ;; Offline: sort the ns form syntactically via clojure-mode, quietly, ;; so this stays useful without a running REPL. (let ((inhibit-message t)) - (ignore-errors (clojure-sort-ns)))))) + (ignore-errors (cljr--sort-ns)))))) (defun cljr--sort-and-remove-hook (&rest _) (cljr--maybe-sort-ns) @@ -3388,7 +3397,7 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-clean-ns" (progn (cider-eval-ns-form) (cljr--clean-ns)) - (clojure-sort-ns) + (cljr--sort-ns) (cljr--post-command-message "Sorted the ns form (pruning unused libspecs needs the refactor-nrepl middleware)."))) diff --git a/tests/unit-test.el b/tests/unit-test.el index c54e08b..d8ab51b 100644 --- a/tests/unit-test.el +++ b/tests/unit-test.el @@ -485,7 +485,21 @@ str/")))) (insert "(ns foo\n (:require [a.a :as a]))\n") (cljr-clean-ns) (expect 'cljr--clean-ns :not :to-have-been-called) - (expect 'cider-eval-ns-form :not :to-have-been-called)))) + (expect 'cider-eval-ns-form :not :to-have-been-called))) + (it "sorts the ns form even under a non-default forward-sexp-function" + ;; clojure-ts-mode installs a tree-sitter-based `forward-sexp-function' + ;; that turns `clojure-sort-ns' into a silent no-op; `cljr--sort-ns' + ;; must force the default syntax-table-based movement. + (spy-on 'cljr--post-command-message) + (cljr--with-clojure-temp-file "foo.clj" + (insert "(ns foo\n (:require [b.b :as b]\n [a.a :as a]))\n") + (setq-local forward-sexp-function + (lambda (&rest _) (error "tree-sitter movement stand-in"))) + (cljr-clean-ns) + (expect (buffer-string) :to-equal "(ns foo + (:require [a.a :as a] + [b.b :as b])) +")))) (describe "cljr--remove-tramp-prefix-from-msg" (it "Removes the tramp prefix from specifc nrepl message attributes"