From 51ee2c243b64e03457549617c0fd9fe78f11d326 Mon Sep 17 00:00:00 2001 From: Benedek Fazekas Date: Fri, 7 Apr 2017 09:21:22 +0100 Subject: [PATCH] [Fix #429] Last occurrence sometimes not replaced for `move-to-let` In case * there are more than one occurrences of expression * and move to let is not initiated from the last occurrence * and actual bound name is longer than the expression being moved to let the last expression won't be replaced. Fix: end of `let` expression is not cached before calling `clojure--replace-sexps-with-binding`. --- CHANGELOG.md | 1 + clojure-mode.el | 18 ++++++++++-------- test/clojure-mode-refactor-let-test.el | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fb84904..0fe95746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Bugs fixed +* [#429](https://github.com/clojure-emacs/clojure-mode/issues/429): Fix a bug causing last occurrence of expression sometimes is not replaced when using `move-to-let`. * [#423](https://github.com/clojure-emacs/clojure-mode/issues/423): Make `clojure-match-next-def` more robust against zero-arity def-like forms. ### New features diff --git a/clojure-mode.el b/clojure-mode.el index 7c958496..3c52b20f 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -2213,24 +2213,26 @@ Assume that point is in the binding form of a let." "[[:space:]\n\r]+") "\\([^[:word:]^-]\\)")) -(defun clojure--replace-sexp-with-binding (bound-name init-expr end) +(defun clojure--replace-sexp-with-binding (bound-name init-expr) (save-excursion - (while (re-search-forward (clojure--sexp-regexp init-expr) end t) + (while (re-search-forward + (clojure--sexp-regexp init-expr) + (clojure--point-after 'clojure--goto-let 'forward-sexp) + t) (replace-match (concat "\\1" bound-name "\\2"))))) -(defun clojure--replace-sexps-with-bindings (bindings end) +(defun clojure--replace-sexps-with-bindings (bindings) "Replace bindings with their respective bound names in the let form. -BINDINGS is the list of bound names and init expressions, END denotes the end of the let expression." +BINDINGS is the list of bound names and init expressions." (let ((bound-name (pop bindings)) (init-expr (pop bindings))) (when bound-name - (clojure--replace-sexp-with-binding bound-name init-expr end) - (clojure--replace-sexps-with-bindings bindings end)))) + (clojure--replace-sexp-with-binding bound-name init-expr) + (clojure--replace-sexps-with-bindings bindings)))) (defun clojure--replace-sexps-with-bindings-and-indent () (clojure--replace-sexps-with-bindings - (clojure--read-let-bindings) - (clojure--point-after 'clojure--goto-let 'forward-sexp)) + (clojure--read-let-bindings)) (clojure-indent-region (clojure--point-after 'clojure--goto-let) (clojure--point-after 'clojure--goto-let 'forward-sexp))) diff --git a/test/clojure-mode-refactor-let-test.el b/test/clojure-mode-refactor-let-test.el index 458ca5f4..6fe55b37 100644 --- a/test/clojure-mode-refactor-let-test.el +++ b/test/clojure-mode-refactor-let-test.el @@ -164,6 +164,21 @@ (search-backward "(or ") (clojure--move-to-let-internal "status")) +(def-refactor-test test-move-to-let-name-longer-than-expression + "(defn handle-request + (let [] + (println \"body: \" body \", params: \" \", status: \" 5) + {:body body + :status 5}))" + "(defn handle-request + (let [status 5] + (println \"body: \" body \", params: \" \", status: \" status) + {:body body + :status status}))" + (search-backward "5") + (search-backward "5") + (clojure--move-to-let-internal "status")) + ;; clojure-emacs/clj-refactor.el#41 (def-refactor-test test-move-to-let-nested-scope "(defn foo []