Skip to content

Commit f23eb20

Browse files
anthonygaleabbatsov
authored andcommitted
Enhance add arity refactoring (#541)
Support reader conditionals, letfn, fn, defmacro, defmethod, defprotocol, reify and proxy in addition to defn.
1 parent 2f90ebc commit f23eb20

File tree

3 files changed

+267
-23
lines changed

3 files changed

+267
-23
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
### Bugs fixed
66

77
* [#520](https://github.com/clojure-emacs/clojure-mode/issues/508): Fix allow `clojure-align-cond-forms` to recognize qualified forms.
8+
* Enhance add arity refactoring to support a defn inside a reader conditional.
9+
10+
### Changes
11+
12+
* Enhance add arity refactoring to support new forms: letfn, fn, defmacro, defmethod, defprotocol, reify and proxy.
813

914
## 5.11.0 (2019-07-16)
1015

clojure-mode.el

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2738,37 +2738,80 @@ With a numeric prefix argument the let is introduced N lists up."
27382738
(clojure--rename-ns-alias-internal current-alias new-alias))
27392739
(message "Cannot find namespace alias: '%s'" current-alias))))))
27402740

2741-
;;;###autoload
2742-
(defun clojure-add-arity ()
2743-
"Add an arity to a function."
2744-
(interactive)
2745-
(let ((end (save-excursion (end-of-defun)
2746-
(point)))
2747-
(beg (progn (beginning-of-defun)
2748-
(point))))
2741+
(defun clojure--add-arity-defprotocol-internal ()
2742+
"Add an arity to a signature inside a defprotocol.
2743+
2744+
Assumes cursor is at beginning of signature."
2745+
(re-search-forward "\\[")
2746+
(save-excursion (insert "] [")))
2747+
2748+
(defun clojure--add-arity-reify-internal ()
2749+
"Add an arity to a function inside a reify.
2750+
2751+
Assumes cursor is at beginning of function."
2752+
(re-search-forward "\\(\\w+ \\)")
2753+
(insert "[")
2754+
(save-excursion (insert "])\n(" (match-string 0))))
2755+
2756+
(defun clojure--add-arity-internal ()
2757+
"Add an arity to a function.
2758+
2759+
Assumes cursor is at beginning of function."
2760+
(let ((beg-line (what-line))
2761+
(end (save-excursion (forward-sexp)
2762+
(point))))
27492763
(down-list 2)
27502764
(when (looking-back "{" 1) ;; skip metadata if present
27512765
(up-list)
27522766
(down-list))
27532767
(cond
2754-
((looking-back "(" 1) ;; multi-arity defn
2768+
((looking-back "(" 1) ;; multi-arity fn
27552769
(insert "[")
2756-
(save-excursion (insert "])\n("))
2757-
(indent-region beg end))
2758-
((looking-back "\\[" 1) ;; single-arity defn
2759-
(let* ((bol (save-excursion (beginning-of-line) (point)))
2760-
(same-line (save-excursion (re-search-backward "defn" bol t)))
2761-
(new-arity-text (concat (when same-line "\n") "([])\n[")))
2762-
(re-search-backward " +\\[")
2763-
(replace-match new-arity-text)
2770+
(save-excursion (insert "])\n(")))
2771+
((looking-back "\\[" 1) ;; single-arity fn
2772+
(let* ((same-line (string= beg-line (what-line)))
2773+
(new-arity-text (concat (when same-line "\n") "([")))
27642774
(save-excursion
2765-
(end-of-defun)
2766-
(re-search-backward ")")
2775+
(goto-char end)
27672776
(insert ")"))
2768-
(left-char)
2769-
(insert "(")
2770-
(indent-region beg end)
2771-
(left-char 6))))))
2777+
2778+
(re-search-backward " +\\[")
2779+
(replace-match new-arity-text)
2780+
(save-excursion (insert "])\n([")))))))
2781+
2782+
;;;###autoload
2783+
(defun clojure-add-arity ()
2784+
"Add an arity to a function."
2785+
(interactive)
2786+
(let ((original-pos (point))
2787+
(n 0))
2788+
(while (not (looking-at-p "(\\(defn\\|letfn\\|fn\\|defmacro\\|defmethod\\|defprotocol\\|reify\\|proxy\\)"))
2789+
(setq n (1+ n))
2790+
(backward-up-list 1 t))
2791+
(let ((beg (point))
2792+
(end-marker (make-marker))
2793+
(end (save-excursion (forward-sexp)
2794+
(point)))
2795+
(jump-up (lambda (x)
2796+
(goto-char original-pos)
2797+
(backward-up-list x t))))
2798+
(set-marker end-marker end)
2799+
(cond
2800+
((looking-at-p "(\\(defn\\|fn\\|defmethod\\|defmacro\\)")
2801+
(clojure--add-arity-internal))
2802+
((looking-at-p "(letfn")
2803+
(funcall jump-up (- n 2))
2804+
(clojure--add-arity-internal))
2805+
((looking-at-p "(proxy")
2806+
(funcall jump-up (- n 1))
2807+
(clojure--add-arity-internal))
2808+
((looking-at-p "(defprotocol")
2809+
(funcall jump-up (- n 1))
2810+
(clojure--add-arity-defprotocol-internal))
2811+
((looking-at-p "(reify")
2812+
(funcall jump-up (- n 1))
2813+
(clojure--add-arity-reify-internal)))
2814+
(indent-region beg end-marker))))
27722815

27732816

27742817
;;; ClojureScript

test/clojure-mode-refactor-add-arity-test.el

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,202 @@ DESCRIPTION is a string with the description of the spec."
149149
([arg]
150150
body))"
151151

152+
(clojure-add-arity))
153+
154+
(when-refactoring-with-point-it "should handle a single-arity fn"
155+
"(fn foo [arg]
156+
body|)"
157+
158+
"(fn foo
159+
([|])
160+
([arg]
161+
body))"
162+
163+
(clojure-add-arity))
164+
165+
(when-refactoring-with-point-it "should handle a multi-arity fn"
166+
"(fn foo
167+
([x y]
168+
body)
169+
([a|rg]
170+
body))"
171+
172+
"(fn foo
173+
([|])
174+
([x y]
175+
body)
176+
([arg]
177+
body))"
178+
179+
(clojure-add-arity))
180+
181+
(when-refactoring-with-point-it "should handle a single-arity defmacro"
182+
"(defmacro foo [arg]
183+
body|)"
184+
185+
"(defmacro foo
186+
([|])
187+
([arg]
188+
body))"
189+
190+
(clojure-add-arity))
191+
192+
(when-refactoring-with-point-it "should handle a multi-arity defmacro"
193+
"(defmacro foo
194+
([x y]
195+
body)
196+
([a|rg]
197+
body))"
198+
199+
"(defmacro foo
200+
([|])
201+
([x y]
202+
body)
203+
([arg]
204+
body))"
205+
206+
(clojure-add-arity))
207+
208+
(when-refactoring-with-point-it "should handle a single-arity defmethod"
209+
"(defmethod foo :bar [arg]
210+
body|)"
211+
212+
"(defmethod foo :bar
213+
([|])
214+
([arg]
215+
body))"
216+
217+
(clojure-add-arity))
218+
219+
(when-refactoring-with-point-it "should handle a multi-arity defmethod"
220+
"(defmethod foo :bar
221+
([x y]
222+
body)
223+
([a|rg]
224+
body))"
225+
226+
"(defmethod foo :bar
227+
([|])
228+
([x y]
229+
body)
230+
([arg]
231+
body))"
232+
233+
(clojure-add-arity))
234+
235+
(when-refactoring-with-point-it "should handle a defn inside a reader conditional"
236+
"#?(:clj
237+
(defn foo
238+
\"some docstring\"
239+
^{:bla \"meta\"}
240+
|([arg]
241+
body)))"
242+
243+
"#?(:clj
244+
(defn foo
245+
\"some docstring\"
246+
^{:bla \"meta\"}
247+
([|])
248+
([arg]
249+
body)))"
250+
251+
(clojure-add-arity))
252+
253+
(when-refactoring-with-point-it "should handle a defn inside a reader conditional with 2 platform tags"
254+
"#?(:clj
255+
(defn foo
256+
\"some docstring\"
257+
^{:bla \"meta\"}
258+
|([arg]
259+
body))
260+
:cljs
261+
(defn foo
262+
\"some docstring\"
263+
^{:bla \"meta\"}
264+
([arg]
265+
body)))"
266+
267+
"#?(:clj
268+
(defn foo
269+
\"some docstring\"
270+
^{:bla \"meta\"}
271+
([|])
272+
([arg]
273+
body))
274+
:cljs
275+
(defn foo
276+
\"some docstring\"
277+
^{:bla \"meta\"}
278+
([arg]
279+
body)))"
280+
281+
(clojure-add-arity))
282+
283+
(when-refactoring-with-point-it "should handle a single-arity fn inside a letfn"
284+
"(letfn [(foo [x]
285+
bo|dy)]
286+
(foo 3))"
287+
288+
"(letfn [(foo
289+
([|])
290+
([x]
291+
body))]
292+
(foo 3))"
293+
294+
(clojure-add-arity))
295+
296+
(when-refactoring-with-point-it "should handle a multi-arity fn inside a letfn"
297+
"(letfn [(foo
298+
([x]
299+
body)
300+
|([x y]
301+
body))]
302+
(foo 3))"
303+
304+
"(letfn [(foo
305+
([|])
306+
([x]
307+
body)
308+
([x y]
309+
body))]
310+
(foo 3))"
311+
312+
(clojure-add-arity))
313+
314+
(when-refactoring-with-point-it "should handle a proxy"
315+
"(proxy [Foo] []
316+
(bar [arg]
317+
body|))"
318+
319+
"(proxy [Foo] []
320+
(bar
321+
([|])
322+
([arg]
323+
body)))"
324+
325+
(clojure-add-arity))
326+
327+
(when-refactoring-with-point-it "should handle a defprotocol"
328+
"(defprotocol Foo
329+
\"some docstring\"
330+
(bar [arg] [x |y] \"some docstring\"))"
331+
332+
"(defprotocol Foo
333+
\"some docstring\"
334+
(bar [|] [arg] [x y] \"some docstring\"))"
335+
336+
(clojure-add-arity))
337+
338+
(when-refactoring-with-point-it "should handle a reify"
339+
"(reify Foo
340+
(bar [arg] body)
341+
(blahs [arg]| body))"
342+
343+
"(reify Foo
344+
(bar [arg] body)
345+
(blahs [|])
346+
(blahs [arg] body))"
347+
152348
(clojure-add-arity)))
153349

154350
(provide 'clojure-mode-refactor-add-arity-test)

0 commit comments

Comments
 (0)