@@ -263,6 +263,8 @@ The prefixes are used to generate the correct namespace."
263263 (define-key map (kbd " C--" ) #'clojure-toggle-ignore )
264264 (define-key map (kbd " _" ) #'clojure-toggle-ignore-surrounding-form )
265265 (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 )
266268 map)
267269 " Keymap for Clojure refactoring commands." )
268270(fset 'clojure-refactor-map clojure-refactor-map)
@@ -284,6 +286,7 @@ The prefixes are used to generate the correct namespace."
284286 [" Toggle #_ ignore form" clojure-toggle-ignore]
285287 [" Toggle #_ ignore of surrounding form" clojure-toggle-ignore-surrounding-form]
286288 [" Add function arity" clojure-add-arity]
289+ [" Promote #() fn literal" clojure-promote-fn-literal]
287290 (" ns forms"
288291 [" Insert ns form at the top" clojure-insert-ns-form]
289292 [" 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."
27692772 (interactive )
27702773 (clojure--move-to-let-internal (read-from-minibuffer " Name of bound symbol: " )))
27712774
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!" )))
27722836
27732837; ;; Renaming ns aliases
27742838
0 commit comments