Skip to content

Improve support of extend-protocol forms #96

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 17, 2025
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,10 @@

## main (unreleased)

- [#96](https://github.com/clojure-emacs/clojure-ts-mode/pull/96): Highlight function name properly in `extend-protocol` form.
- [#96](https://github.com/clojure-emacs/clojure-ts-mode/pull/96): Add support for extend-protocol forms to `clojure-ts-add-arity` refactoring
command.

## 0.4.0 (2025-05-15)

- [#16](https://github.com/clojure-emacs/clojure-ts-mode/issues/16): Introduce `clojure-ts-align`.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -448,7 +448,7 @@ set. The following commands are available:
`clojure-ts-add-arity`: Add a new arity to an existing single-arity or
multi-arity function or macro. Function can be defined using `defn`, `fn` or
`defmethod` form. This command also supports functions defined inside forms like
`letfn`, `defprotol`, `reify` or `proxy`.
`letfn`, `defprotol`, `reify`, `extend-protocol` or `proxy`.

### Default keybindings

19 changes: 17 additions & 2 deletions clojure-ts-mode.el
Original file line number Diff line number Diff line change
@@ -602,7 +602,12 @@ literals with regex grammar."
(sym_lit name: (sym_name) @font-lock-function-name-face))))
((list_lit
((sym_lit name: (sym_name) @def)
((:equal "reify" @def)))
((:match ,(rx-to-string
`(seq bol
(or "reify"
"extend-protocol")
eol))
@def)))
(list_lit
(sym_lit name: (sym_name) @font-lock-function-name-face))))
;; letfn
@@ -2186,6 +2191,12 @@ type, etc. See `treesit-thing-settings' for more details."
(and (clojure-ts--list-node-p node)
(string= (clojure-ts--list-node-sym-text parent) "reify"))))

(defun clojure-ts--extend-protocol-defn-p (node)
"Return non-nil if NODE is a function definition in an extend-protocol form."
(when-let* ((parent (treesit-node-parent node)))
(and (clojure-ts--list-node-p node)
(string= (clojure-ts--list-node-sym-text parent) "extend-protocol"))))

(defun clojure-ts-add-arity ()
"Add an arity to a function or macro."
(interactive)
@@ -2196,6 +2207,7 @@ type, etc. See `treesit-thing-settings' for more details."
"defmacro"
"defmethod"
"defprotocol"
"extend-protocol"
"reify"
"proxy")
eol))
@@ -2210,13 +2222,16 @@ type, etc. See `treesit-thing-settings' for more details."
(clojure-ts--parent-until #'clojure-ts--defprotocol-defn-p))
((string= parent-def-sym "reify")
(clojure-ts--parent-until #'clojure-ts--reify-defn-p))
((string= parent-def-sym "extend-protocol")
(clojure-ts--parent-until #'clojure-ts--extend-protocol-defn-p))
(t parent-def-node))))
(let ((beg-marker (copy-marker (treesit-node-start parent-def-node)))
(end-marker (copy-marker (treesit-node-end parent-def-node))))
(cond
((string= parent-def-sym "defprotocol")
(clojure-ts--add-arity-defprotocol-internal fn-node))
((string= parent-def-sym "reify")
((or (string= parent-def-sym "reify")
(string= parent-def-sym "extend-protocol"))
(clojure-ts--add-arity-reify-internal fn-node))
(t (clojure-ts--add-arity-internal fn-node)))
(indent-region beg-marker end-marker))
8 changes: 7 additions & 1 deletion test/clojure-ts-mode-font-lock-test.el
Original file line number Diff line number Diff line change
@@ -223,4 +223,10 @@ DESCRIPTION is the description of the spec."
(2 12 font-lock-keyword-face)
(14 14 font-lock-type-face)
(19 21 font-lock-function-name-face)
(34 39 font-lock-function-name-face))))
(34 39 font-lock-function-name-face))

("(extend-protocol prepare/SettableParameter
clojure.lang.IPersistentMap
(set-parameter [m ^PreparedStatement s i]
(.setObject s i (->pgobject m))))"
(81 93 font-lock-function-name-face))))
14 changes: 14 additions & 0 deletions test/clojure-ts-mode-refactor-add-arity-test.el
Original file line number Diff line number Diff line change
@@ -324,6 +324,20 @@

(clojure-ts-add-arity))

(when-refactoring-with-point-it "should handle an extend-protocol"
"(extend-protocol prepare/SettableParameter
clojure.lang.IPersistentMap
(set-parameter [m ^PreparedStatement s i]
(.setObject| s i (->pgobject m))))"

"(extend-protocol prepare/SettableParameter
clojure.lang.IPersistentMap
(set-parameter [|])
(set-parameter [m ^PreparedStatement s i]
(.setObject s i (->pgobject m))))"

(clojure-ts-add-arity))

(it "should signal a user error when point is not inside a function body"
(with-clojure-ts-buffer-point "
(letf|n [(foo
6 changes: 6 additions & 0 deletions test/samples/refactoring.clj
Original file line number Diff line number Diff line change
@@ -141,3 +141,9 @@

(when-not true
(println "Hello world"))

(extend-protocol prepare/SettableParameter
clojure.lang.IPersistentMap
(set-parameter [])
(set-parameter [m ^PreparedStatement s i]
(.setObject| s i (->pgobject m))))