branch: elpa/clojure-ts-mode
commit 605adba8babdc82013cd9a9a9f15a8f3ae587e64
Author: Roman Rudakov <rruda...@fastmail.com>
Commit: Bozhidar Batsov <bozhi...@batsov.dev>

    [#11] Add regex syntax highlighting
---
 CHANGELOG.md                               |   1 +
 README.md                                  |  19 ++++-
 clojure-ts-mode.el                         | 107 ++++++++++++++++++++++++-----
 screenshots/markdown-syntax-dark-theme.png | Bin 0 -> 59689 bytes
 screenshots/regex-syntax-dark-theme.png    | Bin 0 -> 50440 bytes
 test/samples/regex.clj                     |   7 ++
 6 files changed, 115 insertions(+), 19 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41e2a140b1..8c11acd343 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ## main (unreleased)
 
 - [#16](https://github.com/clojure-emacs/clojure-ts-mode/issues/16): Introduce 
`clojure-ts-align`.
+- [#11](https://github.com/clojure-emacs/clojure-ts-mode/issues/11): Enable 
regex syntax highlighting.
 
 ## 0.3.0 (2025-04-15)
 
diff --git a/README.md b/README.md
index f44f5839c1..0c96c55c8e 100644
--- a/README.md
+++ b/README.md
@@ -293,12 +293,29 @@ highlighted like regular clojure code.
 ### Highlight markdown syntax in docstrings
 
 By default markdown syntax is highlighted in the docstrings using
-`markdown_inline` grammar. To disable this feature set
+`markdown-inline` grammar. To disable this feature set
 
 ``` emacs-lisp
 (setopt clojure-ts-use-markdown-inline nil)
 ```
 
+Example of syntax highlighting:
+
+<img width="512" src="/screenshots/markdown-syntax-dark-theme.png">
+
+### Highlight regex syntax
+
+By default syntax inside regex literals is highlighted using 
[regex](https://github.com/tree-sitter/tree-sitter-regex) grammar. To
+disable this feature set
+
+```emacs-lisp
+(setopt clojure-ts-use-regex-parser nil)
+```
+
+Example of syntax highlighting:
+
+<img width="512" src="/screenshots/regex-syntax-dark-theme.png">
+
 ### Navigation and Evaluation
 
 To make forms inside of `(comment ...)` forms appear as top-level forms for 
evaluation and navigation, set
diff --git a/clojure-ts-mode.el b/clojure-ts-mode.el
index 7c16c01785..f88f342158 100644
--- a/clojure-ts-mode.el
+++ b/clojure-ts-mode.el
@@ -121,6 +121,12 @@ double quotes on the third column."
   :safe #'booleanp
   :package-version '(clojure-ts-mode . "0.2.3"))
 
+(defcustom clojure-ts-use-regex-parser t
+  "When non-nil, use separate grammar to highlight regex syntax."
+  :type 'boolean
+  :safe #'booleanp
+  :package-version '(clojure-ts-mode . "0.4"))
+
 (defcustom clojure-ts-auto-remap t
   "When non-nil, redirect all `clojure-mode' buffers to `clojure-ts-mode'."
   :safe #'booleanp
@@ -407,17 +413,37 @@ if a third argument (the value) is provided.
                :*)
      (:match ,clojure-ts--interface-def-symbol-regexp @_def_symbol))))
 
-(defvar clojure-ts--treesit-range-settings
-  (treesit-range-rules
-   :embed 'markdown-inline
-   :host 'clojure
-   :local t
-   (clojure-ts--docstring-query '@capture)))
+(defun clojure-ts--treesit-range-settings (use-markdown-inline use-regex)
+  "Return value for `treesit-range-settings' for `clojure-ts-mode'.
 
-(defun clojure-ts--font-lock-settings (markdown-available)
+When USE-MARKDOWN-INLINE is non-nil, include range settings for
+markdown-inline parser.
+
+When USE-REGEX is non-nil, include range settings for regex parser."
+  (append
+   (when use-markdown-inline
+     (treesit-range-rules
+      :embed 'markdown-inline
+      :host 'clojure
+      :offset '(1 . -1)
+      :local t
+      (clojure-ts--docstring-query '@capture)))
+   (when use-regex
+     (treesit-range-rules
+      :embed 'regex
+      :host 'clojure
+      :offset '(2 . -1)
+      :local t
+      '((regex_lit) @capture)))))
+
+(defun clojure-ts--font-lock-settings (markdown-available regex-available)
   "Return font lock settings suitable for use in `treesit-font-lock-settings'.
+
 When MARKDOWN-AVAILABLE is non-nil, includes rules for highlighting docstrings
-with the markdown-inline grammar."
+with the markdown-inline grammar.
+
+When REGEX-AVAILABLE is non-nil, includes rules for highlighting regex
+literals with regex grammar."
   (append
    (treesit-font-lock-rules
     :feature 'string
@@ -590,6 +616,44 @@ with the markdown-inline grammar."
          (inline_link (link_destination) @font-lock-constant-face)
          (shortcut_link (link_text) @link)])))
 
+   (when regex-available
+     ;; Queries are adapted from
+     ;; 
https://github.com/tree-sitter/tree-sitter-regex/blob/v0.24.3/queries/highlights.scm.
+     (treesit-font-lock-rules
+      :feature 'regex
+      :language 'regex
+      :override t
+      '((["("
+           ")"
+           "(?"
+           "(?:"
+           "(?<"
+           "(?P<"
+           "(?P="
+           ">"
+           "["
+           "]"
+           "{"
+           "}"
+           "[:"
+           ":]"] @font-lock-regexp-grouping-construct)
+         (["*"
+           "+"
+           "?"
+           "|"
+           "="
+           "!"] @font-lock-property-name-face)
+         ((group_name) @font-lock-variable-name-face)
+         ((count_quantifier
+           [(decimal_digits) @font-lock-number-face
+            "," @font-lock-delimiter-face]))
+         ((flags) @font-lock-constant-face)
+         ((character_class
+           ["^" @font-lock-escape-face
+            (class_range "-" @font-lock-escape-face)]))
+         ((identity_escape) @font-lock-builtin-face)
+         ([(start_assertion) (end_assertion)] @font-lock-constant-face))))
+
    (treesit-font-lock-rules
     :feature 'quote
     :language 'clojure
@@ -1555,7 +1619,9 @@ between BEG and END."
              "v0.0.13")
     (markdown-inline "https://github.com/MDeiml/tree-sitter-markdown";
                      "v0.4.1"
-                     "tree-sitter-markdown-inline/src"))
+                     "tree-sitter-markdown-inline/src")
+    (regex "https://github.com/tree-sitter/tree-sitter-regex";
+           "v0.24.3"))
   "Intended to be used as the value for `treesit-language-source-alist'.")
 
 (defun clojure-ts--ensure-grammars ()
@@ -1584,20 +1650,22 @@ 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)))))
 
-(defun clojure-ts-mode-variables (&optional markdown-available)
+(defun clojure-ts-mode-variables (&optional markdown-available regex-available)
   "Initialize buffer-local variables for `clojure-ts-mode'.
-See `clojure-ts--font-lock-settings' for usage of MARKDOWN-AVAILABLE."
+
+See `clojure-ts--font-lock-settings' for usage of MARKDOWN-AVAILABLE and
+REGEX-AVAILABLE."
   (setq-local indent-tabs-mode nil)
   (setq-local comment-add 1)
   (setq-local comment-start ";")
 
   (setq-local treesit-font-lock-settings
-              (clojure-ts--font-lock-settings markdown-available))
+              (clojure-ts--font-lock-settings markdown-available 
regex-available))
   (setq-local treesit-font-lock-feature-list
               '((comment definition variable)
                 (keyword string char symbol builtin type)
-                (constant number quote metadata doc)
-                (bracket deref function regex tagged-literals)))
+                (constant number quote metadata doc regex)
+                (bracket deref function tagged-literals)))
 
   (setq-local treesit-defun-prefer-top-level t)
   (setq-local treesit-defun-tactic 'top-level)
@@ -1630,13 +1698,16 @@ See `clojure-ts--font-lock-settings' for usage of 
MARKDOWN-AVAILABLE."
   :syntax-table clojure-ts-mode-syntax-table
   (clojure-ts--ensure-grammars)
   (let ((use-markdown-inline (and clojure-ts-use-markdown-inline
-                                  (treesit-ready-p 'markdown-inline t))))
-    (when use-markdown-inline
-      (setq-local treesit-range-settings clojure-ts--treesit-range-settings))
+                                  (treesit-ready-p 'markdown-inline t)))
+        (use-regex (and clojure-ts-use-regex-parser
+                        (treesit-ready-p 'regex t))))
+    (setq-local treesit-range-settings
+                (clojure-ts--treesit-range-settings use-markdown-inline
+                                                    use-regex))
 
     (when (treesit-ready-p 'clojure)
       (treesit-parser-create 'clojure)
-      (clojure-ts-mode-variables use-markdown-inline)
+      (clojure-ts-mode-variables use-markdown-inline use-regex)
 
       (when clojure-ts--debug
         (setq-local treesit--indent-verbose t)
diff --git a/screenshots/markdown-syntax-dark-theme.png 
b/screenshots/markdown-syntax-dark-theme.png
new file mode 100644
index 0000000000..7a908acb90
Binary files /dev/null and b/screenshots/markdown-syntax-dark-theme.png differ
diff --git a/screenshots/regex-syntax-dark-theme.png 
b/screenshots/regex-syntax-dark-theme.png
new file mode 100644
index 0000000000..ad7ee45dd7
Binary files /dev/null and b/screenshots/regex-syntax-dark-theme.png differ
diff --git a/test/samples/regex.clj b/test/samples/regex.clj
new file mode 100644
index 0000000000..f37b50a35e
--- /dev/null
+++ b/test/samples/regex.clj
@@ -0,0 +1,7 @@
+(ns regex)
+
+(def email-pattern
+  
#"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
+
+(def simple-regex
+  #"^(\\d+).*[a|b|c|d].*[a-z0-9!#]$")

Reply via email to