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

    refactor: enhance indentation
---
 README.md        |   4 +-
 side/utils.el    |   5 ++-
 typst-ts-mode.el | 125 ++++++++++++++++++++++++++++++++++---------------------
 3 files changed, 83 insertions(+), 51 deletions(-)

diff --git a/README.md b/README.md
index 043df9e45a..819815990c 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ Tree Sitter support for Typst. Minimum Emacs version 
requirement: 29.
 `typst 0.10.0 (70ca0d25)`
 
 3. Tree Sitter parser for Typst: https://github.com/uben0/tree-sitter-typst  
-commit: `c0765e3`
+commit: `2d68228e8af537fccd02b10c9b37b353238cfa5e - Feb 4, 2024`  
 
 Note this tree sitter parser is included in [tree sitter 
modules](https://github.com/casouri/tree-sitter-module), so you can use the 
build script 
 in it to get this parser.  
@@ -92,7 +92,7 @@ defined by `outline-minor-mode` such as `outline-cycle`.
 For customizable options: `customize` -> `typst-ts`.  
 
 Here are some options you may find useful:  
-1. `typst-ts-mode-indent-offset` (default 4)  
+1. `typst-ts-mode-indent-offset` (default 4) and 
`typst-ts-mode-indent-offset-section` (default 2)  
 2. `typst-ts-mode-executable-location`  
 3. `typst-ts-mode-watch-options`.  
    Set this to `--open` so typst will open the compiled file for you.
diff --git a/side/utils.el b/side/utils.el
index 8728c3f2e8..4fc0a21d68 100644
--- a/side/utils.el
+++ b/side/utils.el
@@ -29,7 +29,10 @@
   (setq debug-on-error t
         treesit--indent-verbose t)
   (treesit-explore-mode 1)
-  (treesit-inspect-mode 1))
+  (treesit-inspect-mode 1)
+
+  ;; note that when in intensive testing, you'd better turn off 
`auto-save-visited-mode'
+  (whitespace-mode 1))
 
 (defun typst-ts/util/els/get-all-ts-major-modes ()
   "Get all tree sitter major modes from `treesit-auto'."
diff --git a/typst-ts-mode.el b/typst-ts-mode.el
index 8d8c8acae7..e333b42c3e 100644
--- a/typst-ts-mode.el
+++ b/typst-ts-mode.el
@@ -54,7 +54,7 @@
 
 (defcustom typst-ts-mode-indent-offset-section 2
   "The indent offset for section.
-i.e. The a indentation offset after each header."
+i.e. The indentation offset after header."
   :type 'boolean
   :group 'typst-ts)
 
@@ -748,14 +748,11 @@ Return nil if the node is not inside brackets."
 (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.
-Ancestors include the query node itself.
 If RETURN-BOL is non-nil, then return returns the beginning of line position of
 the corresponding ancestor node that its type is in TYPES, else return the
 corresponding ancestor node.  Return nil if ancestor not matching."
-  (lambda (node parent _bol)
-    (let* ((query-node (if node ;; considering node may be nil
-                           node
-                         parent))
+  (lambda (_node parent _bol)
+    (let* ((query-node parent)
            (ancestor (treesit-parent-until
                       query-node
                       (lambda (parent)
@@ -830,37 +827,64 @@ If match, return the bol of the content node."
 (defvar typst-ts-mode--indent-rules
   ;; debug tips:
   ;; use `typst-ts/util/setup-indent-debug-environment' function in 
`side/utils.el'
-  ;; it basically does these:
+  ;; it basically does these (with some extra trivial stuffs):
   ;; 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'
+  
+  ;; `indentation-test.typ' file is used for testing indentation.
+
+  ;; no-node situation: often in insert mode > hit return at the line ending
+  ;; `typst-ts-mode-indent-line-function' is created for handling end of buffer
+  ;;  edge cases
   `((typst
+     ((lambda (node parent bol)  ; NOTE
+        (message "%s %s %s" node parent bol)
+        nil) parent-bol 0)
+
+     ((n-p-gp "section" "source_file" nil) column-0 0)  ; <2>
+     
      ((and (node-is ")") (parent-is "group")) parent-bol 0)
      ((and (node-is "}") (parent-is "block")) parent-bol 0)
      ((and (node-is "]") (parent-is "content")) parent-bol 0)
+     ;; math - the last "$" notation
+     ((match "$" "math" nil 2 2) parent-bol 0)
 
-     ((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)
+     ;; code field, example:
+     ;; "a b c"
+     ;;   .split(" ")
+     ((n-p-gp "." "field" nil) parent-bol typst-ts-mode-indent-offset)
 
-     ((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)
+     ;; math align, example:
+     ;; sum_(k=0)^n k
+     ;;   &= 1 + ... + n \
+     ((node-is "align") parent-bol typst-ts-mode-indent-offset)
 
-     ;; ((n-p-gp "$" "math" nil) parent-bol typst-ts-mode-indent-offset)
+     ;; item - child item
+     ((and (node-is "item") (parent-is "item")) parent-bol 
typst-ts-mode-indent-offset)
 
-     (,(typst-ts-mode--ancestor-in '("ERROR")) no-indent 0)  ; 1
+     ;; item - 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)
 
-     ((lambda (node parent bol)
-        (message "%s %s %s" node parent bol)
-        nil) parent-bol 0)
+     ;; item - item should follow its previous line item's indentation level
+     ((lambda (node parent &rest _)
+        (save-excursion
+          (forward-line -1)
+          (back-to-indentation)
+          (string= "item" (treesit-node-type
+                           (treesit-node-parent
+                            (treesit-node-at (point)))))))
+      prev-line
+      0)
 
-     ;; raw block (TODO add indent offset when 
`typst-ts-mode-highlight-raw-block' is enabled)
-     ((n-p-gp "```" "raw_blck" nil) parent-bol 0)
+     ;; raw block
+     ;; (TODO add indent offset when `typst-ts-mode-highlight-raw-block' is 
enabled)
+     ;; the last "```" notation for raw block
+     ((match "```" "raw_blck" nil 3 3) parent-bol 0)
      ((n-p-gp nil "blob" "raw_blck")
       no-indent
-      ;; make sure the content indentation is at least as big as raw block 
header's
+      ;; make sure the content indentation is at least as long as raw block 
header's
       (lambda (_node parent bol)
         (let* ((node-raw-blck (treesit-node-parent parent))
                (raw-block-column (typst-ts-mode-column-at-pos
@@ -870,38 +894,23 @@ If match, return the bol of the content node."
               (- raw-block-column bol-column)
             0))))
 
-     ;; 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)
+     ;; section > content > *> any, suitable for no-node
+     ;; see <2>, which indents the top level headings
+     (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--container-node-types))
+     ;; inside container
+     (,(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)
 
-
-     ;; cop with <1>
-     ;; = Header 1
-     ;;   ```rust| <- return
      ((and no-node (parent-is "source_file"))
       prev-line 0)
 
+     ;; TODO to be examined
+     (,(typst-ts-mode--ancestor-in '("ERROR")) no-indent 0)
+
      (no-node parent-bol 0)
 
      ;; example: (item (text) (text) (text)) when `(text)' is in different line
@@ -1216,7 +1225,9 @@ TODO lack of documentation."
           
           ((or (equal cur-node-type "parbreak")
                (equal parent-node-type "item")
-               (eobp))
+               ;; please turn on whitespace-mode to test the following 
conditions
+               (eobp)
+               (eq (point) (1- (point-max))))
            (when-let* ((cur-line-bol
                         (save-excursion
                           (back-to-indentation)
@@ -1313,6 +1324,19 @@ See `treesit-language-at-point-function'."
               (message "%s" (error-message-string err))
               nil))))
 
+(defun typst-ts-mode-indent-line-function ()
+  "A simple wrapper of `treesit-indent' for handle indentation edge cases.
+It is useful to handle end of buffer situation (please turn on 
`whitespace-mode'
+to see that it's actually end of buffer).  Basically, if we are at the end of
+buffer, the node, parent passed to our treesit indentation function will be 
nil,
+source_file, which is not desired.
+If we are before a '\n' character, then the node and its parent probably are
+nil and parbreak."
+  (when (eobp)
+    (insert "\n")
+    (backward-char))
+  (treesit-indent))
+
 ;;;###autoload
 (define-derived-mode typst-ts-mode text-mode "Typst"
   "Major mode for editing Typst, powered by tree-sitter."
@@ -1352,7 +1376,10 @@ See `treesit-language-at-point-function'."
 
   ;; Electric
   (setq-local
-   electric-indent-chars (append "{}()[]$" electric-indent-chars)
+   ;; =: heading and others
+   ;; &: math align
+   ;; .: code field
+   electric-indent-chars (append "{}()[]$=&." electric-indent-chars)
    electric-pair-pairs '((?\" . ?\")
                          (?\{ . ?\})
                          (?\( . ?\))
@@ -1403,7 +1430,9 @@ See `treesit-language-at-point-function'."
   ;; provides outline ellipsis
   (outline-minor-mode t)
   
-  (treesit-major-mode-setup))
+  (treesit-major-mode-setup)
+
+  (setq-local indent-line-function #'typst-ts-mode-indent-line-function))
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.typ\\'" . typst-ts-mode))

Reply via email to