branch: elpa/typst-ts-mode commit 7e3f11e675a5c13323f0a64aa7cd3057277a854a Author: Meow King <mr.meowk...@anche.no> Commit: Meow King <mr.meowk...@anche.no>
feat: add detailed documentation --- README.md | 8 ++ ...block-highlighting-mechanism-explain-0.plantuml | 52 +++++++++ .../raw-block-highlighting-mechanism-explain-0.png | Bin 0 -> 76229 bytes ...block-highlighting-mechanism-explain-1.plantuml | 64 +++++++++++ .../raw-block-highlighting-mechanism-explain-1.png | Bin 0 -> 113446 bytes doc/raw-block-highlighing.md | 66 +++++++++++ typst-ts-embedding-lang-settings.el | 126 +++++++++++---------- typst-ts-mode.el | 21 +--- 8 files changed, 256 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index de3ac6f60a..5f6ae564eb 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,14 @@ because Typst itself do this style. You may find `auto-save-visited-mode`, 6. `typst-ts-markup-header-same-height` and `typst-ts-markup-header-scale` to control header height. 7. `typst-ts-mode-before-compile-hook` and `typst-ts-mode-after-compile-hook` +### Raw block highlighting + +For more detailed documentation about raw block highlighting see +[this documentation](./doc/raw-block-highlighing.md) +1. `typst-ts-mode-enable-raw-blocks-highlight` (default `t`) +2. `typst-ts-mode-highlight-raw-blocks-at-startup` (default `t`) +3. `typst-ts-highlight-raw-block-langs-not-in-predefined-settings` (default `t`) + ### Consult Imenu Integration If you use `consult-iemnu` command [consult](https://github.com/minad/consult), you way want this setting. diff --git a/assets/raw-block-highlighting-mechanism-explain-0.plantuml b/assets/raw-block-highlighting-mechanism-explain-0.plantuml new file mode 100644 index 0000000000..4ab4c34b6a --- /dev/null +++ b/assets/raw-block-highlighting-mechanism-explain-0.plantuml @@ -0,0 +1,52 @@ +@startuml +start +floating note +<color:purple>purple</color>: built-in functions / variables +<color:blue>blue</color>: typst-ts-mode functions / variable +<color:red>red</color>: typst-ts-mode raw block configuration variables +end note + +partition customization { + :<color:blue>typst-ts-els-lang-tags-map</color>: used in <color:purple>treesit-language-at-point-function</color> + <color:blue>typst-ts-els-tag-lang-map</color>: used in <color:purple>treesit-range-settings</color> + <color:blue>typst-ts-embedding-lang-settings</color>; + + note right + use function <color:blue>typst-ts-els--add-lang-tags-relationship</color> and + function <color:blue>typst-ts-els--lang-name-remap</color> to change variables + <color:blue>typst-ts-els-lang-tags-map</color> and <color:blue>typst-ts-els-tag-lang-map</color> + ==== + use <color:purple>shortdoc</color> to search for <color:purple>alist</color> related + functions to modifiy <color:blue>typst-ts-embedding-lang-settings</color> + end note +} + +partition mode initialization { + :create typst tree sitter parser; + + if (<color:red> typst-ts-mode-enable-raw-blocks-highlight</color>) is (t) then + :add <color:blue>typst-ts-els-include-dynamically</color> function to + parser notification functions list; + + note right + so <color:blue>typst-ts-els-include-dynamically</color> will receive buffer + change notification + end note + + :set <color:purple>treesit-language-at-point-function</color> and <color:purple>treesit-range-settings</color>; + + note right + They are used to create tree sitter parsers. Moreover, + <color:purple>treesit-range-settings</color> defined which area these parser + will act on. + end note + + :run hooks (functions added in <color:purple>typst-ts-mode-hook</color>); + + if (<color:red> typst-ts-mode-highlight-raw-blocks-at-startup) is (t) then + :load and merge predefined settings from variable + <color:blue>typst-ts-embedding-lang-settings</color>; + endif + endif +} +@enduml diff --git a/assets/raw-block-highlighting-mechanism-explain-0.png b/assets/raw-block-highlighting-mechanism-explain-0.png new file mode 100644 index 0000000000..e87d0533ad Binary files /dev/null and b/assets/raw-block-highlighting-mechanism-explain-0.png differ diff --git a/assets/raw-block-highlighting-mechanism-explain-1.plantuml b/assets/raw-block-highlighting-mechanism-explain-1.plantuml new file mode 100644 index 0000000000..67fee33a8b --- /dev/null +++ b/assets/raw-block-highlighting-mechanism-explain-1.plantuml @@ -0,0 +1,64 @@ +@startuml + +floating note +<color:purple>purple</color>: built-in functions / variables +<color:blue>blue</color>: typst-ts-mode functions / variable +<color:red>red</color>: typst-ts-mode raw block configuration variables +end note + +partition editing { + if (<color:red> typst-ts-mode-enable-raw-blocks-highlight</color>) is (t) then + fork + partition function: <color:purple>treesit-language-at-point-function</color> { + floating note: i.e. <color:blue>typst-ts-mode--language-at-point</color> + :raw block tag (**ignore case**) will be converted to tree sitter + language symbol via <color:blue>typst-ts-els-tag-lang-map</color>; + if (langauge symbol in map) is (nil) then + :use language symbol **typst**; + endif + } + + if (language symbol **not** in <color:red>treesit-range-settings</color> + and dynamic library file for language is loaded) then + :treesit will create a toplevel parser of that language; + note left + which is what we don't want, since it will mess the foncication + (i.e. highlight area outside the raw block) + we will delete it later + end note + endif + + fork again + partition <color:purple>treesit-range-settings</color> { + :create local parsers (parse specific areas) according to + <color:purple>treesit-range-settings</color> (which defines queries for + finding area, and specifys parser language for that area); + } + end fork + + partition function: <color:blue>typst-ts-els-include-dynamically</color> { + note + this function is called when buffer changes. + see <color:red>treesit-parser-add-notifier</color> + end note + + :get all parsers (including toplevel, local); + + while (parser in parsers) + if (the language of the parser haven't been marked loaded) then + if (try load settings via <color:blue>typst-ts-embedding-lang-settings</color>) is (not success) then + if (<color:red>typst-ts-highlight-raw-block-langs-not-in-predefined-settings</color>) is (t) then + :guess the corresponding tree sitter major mode of the language; + :create a temporary buffer with hooks disabled; + :load settings from local variables; + endif + endif + :mark the language as loaded; + endif + endwhile + } + endif +} + +end +@enduml diff --git a/assets/raw-block-highlighting-mechanism-explain-1.png b/assets/raw-block-highlighting-mechanism-explain-1.png new file mode 100644 index 0000000000..e85526cc29 Binary files /dev/null and b/assets/raw-block-highlighting-mechanism-explain-1.png differ diff --git a/doc/raw-block-highlighing.md b/doc/raw-block-highlighing.md new file mode 100644 index 0000000000..d9ba736fc5 --- /dev/null +++ b/doc/raw-block-highlighing.md @@ -0,0 +1,66 @@ +# Raw Block Highlighting + +## Customization Option +1. `typst-ts-mode-enable-raw-blocks-highlight` +2. `typst-ts-mode-highlight-raw-blocks-at-startup` +Due to the lazy fontification feature of `treesit`, raw blocks won't be +highlighted at the startup by default. Set it to `t` to enable this feature. +3. `typst-ts-highlight-raw-block-langs-not-in-predefined-settings` + +## Mechanism + + + + +## Customize +1. add/modify raw block language tags/language relationship. + for example + ~~~typst + ```newtag + ``` + ~~~ + -> customize `typst-ts-els-lang-tags-map` and `typst-ts-els-tag-lang-map` + -> use `typst-ts-els--add-lang-tags-relationship` helper function. +2. remap existing raw block language to new raw block language + like `c++` -> `cpp` + -> customize `typst-ts-els-lang-tags-map` and `typst-ts-els-tag-lang-map` + -> use `typst-ts-els--lang-name-remap` helper function. + +3. add new pre-configured language settings + -> customsize `typst-ts-embedding-lang-settings` + -> use `shortdoc` command to search for `alist` related functions to modify it + -> use `typst-ts-embedding-lang-settings-test` function to test your configuration. + settings specification: see `typst-ts-embedding-lang-settings`. + explain: + 1. key: language name: which is the name specified in your tree sitter dynamic library. Or you can find it by: + 1. go to the `<xxx>-ts-mode` major mode function + 2. find `(treesit-parser-create 'cpp)`. So `cpp` is the language name, instead + of the `c++` + 2. `:feature`: the source file name without extension of the `<xxx>-ts-mode`. Or + you can find it in variable `features` + 3. `:font-lock`: go to the source file, find `treesit-font-lock-settings` + 4. `:indentation`: go to the source file, find `treesit-simple-indent-rules` + 5. `:ts-feature-list`: go to the source file, find `treesit-font-lock-feature-list` + +## Current Limitations + +1. update raw block language will not delete the old local parser + -> this will cause error of raw block raw block highlighting. + -> you need to delete the whole raw block to remove the local parser + -> this is due to the behavior of `treesit--update-ranges-local` + -> currently haven't thought out good way to handle it + +2. typst raw block cannot live in typst raw block +For example: +~~~typst +```typ += a // highlight currectly +```typ += b // cannot highlight +``` +``` +~~~ +This is probably due to the Typst tree sitter parser. + +3. Although we also load the indentation configurations, many language in raw block +still cannot do indentation. Some languages like `rust`(`rust-ts-mode`) works. diff --git a/typst-ts-embedding-lang-settings.el b/typst-ts-embedding-lang-settings.el index b69d2ff3e1..e2cef65afa 100644 --- a/typst-ts-embedding-lang-settings.el +++ b/typst-ts-embedding-lang-settings.el @@ -26,17 +26,6 @@ ;;; 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-predefined-settings t "Whether to highlight raw block of language that is not in settings. i.e. not in `typst-ts-embedding-lang-settings'. @@ -225,7 +214,10 @@ languages in settings." zig ("zig" ) )) - "Tree sitter language -> Raw block tags map.") + "Tree sitter language -> Raw block tags map. +Associated map: `typst-ts-els-tag-lang-map'. +Please use function `typst-ts-els--add-treesit-range-rules' and +`typst-ts-els--lang-name-remap' to modify them.") (defvar typst-ts-els-tag-lang-map #s(hash-table @@ -440,7 +432,10 @@ languages in settings." "inc" yasm "mac" yasm "yaws" yaws "zig" zig )) - "Raw block tag -> tree sitter language map.") + "Raw block tag -> tree sitter language map. +Associated map: `typst-ts-els-lang-tags-map'. +Please use function `typst-ts-els--add-treesit-range-rules' and +`typst-ts-els--lang-name-remap' to modify them.") ;; to test settings: ;; emacs --batch -l ./typst-ts-embedding-lang-settings.el --eval "(typst-ts-embedding-lang-settings-test)" @@ -661,11 +656,13 @@ languages in settings." '((comments) (constants keywords text links) (nodes))))) - "Settings for raw block languages.") + "Predefined settings for raw block languages. +Format: Language name -> settings. +Use function `typst-ts-embedding-lang-settings-test' to test your settings.") (defun typst-ts-els--merge-features (a b) - "Merge `treesit-font-lock-feature-list's A with B." + "Merge `treesit-font-lock-feature-list' A with B." (when (not (and a b)) (error "One of the treesit font lock feature list is nil when merge!")) (cl-loop for i to 3 ; [0, 3] @@ -753,6 +750,10 @@ LANG: language symbol." (typst-ts-els--treesit-range-rules lang)))) (defun typst-ts-els--try-get-ts-settings (mode) + "Try your luck to get related settings for specific tree sitter mode. +MODE: tree sitter mode. +This function basically create a temp buffer, then get the tree sitter settings +from related local variables." (with-temp-buffer (setq-local delay-mode-hooks t) ; don't run hooks associated with MODE (funcall mode) @@ -770,13 +771,19 @@ LANG: language symbol." (defun typst-ts-els-include-dynamically (_ranges _parser) "Include language setting dynamically. +Basically, this function will first try to merge settings from predefined +settings `typst-ts-embedding-lang-settings'. If a language is not in the +predefined settings, then it will try to guess the corresponding tree sitter +major mode name from the language, try to load it using +`typst-ts-els--try-get-ts-settings'. Use this function as one notifier of `treesit-parser-notifiers'." ;; `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' + ;; parsers created by `treesit-language-at-point-function' ( + ;; `typst-ts-mode--language-at-point'.) ;; i.e. parsers cannot be created by `treesit-range-settings' (mapcar #'treesit-parser-language (treesit-parser-list)) ;; parsers created by `treesit-range-settings' @@ -789,8 +796,6 @@ Use this function as one notifier of `treesit-parser-notifiers'." (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) @@ -841,6 +846,21 @@ Use this function as one notifier of `treesit-parser-notifiers'." ;;; Utilities functions for changing language tag relationship (change two maps ;;; synchronizely) ============================================================= +(defun typst-ts-els--get-lang-input (lang) + (if (symbolp lang) + (intern (downcase (symbol-name lang))) + (if (stringp lang) + (intern (downcase lang)) + (error "LANG should be either symbol or string")))) + +(defun typst-ts-els--get-tags-input (tags) + (if (stringp tags) + (list (downcase tags)) + (if (and (listp tags) + (stringp (nth 0 tags))) + (mapcar #'downcase tags) + (error "TAGS should be either a string or a list of strings")))) + ;;;###autoload (defun typst-ts-els--add-lang-tags-relationship (lang tags) "Add or modify language tags relationship. @@ -848,17 +868,8 @@ This function will make changes to `typst-ts-els-lang-tags-map' and `typst-ts-els-tag-lang-map'. LANG: either a symbol or string. TAGS: either a string or a list of strings." - (let ((lang (if (symbolp lang) - lang - (if (stringp lang) - (intern lang) - (error "LANG should be either symbol or string")))) - (tags (if (stringp tags) - (list tags) - (if (and (listp tags) - (stringp (nth 0 tags))) - tags - (error "Tags should be either a string or a list of strings")))) + (let ((lang (typst-ts-els--get-lang-input lang)) + (tags (typst-ts-els--get-tags-input tags)) (original-tags (gethash lang typst-ts-els-lang-tags-map)) temp-lang) (dolist (tag tags) @@ -877,16 +888,8 @@ TAGS: either a string or a list of strings." This function will remap lang to newlang for `typst-ts-els-lang-tags-map' and `typst-ts-els-tag-lang-map'. LANG and NEWLANG: either a symbol or string." - (let ((lang (if (symbolp lang) - lang - (if (stringp lang) - (intern lang) - (error "LANG should be either symbol or string")))) - (newlang (if (symbolp newlang) - newlang - (if (stringp newlang) - (intern newlang) - (error "NEWLANG should be either symbol or string")))) + (let ((lang (typst-ts-els--get-lang-input lang)) + (newlang (typst-ts-els--get-lang-input newlang)) lang-tags newlang-tags) (unless (eq lang newlang) (setq lang-tags (gethash lang typst-ts-els-lang-tags-map)) @@ -901,28 +904,29 @@ LANG and NEWLANG: either a symbol or string." ;;; Test Utilities ============================================================= (defun typst-ts-embedding-lang-settings-test () - "Test typst-ts-embedding-lang-settings." - (setq-local treesit-font-lock-feature-list - '((comment common) - (markup-basic code-basic math-basic) - (markup-standard code-standard math-standard) - (markup-extended code-extended math-extended))) - (let (missing-dylibs err-msgs) - (dolist (setting-entry typst-ts-embedding-lang-settings) - (let ((language (car setting-entry)) - (config (cdr setting-entry))) - (message "Testing %s ..." language) - (unless (treesit-ready-p language t) - (setq missing-dylibs (list (symbol-name language)))) - (condition-case err - (typst-ts-els-merge-settings config) - (error - (setq err-msgs (list (error-message-string err))))))) - (message "--------- Missing Tree Sitter Dynamic libraries -------------") - (message " (This also could be an error of entry key name in settings) ") - (message "%s" (string-join missing-dylibs " ")) - (message "--------- Error Messages ------------------------------------") - (message "%s" (string-join err-msgs "\n")))) + "Test `typst-ts-embedding-lang-settings'." + (with-temp-buffer + (setq-local treesit-font-lock-feature-list + '((comment common) + (markup-basic code-basic math-basic) + (markup-standard code-standard math-standard) + (markup-extended code-extended math-extended))) + (let (missing-dylibs err-msgs) + (dolist (setting-entry typst-ts-embedding-lang-settings) + (let ((language (car setting-entry)) + (config (cdr setting-entry))) + (message "Testing %s ..." language) + (unless (treesit-ready-p language t) + (setq missing-dylibs (list (symbol-name language)))) + (condition-case err + (typst-ts-els-merge-settings config) + (error + (setq err-msgs (list (error-message-string err))))))) + (message "--------- Missing Tree Sitter Dynamic libraries -------------") + (message " (This also could be an error of entry key name in settings) ") + (message "%s" (string-join missing-dylibs " ")) + (message "--------- Error Messages ------------------------------------") + (message "%s" (string-join err-msgs "\n"))))) (provide 'typst-ts-embedding-lang-settings) diff --git a/typst-ts-mode.el b/typst-ts-mode.el index 8ce89229a2..abc1a19a0d 100644 --- a/typst-ts-mode.el +++ b/typst-ts-mode.el @@ -28,21 +28,8 @@ ;; 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 - -;; add documentations ;; add more treesit settings at startup like `treesit-thing-settings' -;; BUGS find: -;; -;; 1. update raw block language will not delete the old local parser -;; -> you need to delete the whole raw block to remove the local parser -;; -> this is due to the behavior of `treesit--update-ranges-local' -;; -> current-haven't thought good way to handle it - ;;; Code: (require 'treesit) @@ -167,12 +154,6 @@ is eliminated." :set-after '(typst-ts-markup-header-same-height) :group 'typst-ts-faces) -(defcustom typst-ts-mode-raw-block-lang-list - '(python rust) ; TODO - "Raw Block Lang List." - :type '(list symbol) - :group 'typst-ts) - ;; Face ========================================================================= (defface typst-ts-watch-modeline-indicator-face '((t :inherit (underline bold))) @@ -1044,7 +1025,7 @@ See `treesit-language-at-point-function'." (when (and typst-ts-mode-enable-raw-blocks-highlight typst-ts-mode-highlight-raw-blocks-at-startup) ;; since currently local parsers haven't created, we cannot only load - ;; those necessary parsers + ;; those necessary parsers (cl-loop for setting in typst-ts-embedding-lang-settings for lang = (car setting) for config = (cdr setting)