branch: elpa/typst-ts-mode commit f1ca0765e9a92470d599fa4bf368cc620f980468 Author: Meow King <mr.meowk...@anche.no> Commit: Meow King <mr.meowk...@anche.no>
feat: Add customizable option for indenting section (header) --- basic-syntax.typ | 130 ++++++++++---------- typst-ts-embedding-lang-settings.el | 4 - typst-ts-mode.el | 228 ++++++++++++++++++++++++------------ 3 files changed, 215 insertions(+), 147 deletions(-) diff --git a/basic-syntax.typ b/basic-syntax.typ index ad85254c64..bf34ccd7a3 100644 --- a/basic-syntax.typ +++ b/basic-syntax.typ @@ -6,77 +6,77 @@ // header face = headline -https://www.google.com // url -_emph_ // emphasis -*strong* // strong -- item // item -/ term1: value -"El Psy Kongraoo" // quote -hello \ // line break -`El Psy Kongraoo` // raw span -// raw block -```bash + https://www.google.com // url + _emph_ // emphasis + *strong* // strong + - item // item + / term1: value + "El Psy Kongraoo" // quote + hello \ // line break + `El Psy Kongraoo` // raw span + // raw block + ```bash sudo rm -rf * ``` -<label> // label -@reference // reference + <label> // label + @reference // reference -Hello\nWorld // escape + Hello\nWorld // escape -#(4.2) // number -#"El Psy Kongaroo" // string -#[El Psy Kongraoo] // content -#true #false // boolean -#sym.bar.h // builtin -#set text(a: 0) // call & builtin -#none // none -#auto // auto -#(a + b) // ident + #(4.2) // number + #"El Psy Kongaroo" // string + #[El Psy Kongraoo] // content + #true #false // boolean + #sym.bar.h // builtin + #set text(a: 0) // call & builtin + #none // none + #auto // auto + #(a + b) // ident -#(0 in "0" not in a) // in -#(a and b or not c) // and, or, not -#(2 + - 1) #(2 - -1) // sign -#(1 + 1) // add -#(1 - 1) // sub -#(1 * 1) // mul -#(1 / 1) // div -#if 2 > 1 [] // cmp -#import "a": * // wildcard + #(0 in "0" not in a) // in + #(a and b or not c) // and, or, not + #(2 + - 1) #(2 - -1) // sign + #(1 + 1) // add + #(1 - 1) // sub + #(1 * 1) // mul + #(1 / 1) // div + #if 2 > 1 [] // cmp + #import "a": * // wildcard -#let a = b // let -#if b {} else {} // branch -#while n < 10 { // while - (n,) -} -#for i in a {} // for -#import "a": a, b // import -#import "a.lib" as b // as -#include "a" // include -#show: columns.with(2) // show -#set text(a: 0) // set -#let a() = { // return - return 2 -} -#for letter in "abc nope" { // flow - if letter == " " { - break - } else if letter == "a" { - continue - } - letter -} + #let a = b // let + #if b {} else {} // branch + #while n < 10 { // while + (n,) + } + #for i in a {} // for + #import "a": a, b // import + #import "a.lib" as b // as + #include "a" // include + #show: columns.with(2) // show + #set text(a: 0) // set + #let a() = { // return + return 2 + } + #for letter in "abc nope" { // flow + if letter == " " { + break + } else if letter == "a" { + continue + } + letter + } -#a()() // function -#range().map // builtin function -#l.zip(r).map( // method - ((a,b)) => a + b // TODO lambda -) -#(a, c: b) // tagged -#a.b // field + #a()() // function + #range().map // builtin function + #l.zip(r).map( // method + ((a,b)) => a + b // TODO lambda + ) + #(a, c: b) // tagged + #a.b // field -$ a $ // math -$ 1 + 1 = 2 $ -$ E = m * c^2 $ -$ eq.not(0) $ -$ cal(A) := { x in RR | x "is natural" } $ + $ a $ // math + $ 1 + 1 = 2 $ + $ E = m * c^2 $ + $ eq.not(0) $ + $ cal(A) := { x in RR | x "is natural" } $ diff --git a/typst-ts-embedding-lang-settings.el b/typst-ts-embedding-lang-settings.el index 4627e83653..84783e8329 100644 --- a/typst-ts-embedding-lang-settings.el +++ b/typst-ts-embedding-lang-settings.el @@ -19,10 +19,6 @@ ;; Functionality to embed other languages in typst documentation. -;; NOTE: -;; Raw block 'typc' tag cannot work as expected in typst code mode, it works in -;; typst markup mode - ;;; Code: (require 'treesit) diff --git a/typst-ts-mode.el b/typst-ts-mode.el index 1e99976922..6741d66400 100644 --- a/typst-ts-mode.el +++ b/typst-ts-mode.el @@ -51,6 +51,13 @@ :type 'integer :group 'typst-ts) + +(defcustom typst-ts-mode-indent-offset-section 2 + "The indent offset for section. +i.e. The a indentation offset after each header." + :type 'boolean + :group 'typst-ts) + (defcustom typst-ts-mode-fontification-precision-level 'middle "Whether to use precise face fontification. Note that precise face fontification will case performance degrading. @@ -91,14 +98,23 @@ The compile options will be passed to the end of :type 'boolean :group 'typst-ts) -(defvar typst-ts-mode-before-compile-hook nil - "Hook runs after compile.") +(defcustom typst-ts-mode-before-compile-hook nil + "Hook runs after compile." + :type 'hook + :group 'typst-ts) -(defvar typst-ts-mode-after-compile-hook nil +(defcustom typst-ts-mode-after-compile-hook nil "Hook runs after compile. Note the requirement of this hook is the same as `compilation-finish-functions'. Also note that this hook runs with typst buffer(the buffer you are editing) as -the current buffer.") +the current buffer." + :type 'hook + :group 'typst-ts) + +(defcustom typst-ts-mode-tab-function 'indent-for-tab-command + "Default function for `typst-ts-mode-cycle' when conditions don't match." + :type 'function + :group 'typst-ts) (defcustom typst-ts-mode-watch-options "" "User defined compile options for `typst-ts-mode-watch'. @@ -709,8 +725,8 @@ If you want to customize the rules, please customize the same name variable (markup-standard code-standard math-standard) (markup-extended code-extended math-extended))) -(defconst typst-ts-mode--bracket-node-types - '("block" "content" "group") +(defconst typst-ts-mode--container-node-types + '("block" "content" "group" "math") "Bracket node types.") (defun typst-ts-mode--node-inside-brackets (parent) @@ -719,9 +735,16 @@ Return nil if the node is not inside brackets." (treesit-parent-until parent (lambda (parent) - (member (treesit-node-type parent) typst-ts-mode--bracket-node-types)) + (member (treesit-node-type parent) typst-ts-mode--container-node-types)) t)) +(defun typst-ts-mode--get-node-bol (node) + "Get the NODE's indentation offset (at node beginning)." + (save-excursion + (goto-char (treesit-node-start node)) + (back-to-indentation) + (point))) + (defun typst-ts-mode--ancestor-in (types &optional return-bol) "Return a function to check whether one of the ancestors of a node is in TYPES. The returned function suits `treesit-simple-indent-rules' Match. @@ -739,12 +762,8 @@ corresponding ancestor node. Return nil if ancestor not matching." (member (treesit-node-type parent) types)) t))) (if return-bol - (if ancestor - (save-excursion - (goto-char (treesit-node-start ancestor)) - (back-to-indentation) - (point)) - nil) + (when ancestor + (typst-ts-mode--get-node-bol ancestor)) ancestor)))) (defun typst-ts-mode--ancestor-bol (types) @@ -761,8 +780,8 @@ See `treesit-simple-indent-rules'." (goto-char bol) (skip-chars-backward " \r\n\t") (1- (point)))) - ((and (not (eq prev-nonwhite-pos 0)) ;; first line - (not (eq + ((and (not (eq prev-nonwhite-pos 0)) ; first line + (not (eq ; has previous sibling (line-number-at-pos prev-nonwhite-pos) (line-number-at-pos (point)))))) (prev-nonwhite-line-node @@ -796,9 +815,23 @@ work well. Example: (back-to-indentation) (point))) +(defun typst-ts-mode--indentation-in-section-content (node parent bol) + "Detect whether current node is inside section > content. +NODE, PARENT, BOL see info node `(elisp) Parser-based Indentation'. +If match, return the bol of the content node." + (when-let ((container-node + (funcall (typst-ts-mode--ancestor-in typst-ts-mode--container-node-types) + node parent bol))) + (when (and + (string= "content" (treesit-node-type container-node)) + (string= "section" (treesit-node-type (treesit-node-parent container-node)))) + (typst-ts-mode--get-node-bol container-node)))) + (defvar typst-ts-mode--indent-rules - ;; you can set `treesit--indent-verbose' variable to t to see which indentation - ;; rule matches. + ;; debug tips: + ;; 1. `toggle-debug-on-error' to make sure you indentation code error report + ;; 2. enable `treesit--indent-verbose' to see what indentation rule matches + ;; 3. `treesit-inspect-mode' or `treesit-inspect-node-at-point' `((typst ((and (node-is ")") (parent-is "group")) parent-bol 0) ((and (node-is "}") (parent-is "block")) parent-bol 0) @@ -806,21 +839,46 @@ work well. Example: ((and (node-is "item") (parent-is "item")) parent-bol typst-ts-mode-indent-offset) + ((n-p-gp nil "content" "section") + parent-bol typst-ts-mode-indent-offset-section) + ((parent-is "block") parent-bol typst-ts-mode-indent-offset) ((parent-is "content") parent-bol typst-ts-mode-indent-offset) ((parent-is "group") parent-bol typst-ts-mode-indent-offset) + ((lambda (node parent bol) + (message "%s %s %s" node parent bol) + nil) parent-bol 0) + + ((n-p-gp "$" "math" nil) parent-bol typst-ts-mode-indent-offset) + ;; don't indent raw block ((and no-node ,(typst-ts-mode--ancestor-in (list "raw_blck"))) no-indent 0) - ;; previous line is item type and the ending is a linebreak - ((and no-node typst-ts-mode--identation-item-linebreak) + ;; previous nonwhite line is item type and the ending is a linebreak + (typst-ts-mode--identation-item-linebreak typst-ts-mode--indentation-item-linebreak-get-pos typst-ts-mode-indent-offset) + ;; item should follow its previous line item's indentation level + ((lambda (node parent &rest _) + (unless node + (save-excursion + (forward-line -1) + (back-to-indentation) + (string= "item" (treesit-node-type + (treesit-node-parent + (treesit-node-at (point)))))))) + prev-line + 0) + + ((and no-node typst-ts-mode--indentation-in-section-content) + typst-ts-mode--indentation-in-section-content + typst-ts-mode-indent-offset-section) + ((and no-node - ,(typst-ts-mode--ancestor-in typst-ts-mode--bracket-node-types)) - ,(typst-ts-mode--ancestor-bol typst-ts-mode--bracket-node-types) + ,(typst-ts-mode--ancestor-in typst-ts-mode--container-node-types)) + ,(typst-ts-mode--ancestor-bol typst-ts-mode--container-node-types) typst-ts-mode-indent-offset) ;; ((lambda (node parent bol) @@ -830,8 +888,11 @@ work well. Example: ((and no-node (parent-is "source_file")) prev-line 0) - - (no-node parent-bol 0))) + + (no-node parent-bol 0) + + ;; example: (item (text) (text) (text)) when `(text)' is in different line + (catch-all prev-line 0))) "Tree-sitter indent rules for `rust-ts-mode'.") (defun typst-ts-mode-comment-setup() @@ -1121,64 +1182,75 @@ PROC: process; OUTPUT: new output from PROC." ;;;###autoload (defun typst-ts-mode-cycle (&optional arg) "Cycle. +Customize `typst-ts-mode-tab-function' for default tab function when no +condition matches. ARG. TODO lack of documentation." (interactive "P") - (when-let* ((cur-pos (point)) - (cur-node (treesit-node-at cur-pos)) - (cur-node-type (treesit-node-type cur-node)) - (parent-node (treesit-node-parent cur-node)) ; could be nil - (parent-node-type (treesit-node-type parent-node))) - (cond - ((or (equal cur-node-type "parbreak") - (eobp)) - (when-let* ((cur-line-bol - (save-excursion - (back-to-indentation) - (point))) - (prev-nonwhite-pos (save-excursion - (goto-char cur-line-bol) - (skip-chars-backward " \r\n\t") - (1- (point)))) - ((and (not (eq prev-nonwhite-pos 0)) ;; first line - (not (eq - (line-number-at-pos prev-nonwhite-pos) - (line-number-at-pos (point)))))) - (prev-nonwhite-line-node - (treesit-node-at prev-nonwhite-pos)) - (prev-nonwhite-line-bol - (save-excursion - (goto-char prev-nonwhite-pos) - (back-to-indentation) - (point))) - (prev-nonwhite-line-heading-node - (treesit-node-at prev-nonwhite-line-bol)) - (prev-nonwhite-line-top-node (treesit-node-parent - prev-nonwhite-line-heading-node)) - (cur-line-bol-column (typst-ts-mode-column-at-pos cur-line-bol)) - (prev-nonwhite-line-bol-column - (typst-ts-mode-column-at-pos prev-nonwhite-line-bol))) - (cond - ;; 1. el - ;; 2. psy| <- can toggle indent - ((and - (equal (treesit-node-type prev-nonwhite-line-top-node) "item") - (equal (treesit-node-type prev-nonwhite-line-heading-node) "-") - (not (equal (treesit-node-type prev-nonwhite-line-node) "linebreak"))) - (let (point) - (if (not (eq cur-line-bol-column prev-nonwhite-line-bol-column)) - (progn - (setq point (point)) - (indent-line-to prev-nonwhite-line-bol-column) - (goto-char (- point typst-ts-mode-indent-offset))) - (setq point (point)) - (indent-line-to (+ typst-ts-mode-indent-offset - prev-nonwhite-line-bol-column)) - (goto-char (+ typst-ts-mode-indent-offset point))))) - ))) - (t - (indent-for-tab-command)) - ))) + (let (execute-result) + (setq + execute-result + (catch 'execute-result + (when-let* ((cur-pos (point)) + (cur-node (treesit-node-at cur-pos)) + (cur-node-type (treesit-node-type cur-node)) + (parent-node (treesit-node-parent cur-node)) ; could be nil + (parent-node-type (treesit-node-type parent-node))) + (cond + ((or (equal cur-node-type "parbreak") + (equal parent-node-type "item") + (eobp)) + (when-let* ((cur-line-bol + (save-excursion + (back-to-indentation) + (point))) + (prev-nonwhite-pos (save-excursion + (goto-char cur-line-bol) + (skip-chars-backward " \r\n\t") + (1- (point)))) + ((and (not (eq prev-nonwhite-pos 0)) ; first line + (not (eq ; has previous sibling + (line-number-at-pos prev-nonwhite-pos) + (line-number-at-pos (point)))))) + (prev-nonwhite-line-node + (treesit-node-at prev-nonwhite-pos)) + (prev-nonwhite-line-bol + (save-excursion + (goto-char prev-nonwhite-pos) + (back-to-indentation) + (point))) + (prev-nonwhite-line-heading-node + (treesit-node-at prev-nonwhite-line-bol)) + (prev-nonwhite-line-top-node (treesit-node-parent + prev-nonwhite-line-heading-node)) + (cur-line-bol-column (typst-ts-mode-column-at-pos cur-line-bol)) + (prev-nonwhite-line-bol-column + (typst-ts-mode-column-at-pos prev-nonwhite-line-bol))) + (cond + ;; 1. el + ;; 2. psy| <- can toggle indent + ((and + (equal (treesit-node-type prev-nonwhite-line-top-node) "item") + (equal (treesit-node-type prev-nonwhite-line-heading-node) "-") + ;; previous nonwhite-line ending is not '\' character + (not (equal (treesit-node-type prev-nonwhite-line-node) "linebreak"))) + (let (point) + (if (not (eq cur-line-bol-column prev-nonwhite-line-bol-column)) + (progn + (setq point (point)) + (indent-line-to prev-nonwhite-line-bol-column) + (goto-char (- point typst-ts-mode-indent-offset))) + (setq point (point)) + (indent-line-to (+ typst-ts-mode-indent-offset + prev-nonwhite-line-bol-column)) + (goto-char (+ typst-ts-mode-indent-offset point))) + (throw 'execute-result 'success)))))) + (t nil))))) + ;; execute default action + (unless (eq execute-result 'success) + (if (commandp typst-ts-mode-tab-function) + (call-interactively typst-ts-mode-tab-function) + (funcall typst-ts-mode-tab-function))))) ;;;###autoload (defvar typst-ts-mode-map