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))