Skip to content

Introduce clojure-ts-extra-def-forms customization #104

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 2 commits into from
May 31, 2025
Merged
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
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
- [#99](https://github.com/clojure-emacs/clojure-ts-mode/pull/99): Fix bug in `clojure-ts-align` when nested form has extra spaces.
- [#99](https://github.com/clojure-emacs/clojure-ts-mode/pull/99): Fix bug in `clojure-ts-unwind` when there is only one expression after
threading symbol.
- Introduce `clojure-ts-jank-use-cpp-parser` customization which allows
- [#103](https://github.com/clojure-emacs/clojure-ts-mode/issues/103): Introduce `clojure-ts-jank-use-cpp-parser` customization which allows
highlighting C++ syntax in Jank `native/raw` forms.
- Introduce `clojure-ts-clojurescript-use-js-parser` customization which allows
highlighting JS syntax in ClojureScript `js*` forms.

- [#103](https://github.com/clojure-emacs/clojure-ts-mode/issues/103): Introduce `clojure-ts-clojurescript-use-js-parser` customization which
allows highlighting JS syntax in ClojureScript `js*` forms.
- Introduce the `clojure-ts-extra-def-forms` customization option to specify
additional `defn`-like forms that should be fontified.

## 0.4.0 (2025-05-15)

Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,37 @@ highlighted like regular Clojure code.
> section](https://www.gnu.org/software/emacs/manual/html_node/emacs/Parser_002dbased-Font-Lock.html)
> of the Emacs manual for more details.

#### Extending font-lock rules

In `clojure-ts-mode` it is possible to specify additional defn-like forms that
should be fontified. For example to highlight the following form from Hiccup
library as a function definition:

```clojure
(defelem file-upload
"Creates a file upload input."
[name]
(input-field "file" name nil))
```

You can add `defelem` to `clojure-ts-extra-def-forms` list like this:

```emacs-lisp
(add-to-list 'clojure-ts-extra-def-forms "defelem")
```

or set this variable using `setopt`:

```emacs-lisp
(setopt clojure-ts-extra-def-forms '("defelem"))
```

This setting will highlight `defelem` symbol, function name and the docstring.

**NOTE**: Setting `clojure-ts-extra-def-forms` won't change the indentation rule for
these forms. For indentation rules you should use
`clojure-ts-semantic-indent-rules` variable (see [semantic indentation](#customizing-semantic-indentation) section).

### Highlight markdown syntax in docstrings

By default Markdown syntax is highlighted in the docstrings using
Expand Down
78 changes: 49 additions & 29 deletions clojure-ts-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ values like this:
:safe #'booleanp
:type 'boolean)

(defcustom clojure-ts-extra-def-forms nil
"List of forms that should be fontified the same way as defn."
:package-version '(clojure-ts-mode . "0.5")
:safe #'listp
:type '(repeat string))

(defvar clojure-ts-mode-remappings
'((clojure-mode . clojure-ts-mode)
(clojurescript-mode . clojure-ts-clojurescript-mode)
Expand Down Expand Up @@ -468,6 +474,15 @@ if a third argument (the value) is provided.
:anchor (str_lit (str_content) ,capture-symbol) @font-lock-doc-face)
(:match ,clojure-ts-function-docstring-symbols
@_def_symbol))
((list_lit :anchor [(comment) (meta_lit) (old_meta_lit)] :*
:anchor (sym_lit) @_def_symbol
:anchor [(comment) (meta_lit) (old_meta_lit)] :*
;; Function_name
:anchor (sym_lit)
:anchor [(comment) (meta_lit) (old_meta_lit)] :*
:anchor (str_lit (str_content) ,capture-symbol) @font-lock-doc-face)
(:match ,(clojure-ts-symbol-regexp clojure-ts-extra-def-forms)
@_def_symbol))
;; Captures docstrings in defprotcol, definterface
((list_lit :anchor [(comment) (meta_lit) (old_meta_lit)] :*
:anchor (sym_lit) @_def_symbol
Expand Down Expand Up @@ -630,6 +645,12 @@ literals with regex grammar."
"defonce")
eol))
@font-lock-keyword-face))
((list_lit :anchor [(comment) (meta_lit) (old_meta_lit)] :*
:anchor (sym_lit (sym_name) @font-lock-keyword-face)
:anchor [(comment) (meta_lit) (old_meta_lit)] :*
:anchor (sym_lit (sym_name) @font-lock-function-name-face))
(:match ,(clojure-ts-symbol-regexp clojure-ts-extra-def-forms)
@font-lock-keyword-face))
((anon_fn_lit
marker: "#" @font-lock-property-face))
;; Methods implementation
Expand Down Expand Up @@ -1668,25 +1689,33 @@ BOUND bounds the whitespace search."

(defvar clojure-ts--align-query
(treesit-query-compile 'clojure
(append
`(((map_lit) @map)
((ns_map_lit) @ns-map)
((list_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-binding-forms) @sym))
(vec_lit) @bindings-vec))
((list_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-cond-forms) @sym)))
@cond)
((anon_fn_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-binding-forms) @sym))
(vec_lit) @bindings-vec))
((anon_fn_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-cond-forms) @sym)))
@cond)))))
`(((map_lit) @map)
((ns_map_lit) @ns-map)
((list_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-binding-forms) @sym))
(vec_lit) @bindings-vec))
((list_lit
:anchor
((sym_lit) @sym
(:match ,(rx bol (or "for" "doseq") eol) @sym))
(vec_lit
((kwd_lit) @kwd
(:equal ":let" @kwd))
:anchor
(vec_lit) @bindings-vec)))
((list_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-cond-forms) @sym)))
@cond)
((anon_fn_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-binding-forms) @sym))
(vec_lit) @bindings-vec))
((anon_fn_lit
((sym_lit) @sym
(:match ,(clojure-ts-symbol-regexp clojure-ts-align-cond-forms) @sym)))
@cond))))

(defvar clojure-ts--align-reader-conditionals-query
(treesit-query-compile 'clojure
Expand Down Expand Up @@ -2564,12 +2593,6 @@ function can also be used to upgrade the grammars if they are outdated."
(let ((treesit-language-source-alist clojure-ts-grammar-recipes))
(treesit-install-language-grammar grammar)))))

(defsubst clojure-ts--font-lock-setting-update-override (setting)
"Return SETTING with override set to TRUE."
(let ((new-setting (copy-tree setting)))
(setf (nth 3 new-setting) t)
new-setting))

(defun clojure-ts--harvest-treesit-configs (mode)
"Harvest tree-sitter configs from MODE.
Return a plist with the following keys and value:
Expand All @@ -2578,10 +2601,7 @@ Return a plist with the following keys and value:
:simple-indent (from `treesit-simple-indent-rules')"
(with-temp-buffer
(funcall mode)
;; We need to set :override t for all external queries, otherwise new faces
;; won't be applied on top of the string face defined for `clojure-ts-mode'.
(list :font-lock (seq-map #'clojure-ts--font-lock-setting-update-override
treesit-font-lock-settings)
(list :font-lock treesit-font-lock-settings
:simple-indent treesit-simple-indent-rules)))

(defun clojure-ts--add-config-for-mode (mode)
Expand Down
19 changes: 19 additions & 0 deletions test/clojure-ts-mode-font-lock-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,22 @@ DESCRIPTION is the description of the spec."
(set-parameter [m ^PreparedStatement s i]
(.setObject s i (->pgobject m))))"
(81 93 font-lock-function-name-face))))

;;;; Extra def forms

(describe "clojure-ts-extra-def-forms"
(it "should respect the value of clojure-ts-extra-def-forms"
(with-clojure-ts-buffer "(defelem file-upload
\"Creates a file upload input.\"
[name]
(input-field \"file\" name nil))"
(setopt clojure-ts-extra-def-forms '("defelem"))
(clojure-ts-mode)
(font-lock-ensure)
(goto-char (point-min))
(expect (get-text-property 2 'face)
:to-equal 'font-lock-keyword-face)
(expect (get-text-property 10 'face)
:to-equal 'font-lock-function-name-face)
(expect (get-text-property 25 'face)
:to-equal 'font-lock-doc-face))))