@@ -128,6 +128,18 @@ double quotes on the third column."
128
128
:safe #'booleanp
129
129
:package-version '(clojure-ts-mode . " 0.4" ))
130
130
131
+ (defcustom clojure-ts-clojurescript-use-js-parser t
132
+ " When non-nil, use JS grammar to highlight syntax in js* forms."
133
+ :type 'boolean
134
+ :safe #'booleanp
135
+ :package-version '(clojure-ts-mode . " 0.5" ))
136
+
137
+ (defcustom clojure-ts-jank-use-cpp-parser t
138
+ " When non-nil, use C++ grammar to highlight syntax in native/raw forms."
139
+ :type 'boolean
140
+ :safe #'booleanp
141
+ :package-version '(clojure-ts-mode . " 0.5" ))
142
+
131
143
(defcustom clojure-ts-auto-remap t
132
144
" When non-nil, redirect all `clojure-mode' buffers to `clojure-ts-mode' ."
133
145
:safe #'booleanp
@@ -489,6 +501,34 @@ When USE-REGEX is non-nil, include range settings for regex parser."
489
501
:local t
490
502
'((regex_content) @capture)))))
491
503
504
+ (defun clojure-ts--fontify-string (node override _start _end &optional _rest )
505
+ " Fontify string content NODE with `font-lock-string-face' .
506
+
507
+ In order to support embedded syntax highlighting for JS in ClojureScript
508
+ and C++ in Jank we need to avoid fontifying string content in some
509
+ special forms, such as native/raw in Jank and js* in ClojureScript,
510
+ otherwise string face will interfere with embedded parser's faces.
511
+
512
+ This function respects OVERRIDE argument by passing it to
513
+ `treesit-fontify-with-override' .
514
+
515
+ START and END arguments that are passed to this function are not start
516
+ and end of the NODE, so we ignore them."
517
+ (let* ((prev (treesit-node-prev-sibling (treesit-node-parent node)))
518
+ (jank-native-p (and (derived-mode-p 'clojure-ts-jank-mode )
519
+ clojure-ts-jank-use-cpp-parser
520
+ (clojure-ts--symbol-node-p prev)
521
+ (string= (treesit-node-text prev) " native/raw" )))
522
+ (js-interop-p (and (derived-mode-p 'clojure-ts-clojurescript-mode )
523
+ clojure-ts-clojurescript-use-js-parser
524
+ (clojure-ts--symbol-node-p prev)
525
+ (string= (treesit-node-text prev) " js*" ))))
526
+ (when (not (or jank-native-p js-interop-p))
527
+ (treesit-fontify-with-override (treesit-node-start node)
528
+ (treesit-node-end node)
529
+ 'font-lock-string-face
530
+ override))))
531
+
492
532
(defun clojure-ts--font-lock-settings (markdown-available regex-available )
493
533
" Return font lock settings suitable for use in `treesit-font-lock-settings' .
494
534
@@ -501,7 +541,9 @@ literals with regex grammar."
501
541
(treesit-font-lock-rules
502
542
:feature 'string
503
543
:language 'clojure
504
- '((str_lit) @font-lock-string-face
544
+ '((str_lit open: _ @font-lock-string-face
545
+ (str_content) @clojure-ts--fontify-string
546
+ close: _ @font-lock-string-face)
505
547
(regex_lit) @font-lock-regexp-face)
506
548
507
549
:feature 'regex
@@ -1400,7 +1442,6 @@ regexes with anchors matching the beginning and end of the line are
1400
1442
used."
1401
1443
`((clojure
1402
1444
((parent-is " ^source$" ) parent-bol 0 )
1403
- (clojure-ts--match-docstring parent 0 )
1404
1445
; ; Literal Sequences
1405
1446
((parent-is " ^vec_lit$" ) parent 1 ) ; ; https://guide.clojure.style/#bindings-alignment
1406
1447
((parent-is " ^map_lit$" ) parent 1 ) ; ; https://guide.clojure.style/#map-keys-alignment
@@ -1418,7 +1459,12 @@ used."
1418
1459
; ; https://guide.clojure.style/#one-space-indent
1419
1460
((parent-is " ^list_lit$" ) parent 1 )
1420
1461
((parent-is " ^anon_fn_lit$" ) parent 2 )
1421
- (clojure-ts--match-with-metadata parent 0 ))))
1462
+ (clojure-ts--match-with-metadata parent 0 )
1463
+ ; ; This is slow and only matches when point is inside of a docstring and
1464
+ ; ; only when Markdown grammar is disabled. `indent-region' tries to match
1465
+ ; ; all the rules from top to bottom, so order matters here (the slowest
1466
+ ; ; rules should be at the bottom).
1467
+ (clojure-ts--match-docstring parent 0 ))))
1422
1468
1423
1469
(defun clojure-ts--configured-indent-rules ()
1424
1470
" Gets the configured choice of indent rules."
@@ -2518,6 +2564,44 @@ function can also be used to upgrade the grammars if they are outdated."
2518
2564
(let ((treesit-language-source-alist clojure-ts-grammar-recipes))
2519
2565
(treesit-install-language-grammar grammar)))))
2520
2566
2567
+ (defsubst clojure-ts--font-lock-setting-update-override (setting )
2568
+ " Return SETTING with override set to TRUE."
2569
+ (let ((new-setting (copy-tree setting)))
2570
+ (setf (nth 3 new-setting) t )
2571
+ new-setting))
2572
+
2573
+ (defun clojure-ts--harvest-treesit-configs (mode )
2574
+ " Harvest tree-sitter configs from MODE.
2575
+ Return a plist with the following keys and value:
2576
+
2577
+ :font-lock (from `treesit-font-lock-settings' )
2578
+ :simple-indent (from `treesit-simple-indent-rules' )"
2579
+ (with-temp-buffer
2580
+ (funcall mode)
2581
+ ; ; We need to set :override t for all external queries, otherwise new faces
2582
+ ; ; won't be applied on top of the string face defined for `clojure-ts-mode' .
2583
+ (list :font-lock (seq-map #'clojure-ts--font-lock-setting-update-override
2584
+ treesit-font-lock-settings)
2585
+ :simple-indent treesit-simple-indent-rules)))
2586
+
2587
+ (defun clojure-ts--add-config-for-mode (mode )
2588
+ " Add configurations for MODE to current buffer.
2589
+
2590
+ Configuration includes font-lock and indent. For font-lock rules, use
2591
+ the same features enabled in MODE."
2592
+ (let ((configs (clojure-ts--harvest-treesit-configs mode)))
2593
+ (setq treesit-font-lock-settings
2594
+ (append treesit-font-lock-settings
2595
+ (plist-get configs :font-lock )))
2596
+ ; ; FIXME: This works a bit aggressively. `indent-region' always tries to
2597
+ ; ; use rules for embedded parser. Without it users can format embedded code
2598
+ ; ; in an arbitrary way.
2599
+ ; ;
2600
+ ; ; (setq treesit-simple-indent-rules
2601
+ ; ; (append treesit-simple-indent-rules
2602
+ ; ; (plist-get configs :simple-indent)))
2603
+ ))
2604
+
2521
2605
(defun clojure-ts-mode-variables (&optional markdown-available regex-available )
2522
2606
" Initialize buffer-local variables for `clojure-ts-mode' .
2523
2607
@@ -2625,7 +2709,20 @@ REGEX-AVAILABLE."
2625
2709
(define-derived-mode clojure-ts-clojurescript-mode clojure-ts-mode " ClojureScript[TS]"
2626
2710
" Major mode for editing ClojureScript code.
2627
2711
2628
- \\ {clojure-ts-clojurescript-mode-map}" )
2712
+ \\ {clojure-ts-clojurescript-mode-map}"
2713
+ (when (and clojure-ts-clojurescript-use-js-parser
2714
+ (treesit-ready-p 'javascript t ))
2715
+ (setq-local treesit-range-settings
2716
+ (append treesit-range-settings
2717
+ (treesit-range-rules
2718
+ :embed 'javascript
2719
+ :host 'clojure
2720
+ :local t
2721
+ '(((list_lit (sym_lit) @_sym-name
2722
+ :anchor (str_lit (str_content) @capture))
2723
+ (:equal @_sym-name " js*" ))))))
2724
+ (clojure-ts--add-config-for-mode 'js-ts-mode )
2725
+ (treesit-major-mode-setup)))
2629
2726
2630
2727
;;;### autoload
2631
2728
(define-derived-mode clojure-ts-clojurec-mode clojure-ts-mode " ClojureC[TS]"
@@ -2643,7 +2740,20 @@ REGEX-AVAILABLE."
2643
2740
(define-derived-mode clojure-ts-jank-mode clojure-ts-mode " Jank[TS]"
2644
2741
" Major mode for editing Jank code.
2645
2742
2646
- \\ {clojure-ts-jank-mode-map}" )
2743
+ \\ {clojure-ts-jank-mode-map}"
2744
+ (when (and clojure-ts-jank-use-cpp-parser
2745
+ (treesit-ready-p 'cpp t ))
2746
+ (setq-local treesit-range-settings
2747
+ (append treesit-range-settings
2748
+ (treesit-range-rules
2749
+ :embed 'cpp
2750
+ :host 'clojure
2751
+ :local t
2752
+ '(((list_lit (sym_lit) @_sym-name
2753
+ :anchor (str_lit (str_content) @capture))
2754
+ (:equal @_sym-name " native/raw" ))))))
2755
+ (clojure-ts--add-config-for-mode 'c++-ts-mode )
2756
+ (treesit-major-mode-setup)))
2647
2757
2648
2758
(defun clojure-ts--register-novel-modes ()
2649
2759
" Set up Clojure modes not present in progenitor clojure-mode.el."
0 commit comments