Subject: Re: bug#65470: 29.1.50; js-ts-mode: regex pattern can cause incorrect parenthesis matching

From: Dmitry Gutov <[email-masked]>
Date: Sat, 26 Aug 2023 04:52:35 +0300

Hi Augustin!

On 25/08/2023 10:17, Augustin Chéneau (BTuin) wrote:
> Thanks for the patch, but I still have some issues. I believe that the
> START and END arguments of `put-text-property` are off by one. The
> attached modified patch seems to work better.

Thanks for trying it out. Sorry about missing your first patch: 
apparently while it was the first time-wise, it was help up in moderation.

Anyway, you make a good point about the case with the regexp: since I 
matched the pattern inside, the bounds of the node are off by one 
compared to the case with the jsx node. Your patch moves those bounds, 
but then they'll be wrong for the latter case.

Here's an update which tries to handle both, but I guess if we add more 
node types later we'll just have to stop trying to handle them the same 
way (and do it closer to ruby-ts--syntax-propertize).

Also added the new return_statement case for jsx.

diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 9d2990e7bc9..9b6da4ec2fc 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3829,6 +3829,7 @@ js-ts-mode
                 (append "{}():;,<>/" electric-indent-chars)) ;FIXME: js2-mode adds "[]*".
     (setq-local electric-layout-rules
 	        '((?\; . after) (?\{ . after) (?\} . before)))
+    (setq-local syntax-propertize-function #'js-ts--syntax-propertize)
 
     ;; Tree-sitter setup.
     (treesit-parser-create 'javascript)
@@ -3864,6 +3865,29 @@ js-ts-mode
     (add-to-list 'auto-mode-alist
                  '("\\(\\.js[mx]\\|\\.har\\)\\'" . js-ts-mode))))
 
+(defvar js-ts--s-p-query
+  (when (treesit-available-p)
+    (treesit-query-compile 'javascript
+                           '(((regex pattern: (regex_pattern) @regexp))
+                             ((variable_declarator value: (jsx_element) @jsx))
+                             ((assignment_expression right: (jsx_element) @jsx))
+                             ((return_statement (jsx_element) @jsx))))))
+
+(defun js-ts--syntax-propertize (beg end)
+  (let ((captures (treesit-query-capture 'javascript js-ts--s-p-query beg end)))
+    (pcase-dolist (`(,name . ,node) captures)
+      (let* ((ns (treesit-node-start node))
+             (ne (treesit-node-end node))
+             (syntax (pcase-exhaustive name
+                       ('regexp
+                        (cl-decf ns)
+                        (cl-incf ne)
+                        (string-to-syntax "\"/"))
+                       ('jsx
+                        (string-to-syntax "|")))))
+        (put-text-property ns (1+ ns) 'syntax-table syntax)
+        (put-text-property (1- ne) ne 'syntax-table syntax)))))
+
 ;;;###autoload
 (define-derived-mode js-json-mode js-mode "JSON"
   (setq-local js-enabled-frameworks nil)