From 83f5bf12be91194a40fad7271dc164a3ce2156d5 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Sun, 12 Jul 2026 12:14:27 +0300 Subject: [PATCH] Preview cljr-inline-symbol too Route cljr-inline-symbol through cljr--run-previewable-refactoring, like rename and change-signature: gather the edits, show a diff, and write only on confirm. Its two save-buffer calls (after the occurrence loop and in cljr--delete-definition) become cljr--save-buffer so they defer during a preview session, and the success message is guarded on the edits actually being applied. Validated live against a real refactor-nrepl connection: inlining a def (both usages replaced, definition removed) previewed and applied on confirm, left untouched on decline. --- CHANGELOG.md | 2 +- clj-refactor.el | 54 +++++++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81d6e24..84880c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Unreleased -- Preview project-wide refactorings before they touch disk. `cljr-rename-symbol` and `cljr-change-function-signature` now gather all their edits first and show them as a diff, and nothing is written until you confirm. Controlled by the new `cljr-preview-refactorings` (default on); set it to nil for the old apply-immediately behavior. +- Preview project-wide refactorings before they touch disk. `cljr-rename-symbol`, `cljr-change-function-signature` and `cljr-inline-symbol` now gather all their edits first and show them as a diff, and nothing is written until you confirm. Controlled by the new `cljr-preview-refactorings` (default on); set it to nil for the old apply-immediately behavior. - New `cljr-undo-last-refactoring` reverts every file changed by the last applied rename or change-signature in one step (bound to `ur`, and in `clj-refactor-menu`). - `cljr-change-function-signature` can now add and remove parameters, not just reorder and rename them. In the edit buffer, `a` adds a parameter (you're prompted for its name and a placeholder to insert at call sites) and `k`/`d` marks one for removal. Added parameters get their placeholder inserted at every call site; removals are never auto-deleted (an argument might have side effects) - the affected call sites are routed to the manual-intervention buffer for review. diff --git a/clj-refactor.el b/clj-refactor.el index 3256238..f67987f 100644 --- a/clj-refactor.el +++ b/clj-refactor.el @@ -3679,7 +3679,7 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-add-stubs" (cljr--indent-defun)) (when (looking-at-p "\s*\n") (cljr--just-one-blank-line)) - (save-buffer)))) + (cljr--save-buffer)))) (defun cljr--sort-occurrences (occurrences) "Sort the OCCURRENCES so the last ones in the file comes first." @@ -3718,29 +3718,31 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-add-stubs" (insert def))) (defun cljr--inline-symbol (definition occurrences) - (cljr--with-opened-buffers - (let* ((def (gethash :definition definition)) - (inline-fn-p (string-prefix-p "(fn" def))) - (dolist (symbol-meta (cljr--sort-occurrences occurrences)) - (let* ((file (cljr--get-valid-filename symbol-meta)) - (line-beg (gethash :line-beg symbol-meta)) - (col-beg (gethash :col-beg symbol-meta))) - (with-current-buffer (cljr--find-file-noselect file) - (goto-char (point-min)) - (forward-line (1- line-beg)) - (forward-char (1- col-beg)) - (let* ((call-site-p (and inline-fn-p - (looking-back "(\s*" (line-beginning-position)))) - (sexp (if call-site-p - (prog1 (cljr--extract-sexp-as-list) - (paredit-backward-up) - (clojure-delete-and-extract-sexp)) - (clojure-delete-and-extract-sexp)))) - (if call-site-p - (cljr--inline-fn-at-call-site def sexp) - (insert def))))))) - (save-buffer) - (cljr--delete-definition definition))) + (cljr--run-previewable-refactoring + "Inline symbol" + (lambda () + (let* ((def (gethash :definition definition)) + (inline-fn-p (string-prefix-p "(fn" def))) + (dolist (symbol-meta (cljr--sort-occurrences occurrences)) + (let* ((file (cljr--get-valid-filename symbol-meta)) + (line-beg (gethash :line-beg symbol-meta)) + (col-beg (gethash :col-beg symbol-meta))) + (with-current-buffer (cljr--find-file-noselect file) + (goto-char (point-min)) + (forward-line (1- line-beg)) + (forward-char (1- col-beg)) + (let* ((call-site-p (and inline-fn-p + (looking-back "(\s*" (line-beginning-position)))) + (sexp (if call-site-p + (prog1 (cljr--extract-sexp-as-list) + (paredit-backward-up) + (clojure-delete-and-extract-sexp)) + (clojure-delete-and-extract-sexp)))) + (if call-site-p + (cljr--inline-fn-at-call-site def sexp) + (insert def)))))) + (cljr--save-buffer) + (cljr--delete-definition definition))))) (defun cljr--var-info (&optional symbol all) "Like `cider-var-info' but also handles locally bound vars. @@ -3794,8 +3796,8 @@ See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-inline-symbol" extract-definition-request "definition"))) (definition (gethash :definition response)) (occurrences (gethash :occurrences response))) - (cljr--inline-symbol definition occurrences) - (unless *cljr--noninteractive* ; don't spam when called from `cljr-remove-let' + (when (and (cljr--inline-symbol definition occurrences) + (not *cljr--noninteractive*)) (if occurrences (cljr--post-command-message "Inlined %s occurrence(s) of '%s'" (length occurrences) symbol) (cljr--post-command-message "No occurrences of '%s' found. Deleted the definition." symbol)))))