Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

### Bugs fixed

* [#649](https://github.com/clojure-emacs/clojure-mode/issues/649): Fix `clojure-add-arity` severing arglist metadata (`^String`, `^:keyword`, `^{...}`) when converting single-arity to multi-arity.
* Fix typos in `clojure-mode-extra-font-locking`: `halt-when?` -> `halt-when`, `simple-indent?` -> `simple-ident?`.
* Fix `doc` and `find-doc` misplaced under `clojure.core` instead of `clojure.repl` in extra font-locking.

Expand Down
37 changes: 32 additions & 5 deletions clojure-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -3211,6 +3211,19 @@ Assumes cursor is at beginning of function."
(insert "[")
(save-excursion (insert "])\n(" (match-string 0))))

(defun clojure--find-arglist-metadata-start (bracket-pos)
"Return the start of metadata annotations before BRACKET-POS.
If no metadata is found, return BRACKET-POS."
(save-excursion
(goto-char bracket-pos)
(let ((result bracket-pos))
(ignore-errors
(while (progn
(backward-sexp)
(eq (char-after) ?^))
(setq result (point))))
result)))

(defun clojure--add-arity-internal ()
"Add an arity to a function.

Expand All @@ -3228,14 +3241,28 @@ Assumes cursor is at beginning of function."
(save-excursion (insert "])\n(")))
((looking-back "\\[" 1) ;; single-arity fn
(let* ((same-line (= beg-line (line-number-at-pos)))
(new-arity-text (concat (when same-line "\n") "([")))
(bracket-pos (1- (point)))
(meta-start (clojure--find-arglist-metadata-start bracket-pos)))
(save-excursion
(goto-char end)
(insert ")"))

(re-search-backward " +\\[")
(replace-match new-arity-text)
(save-excursion (insert "])\n([")))))))
(if (< meta-start bracket-pos)
;; Has metadata before arglist — include it in the arity wrapper
(let ((meta-text (replace-regexp-in-string
"[ \t\n\r]+" " "
(string-trim
(buffer-substring meta-start bracket-pos)))))
(goto-char meta-start)
(skip-chars-backward " \t\n")
(delete-region (point) (1+ bracket-pos))
(insert "\n([")
(save-excursion
(insert "])\n(" meta-text " [")))
;; No metadata — original behavior
(let ((new-arity-text (concat (when same-line "\n") "([")))
(re-search-backward " +\\[")
(replace-match new-arity-text)
(save-excursion (insert "])\n([")))))))))

;;;###autoload
(defun clojure-add-arity ()
Expand Down
42 changes: 40 additions & 2 deletions test/clojure-mode-refactor-add-arity-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,47 @@
body)"

"(defn foo
^{:bla \"meta\"}
([|])
([arg]
(^{:bla \"meta\"} [arg]
body))"

(clojure-add-arity))

(when-refactoring-with-point-it "should handle a single-arity defn with ^Type metadata"
"(defn string
^String
|[x]
(str x))"

"(defn string
([|])
(^String [x]
(str x)))"

(clojure-add-arity))

(when-refactoring-with-point-it "should handle a single-arity defn with ^:keyword metadata"
"(defn fo|o
^:private
[arg]
body)"

"(defn foo
([|])
(^:private [arg]
body))"

(clojure-add-arity))

(when-refactoring-with-point-it "should handle a single-arity defn with multiple metadata"
"(defn fo|o
^:private ^String
[arg]
body)"

"(defn foo
([|])
(^:private ^String [arg]
body))"

(clojure-add-arity))
Expand Down