@@ -263,6 +263,8 @@ The prefixes are used to generate the correct namespace."
263
263
(define-key map (kbd " C--" ) #'clojure-toggle-ignore )
264
264
(define-key map (kbd " _" ) #'clojure-toggle-ignore-surrounding-form )
265
265
(define-key map (kbd " C-_" ) #'clojure-toggle-ignore-surrounding-form )
266
+ (define-key map (kbd " P" ) #'clojure-promote-fn-literal )
267
+ (define-key map (kbd " C-P" ) #'clojure-promote-fn-literal )
266
268
map)
267
269
" Keymap for Clojure refactoring commands." )
268
270
(fset 'clojure-refactor-map clojure-refactor-map)
@@ -284,6 +286,7 @@ The prefixes are used to generate the correct namespace."
284
286
[" Toggle #_ ignore form" clojure-toggle-ignore]
285
287
[" Toggle #_ ignore of surrounding form" clojure-toggle-ignore-surrounding-form]
286
288
[" Add function arity" clojure-add-arity]
289
+ [" Promote #() fn literal" clojure-promote-fn-literal]
287
290
(" ns forms"
288
291
[" Insert ns form at the top" clojure-insert-ns-form]
289
292
[" Insert ns form here" clojure-insert-ns-form-at-point]
@@ -2769,6 +2772,67 @@ With a numeric prefix argument the let is introduced N lists up."
2769
2772
(interactive )
2770
2773
(clojure--move-to-let-internal (read-from-minibuffer " Name of bound symbol: " )))
2771
2774
2775
+ ; ;; Promoting #() function literals
2776
+ (defun clojure--gather-fn-literal-args ()
2777
+ " Return a cons cell (ARITY . VARARG)
2778
+ ARITY is number of arguments in the function,
2779
+ VARARG is a boolean of whether it takes a variable argument %&."
2780
+ (save-excursion
2781
+ (let ((end (save-excursion (clojure-forward-logical-sexp) (point )))
2782
+ (rgx (rx symbol-start " %" (group (? (or " &" (+ (in " 0-9" ))))) symbol-end))
2783
+ (arity 0 )
2784
+ (vararg nil ))
2785
+ (while (re-search-forward rgx end 'noerror )
2786
+ (when (not (or (clojure--in-comment-p) (clojure--in-string-p)))
2787
+ (let ((s (match-string 1 )))
2788
+ (if (string= s " &" )
2789
+ (setq vararg t )
2790
+ (setq arity
2791
+ (max arity
2792
+ (if (string= s " " ) 1
2793
+ (string-to-number s))))))))
2794
+ (cons arity vararg))))
2795
+
2796
+ (defun clojure--substitute-fn-literal-arg (arg sub end )
2797
+ " ARG is either a number or the symbol '&.
2798
+ SUB is a string to substitute with, and
2799
+ END marks the end of the fn expression"
2800
+ (save-excursion
2801
+ (let ((rgx (format " \\ _<%%%s \\ _>" (if (eq arg 1 ) " 1?" arg))))
2802
+ (while (re-search-forward rgx end 'noerror )
2803
+ (when (and (not (clojure--in-comment-p))
2804
+ (not (clojure--in-string-p)))
2805
+ (replace-match sub))))))
2806
+
2807
+ (defun clojure-promote-fn-literal ()
2808
+ " Convert a #(...) function into (fn [...] ...), prompting for the argument names."
2809
+ (interactive )
2810
+ (when-let (beg (clojure-string-start))
2811
+ (goto-char beg))
2812
+ (if (or (looking-at-p " #(" )
2813
+ (ignore-errors (forward-char 1 ))
2814
+ (re-search-backward " #(" (save-excursion (beginning-of-defun ) (point )) 'noerror ))
2815
+ (let* ((end (save-excursion (clojure-forward-logical-sexp) (point-marker )))
2816
+ (argspec (clojure--gather-fn-literal-args))
2817
+ (arity (car argspec))
2818
+ (vararg (cdr argspec)))
2819
+ (delete-char 1 )
2820
+ (save-excursion (forward-sexp 1 ) (insert " )" ))
2821
+ (save-excursion
2822
+ (insert " (fn [] " )
2823
+ (backward-char 2 )
2824
+ (mapc (lambda (n )
2825
+ (let ((name (read-string (format " Name of argument %d : " n))))
2826
+ (when (/= n 1 ) (insert " " ))
2827
+ (insert name)
2828
+ (clojure--substitute-fn-literal-arg n name end)))
2829
+ (number-sequence 1 arity))
2830
+ (when vararg
2831
+ (insert " & " )
2832
+ (let ((name (read-string " Name of variadic argument: " )))
2833
+ (insert name)
2834
+ (clojure--substitute-fn-literal-arg '& name end)))))
2835
+ (user-error " No #() literal at point!" )))
2772
2836
2773
2837
; ;; Renaming ns aliases
2774
2838
0 commit comments