branch: elpa/typst-ts-mode
commit f43cba2548b21606551c60841d9c2060a1beedd7
Author: Meow King <mr.meowk...@anche.no>
Commit: Meow King <mr.meowk...@anche.no>

    feat: capable to correctly highlight regions
---
 typst-ts-embedding-lang-settings.el | 151 +++++++++++++++++++++++++-----------
 typst-ts-mode.el                    |  53 +++++++------
 2 files changed, 135 insertions(+), 69 deletions(-)

diff --git a/typst-ts-embedding-lang-settings.el 
b/typst-ts-embedding-lang-settings.el
index 3c6cbf4288..df12774fb8 100644
--- a/typst-ts-embedding-lang-settings.el
+++ b/typst-ts-embedding-lang-settings.el
@@ -17,13 +17,22 @@
 
 ;;; Commentary:
 
-;; This file contains settings for tree sitter languages.
-;; to test settings:
-;; emacs --batch -l ./typst-ts-embedding-lang-settings.el --eval 
"(typst-ts-embedding-lang-settings-test)"
+;; Functionality to embed other languages in typst documentation.
 
 ;;; Code:
 (require 'treesit)
 
+(defcustom typst-ts-enable-predefined-settings t
+  "Whether to use predefined embedding language settings.
+Use predefined settings will speed up the process of merging tree sitter
+language mode settings.  However, settings (especially feature list)
+may vary with different versions of a language mode, so you may get wrong
+settings.
+If you enable this feature, we highly recommend you to customize it when
+error occurs."
+  :type 'boolean
+  :group 'typst-ts)
+
 (defcustom typst-ts-highlight-raw-block-langs-not-in-settings nil
   "Whether to highlight raw block of language that is not in settings.
 The cost for setting up these languages is usually higher than those
@@ -31,6 +40,8 @@ languages in settings."
   :type 'boolean
   :group 'typst-ts)
 
+;; to test settings:
+;; emacs --batch -l ./typst-ts-embedding-lang-settings.el --eval 
"(typst-ts-embedding-lang-settings-test)"
 (defvar typst-ts-embedding-lang-settings
   '((python . (:feature
                python
@@ -51,7 +62,17 @@ languages in settings."
                ( keyword string)
                ( assignment attribute builtin constant escape-sequence
                  number type)
-               ( bracket delimiter error function operator property 
variable)))))
+               ( bracket delimiter error function operator property 
variable))))
+    (bash . (:feature
+             sh-script
+             :font-lock sh-mode--treesit-settings
+             :indentation nil
+             :ts-feature-list
+             '(( comment function)
+               ( command declaration-command keyword string)
+               ( builtin-variable constant heredoc number
+                 string-interpolation variable)
+               ( bracket delimiter misc-punctuation operator)))))
   "Settings for raw block languages.")
 
 
@@ -82,13 +103,34 @@ languages in settings."
                                      treesit-font-lock-feature-list
                                      ts-feature-list))))
 
-(defun typst-ts-els-merge-lang (lang)
+(defun typst-ts-els-merge-lang-settings (lang)
   "Merge embedding language LANG settings."
   (let ((settings (alist-get lang typst-ts-embedding-lang-settings)))
     (if settings
         (typst-ts-els-merge-settings settings)
       (error "Language %s not in settings" lang))))
 
+(defun typst-ts-els--treesit-range-rules (lang)
+  "Get the treesit range rules for LANG.
+LANG: language symbol."
+  (treesit-range-rules
+   :embed lang
+   :host 'typst
+   :local t
+   `((raw_blck
+      lang: (_) @_lang
+      (blob) @capture
+      (:equal @_lang ,(symbol-name lang))))))
+
+(defun typst-ts-els--add-treesit-range-rules (lang)
+  "Add treesit range rule for LANG.
+LANG: language symbol."
+  (setq
+   treesit-range-settings
+   (nconc
+    treesit-range-settings
+    (typst-ts-els--treesit-range-rules lang))))
+
 (defun typst-ts-els--try-get-ts-settings (mode)
   (with-temp-buffer
     (setq-local delay-mode-hooks t)  ; don't run hooks associated with MODE
@@ -108,46 +150,67 @@ languages in settings."
 (defun typst-ts-els-include-dynamically (_ranges _parser)
   "Include language setting dynamically.
 Use this function as one notifier of `treesit-parser-notifiers'."
-  (let ((parser-langs (mapcar #'treesit-parser-language (treesit-parser-list)))
+  ;; `treesit-language-at-point-function' will ensure that the
+  ;; languages in `treesit-parser-list' are valid (not just a random string)
+  (let ((parser-langs
+         (delete-dups
+          (append
+           ;; parsers created by `treesit-language-at-point-function'
+           ;; i.e. parsers cannot be created by `treesit-range-settings'
+           (mapcar #'treesit-parser-language (treesit-parser-list))
+           ;; parsers created by `treesit-range-settings'
+           (mapcar #'treesit-parser-language
+                   (treesit-local-parsers-on (point-min) (point-max))))))
         lang-ts-mode settings)
-    (unless (eq (length parser-langs) (length typst-ts-els--include-languages))
-      (dolist (lang parser-langs)
-        (unless (member lang typst-ts-els--include-languages)
-          (unwind-protect
-              (condition-case _err
-                  ;; first try loading settings from configuration
-                  (progn
-                    (typst-ts-els-merge-lang lang)
-                    (message "Load %s language settings from configuration." 
lang))
-                (error
-                 ;; if language not in setting or encounter error during 
loading,
-                 ;; then try your luck to load it
-                 (condition-case err
-                     (progn
-                       (setq lang-ts-mode
-                             (intern (concat (symbol-name lang) "-ts-mode")))
-                       (setq settings
-                             (typst-ts-els--try-get-ts-settings lang-ts-mode))
-
-                       (setq treesit-font-lock-settings
-                             (append treesit-font-lock-settings
-                                     (plist-get settings 
:treesit-font-lock-settings)))
-
-                       (setq treesit-simple-indent-rules
-                             (append treesit-simple-indent-rules
-                                     (plist-get settings 
:treesit-simple-indent-rules)))
-
-                       (setq treesit-font-lock-feature-list
-                             (typst-ts-els--merge-features
-                              treesit-font-lock-feature-list
-                              (plist-get settings 
:treesit-font-lock-feature-list)))
-                       (message "Getting %s language settings luckily 
succeeded." lang))
-                   (error
-                    (message "Highlighting raw block error: \n%s"
-                             (error-message-string err))))))
-            ;; whatever, we won't load that language again
-            (add-to-list 'typst-ts-els--include-languages lang))
-          )))))
+    (dolist (lang parser-langs)
+      (unless (member lang typst-ts-els--include-languages)
+        (unwind-protect
+            (condition-case _err
+                ;; first try loading settings from configuration
+                (progn
+                  (unless typst-ts-enable-predefined-settings
+                    (error "User don't allow to load predefined settings"))
+                  ;; note: the `treesit-range-settings' for languages in
+                  ;; predefined settings are already settled at mode start
+                  (typst-ts-els-merge-lang-settings lang)
+                  (message "Load %s language settings from configuration." 
lang))
+              (error
+               ;; if language not in setting or encounter error during loading,
+               ;; then try your luck to load it
+               (condition-case err
+                   (progn
+                     ;; add range rules
+                     (typst-ts-els--add-treesit-range-rules lang)
+                     ;; delete top level parsers, so range rules works (i.e. 
local parsers)
+                     ;; so that highlighting will not exceed the desired range
+                     (mapc #'treesit-parser-delete (treesit-parser-list nil 
lang))
+
+                     ;; find and merge settings
+                     (setq lang-ts-mode
+                           (intern (concat (symbol-name lang) "-ts-mode")))
+                     (setq settings
+                           (typst-ts-els--try-get-ts-settings lang-ts-mode))
+
+                     (setq treesit-font-lock-settings
+                           (append treesit-font-lock-settings
+                                   (plist-get settings 
:treesit-font-lock-settings)))
+
+                     (setq treesit-simple-indent-rules
+                           (append treesit-simple-indent-rules
+                                   (plist-get settings 
:treesit-simple-indent-rules)))
+
+                     (setq treesit-font-lock-feature-list
+                           (typst-ts-els--merge-features
+                            treesit-font-lock-feature-list
+                            (plist-get settings 
:treesit-font-lock-feature-list)))
+                     (message "Luckily merged %s language settings." lang))
+                 (error
+                  (message "Loading %s language settings without luck: \n%s"
+                           lang
+                           (error-message-string err))))))
+          ;; whatever, we won't load that language again
+          (add-to-list 'typst-ts-els--include-languages lang))
+        ))))
 
 (defun typst-ts-embedding-lang-settings-test ()
   "Test typst-ts-embedding-lang-settings."
diff --git a/typst-ts-mode.el b/typst-ts-mode.el
index 88a8852094..8715c38067 100644
--- a/typst-ts-mode.el
+++ b/typst-ts-mode.el
@@ -27,6 +27,12 @@
 
 ;; Tree Sitter Support for Typst
 
+;; TODO
+;; 1. search all other TODOS
+;; 2. enable highlighting raw block at startup
+;; 3. rememeber git commit --amend instead directly
+;; 4. add more predefined configurations
+
 ;;; Code:
 
 (require 'treesit)
@@ -51,6 +57,16 @@
   :type 'integer
   :group 'typst-ts)
 
+;;; TODO
+(defcustom typst-ts-mode-highlight-raw-blocks-at-startup nil
+  "Whether to highlight raw blocks at *mode startup*.
+Note: this may take some time for documents with lot of raw blocks."
+  :type '(choice (const :tag "don't highlight at all." nil)
+                 (const :tag "highlight all." t)
+                 (const :tag "only highlight pre-configured languages.
+you need `typst-ts-enable-predefined-settings' to be `t' too." defined))
+  :group 'typst-ts)
+
 (defcustom typst-ts-mode-executable-location "typst"
   "The location or name(if in variable `exec-path') for Typst executable."
   :type 'string
@@ -981,14 +997,7 @@ See `treesit-language-at-point-function'."
   (cl-loop for lang in langs
            when (treesit-ready-p lang)
            nconc
-           (treesit-range-rules
-            :host 'typst
-            :embed lang
-            :local t
-            `((raw_blck
-               lang: (_) @_lang
-               (blob) @capture
-               (:equal @_lang ,(symbol-name lang)))))))
+           (typst-ts-els--treesit-range-rules lang)))
 
 ;;;###autoload
 (define-derived-mode typst-ts-mode text-mode "Typst"
@@ -999,13 +1008,11 @@ See `treesit-language-at-point-function'."
   (unless (treesit-ready-p 'typst)
     (error "Tree-sitter for Typst isn't available"))
 
-  (treesit-parser-create 'typst)
-  
-  ;; (let ((parser (treesit-parser-create 'typst)))
-  ;;   (when typst-ts-mode-highlight-raw-block
-  ;;     (treesit-parser-add-notifier
-  ;;      parser
-  ;;      'typst-ts-els-include-dynamically)))
+  (let ((parser (treesit-parser-create 'typst)))
+    (when typst-ts-mode-highlight-raw-block
+      (treesit-parser-add-notifier
+       parser
+       'typst-ts-els-include-dynamically)))
 
   ;; Comments.
   (typst-ts-mode-comment-setup)
@@ -1043,16 +1050,9 @@ See `treesit-language-at-point-function'."
   
   (setq-local treesit-language-at-point-function
               'typst-ts-mode--language-at-point)
-  ;; (setq-local treesit-range-settings
-  ;;             (typst-ts-mode--treesit-range-rules '(python rust)))
-  ;; (setq-local treesit-range-settings
-  ;;             (treesit-range-rules
-  ;;              :host 'typst
-  ;;              :embed 'rust
-  ;;              ;; :local t
-  ;;              '((raw_blck
-  ;;                 ;; lang: (_)
-  ;;                 (blob) @capture))))
+  (setq-local treesit-range-settings
+              (typst-ts-mode--treesit-range-rules
+               (append (mapcar #'car typst-ts-embedding-lang-settings) 
'(typst))))
 
   ;; Outline
   (setq-local outline-regexp typst-ts-mode-outline-regexp)
@@ -1061,6 +1061,9 @@ See `treesit-language-at-point-function'."
   ;; Although without enabling `outline-minor-mode' also works, enabling it
   ;; provides outline ellipsis
   (outline-minor-mode t)
+
+  ;; TODO
+  ;; (typst-ts-els-include-dynamically nil nil)
   
   (treesit-major-mode-setup))
 

Reply via email to