branch: elpa/typst-ts-mode
commit 96d82bc4ba38a6d2d1fcabca5e413c58cb278a80
Author: Meow King <[email protected]>
Commit: Meow King <[email protected]>
refactor: separate editing commands into another file
---
README.md | 7 +
typst-ts-utils.el => typst-ts-core.el | 21 ++-
typst-ts-editing.el | 294 ++++++++++++++++++++++++++++++++++
typst-ts-embedding-lang-settings.el | 10 +-
typst-ts-mode.el | 287 +--------------------------------
5 files changed, 327 insertions(+), 292 deletions(-)
diff --git a/README.md b/README.md
index e654c8a718..c7beaefeb9 100644
--- a/README.md
+++ b/README.md
@@ -160,6 +160,13 @@ and `defcustom' forms reset their default values."
(eval-defun nil))))
```
+### How to use different version of Emacs to test
+
+``` shell
+# change `emacs` to `emacs29`, `emacs30` or the path of your emacs executable
+emacs -Q -L . --eval "(require 'typst-ts-mode)"
+```
+
#### How to do lint
I recommend you to use [makem.sh](https://github.com/alphapapa/makem.sh).
However, you can choose anything you like.
To use it, first `cd` into the project root directory, then:
diff --git a/typst-ts-utils.el b/typst-ts-core.el
similarity index 86%
rename from typst-ts-utils.el
rename to typst-ts-core.el
index 8113b71138..bdc6195173 100644
--- a/typst-ts-utils.el
+++ b/typst-ts-core.el
@@ -1,4 +1,4 @@
-;;; typst-ts-utils.el --- utility functions for typst-ts-mode -*-
lexical-binding: t; -*-
+;;; typst-ts-core.el --- core functions for typst-ts-mode -*- lexical-binding:
t; -*-
;; Copyright (C) 2023 The typst-ts-mode Project Contributors
;; This file is NOT part of Emacs.
@@ -27,7 +27,14 @@
;; code from Emacs binary
(declare-function treesit-parser-list "treesit" t t)
-(defun typst-ts-utils-parser-list (&optional buffer language)
+(defun typst-ts-core-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-core-parser-list (&optional buffer language)
"An comptibility function for Emacs 29's `treesit-parser-list' function.
BUFFER defaults to the current buffer. If that buffer is an indirect
buffer, its base buffer is used instead. That is, indirect buffers
@@ -43,7 +50,7 @@ If LANGUAGE is non-nil, only return parsers for that
language."
parsers))))
;; code is from treesit.el inside Emacs Source
-(defun typst-ts-utils-local-parsers-at (&optional pos language with-host)
+(defun typst-ts-core-local-parsers-at (&optional pos language with-host)
"Return all the local parsers at POS.
It's a copy of Emacs 30's `treesit-local-parsers-at' function.
POS LANGUAGE WITH-HOST."
@@ -60,7 +67,7 @@ POS LANGUAGE WITH-HOST."
(nreverse res))))
;; code is from treesit.el inside Emacs Source
-(defun typst-ts-utils-local-parsers-on (&optional beg end language with-host)
+(defun typst-ts-core-local-parsers-on (&optional beg end language with-host)
"Return all the local parsers between BEG END.
It's a copy of Emacs 30's `treesit-local-parsers-on' function.
BEG END LANGUAGE WITH-HOST."
@@ -76,7 +83,7 @@ BEG END LANGUAGE WITH-HOST."
(push (if with-host (cons parser host-parser) parser) res))))
(nreverse res))))
-(defun typst-ts-utils-node-get (node instructions)
+(defun typst-ts-core-node-get (node instructions)
"Get things from NODE by INSTRUCTIONS.
It's a copy of Emacs 30's `treesit-node-get' function."
(declare (indent 1))
@@ -98,6 +105,6 @@ It's a copy of Emacs 30's `treesit-node-get' function."
(treesit-node-prev-sibling node named)))))))
node))
-(provide 'typst-ts-utils)
+(provide 'typst-ts-core)
-;;; typst-ts-utils.el ends here
+;;; typst-ts-core.el ends here
diff --git a/typst-ts-editing.el b/typst-ts-editing.el
new file mode 100644
index 0000000000..7abcad9124
--- /dev/null
+++ b/typst-ts-editing.el
@@ -0,0 +1,294 @@
+;;; typst-ts-editing.el --- Helper functions for editing Typst documents -*-
lexical-binding: t; -*-
+;; Copyright (C) 2023 The typst-ts-mode Project Contributors
+
+;; This file is NOT part of Emacs.
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'outline)
+(require 'typst-ts-core)
+
+;;;###autoload
+(defun typst-ts-mode-heading-up ()
+ "Switch the current heading with the heading above."
+ (interactive)
+ (typst-ts-mode-meta--dwim 'up))
+
+;;;###autoload
+(defun typst-ts-mode-heading-down ()
+ "Switch the current heading with the heading below."
+ (interactive)
+ (typst-ts-mode-meta--dwim 'down))
+
+;;;###autoload
+(defun typst-ts-mode-heading-increase ()
+ "Increase the heading level."
+ (interactive)
+ (typst-ts-mode-meta--dwim 'right))
+
+;;;###autoload
+(defun typst-ts-mode-heading-decrease ()
+ "Decrease heading level."
+ (interactive)
+ (typst-ts-mode-meta--dwim 'left))
+
+(defun typst-ts-mode-heading--at-point-p ()
+ "Whether the current line is a heading.
+Return the heading node when yes otherwise nil."
+ (let ((node (treesit-node-parent
+ (treesit-node-at
+ (save-excursion
+ (beginning-of-line-text)
+ (point))))))
+ (if (string= (treesit-node-type node) "heading")
+ node
+ nil)))
+
+(defun typst-ts-mode-meta--dwim (direction)
+ "Do something depending on the context with meta key + DIRECTION.
+`left': `typst-ts-mode-heading-decrease',
+`right': `typst-ts-mode-heading-increase',
+`up': `typst-ts-mode-heading-up',
+`down': `typst-ts-mode-heading-down'.
+When there is no relevant action to do it will execute the relevant function in
+the `GLOBAL-MAP' (example: `right-word')."
+ (let ((heading (typst-ts-mode-heading--at-point-p))
+ ;; car function, cdr string of function for
`substitute-command-keys'
+ (call-me/string
+ (pcase direction
+ ('left
+ (cons #'outline-promote
+ "\\[typst-ts-mode-heading-decrease]"))
+ ('right
+ (cons #'outline-demote
+ "\\[typst-ts-mode-heading-decrease]"))
+ ('up
+ (cons #'outline-move-subtree-up
+ "\\[typst-ts-mode-heading-up]"))
+ ('down
+ (cons #'outline-move-subtree-down
+ "\\[typst-ts-mode-heading-down]"))
+ (_ (error "%s is not one of: `right' `left'" direction)))))
+ (if heading
+ (call-interactively (car call-me/string))
+ (call-interactively
+ (keymap-lookup global-map (substitute-command-keys (cdr
call-me/string)))))))
+
+(defun typst-ts-mode--item-on-line-p ()
+ "Does the current line have an item node?
+Return the node when yes otherwise
+return the node that is one character left from the end of line."
+ (treesit-node-parent
+ (treesit-node-at
+ (save-excursion
+ ;; starting from the beginning because line could be 1. wow.
+ (beginning-of-line)
+ (condition-case nil
+ (progn
+ (search-forward-regexp (rx (or "+" "-" "."))
+ (pos-eol)
+ nil
+ nil)
+ (left-char))
+ (search-failed
+ ;; need to go to the end of line and then one left because end of
line is the next node
+ (goto-char (1- (pos-eol)))))
+ (point)))))
+
+(defun typst-ts-mode-meta-return (&optional arg)
+ "Depending on context, insert a heading or insert an item.
+The new heading is created after the ending of current heading.
+Using ARG argument will ignore the context and it will insert a heading
instead."
+ (interactive "P")
+ (let ((node (typst-ts-mode--item-on-line-p)))
+ (cond
+ (arg (typst-ts-mode-insert--heading nil))
+ ((string= (treesit-node-type node) "item")
+ (typst-ts-mode-insert--item node))
+ (t
+ (typst-ts-mode-insert--heading node)))))
+
+(defun typst-ts-mode-return (&optional arg)
+ "Handle RET depends on condition.
+When prefix ARG is non-nil, call global return function."
+ (interactive "P")
+ (let (execute-result node)
+ (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
+ (arg (throw 'execute-result 'default))
+ ;; on item node end
+ ((and (eolp)
+ (setq node (typst-ts-mode--item-on-line-p))
+ (string= (treesit-node-type node) "item")
+ (not (string= (typst-ts-core-node-get node '((child -1 nil)
(type))) "linebreak")))
+ (if (> (treesit-node-child-count node) 1)
+ (typst-ts-mode-insert--item node)
+ ;; no text means delete the item on current line
+ (beginning-of-line)
+ (kill-line)
+ (indent-according-to-mode))
+ (throw 'execute-result 'success))
+ ))))
+ ;; execute default action if not successful
+ (unless (eq execute-result 'success)
+ (let ((global-ret-function
+ (global-key-binding (kbd "RET"))))
+ (if (and current-prefix-arg
+ (yes-or-no-p
+ (format
+ "Execute function `%s' with the given prefix argument?"
+ global-ret-function)))
+ (call-interactively global-ret-function)
+ (let ((current-prefix-arg nil))
+ (call-interactively global-ret-function)))))))
+
+(defun typst-ts-mode-insert--item (node)
+ "Insert an item after NODE.
+NODE must be an item node!
+This function respects indentation."
+ (let* (;; +, -, or <num>.
+ (item-type (treesit-node-text
+ (treesit-node-child node 0)))
+ (item-number (string-to-number item-type))
+ (item-end (treesit-node-end node))
+ (node-bol-column (typst-ts-mode-column-at-pos
+ (typst-ts-core-get-node-bol node))))
+ (goto-char item-end)
+ (newline)
+ (indent-line-to node-bol-column)
+ (insert (if (= item-number 0)
+ item-type
+ (concat (number-to-string (1+ item-number)) "."))
+ " ")))
+
+(defun typst-ts-mode-insert--heading (node)
+ "Insert a heading after the section that NODE is part of.
+When there is no section it will insert a heading below point."
+ (let* ((section
+ (treesit-parent-until
+ node
+ (lambda (node)
+ (string= (treesit-node-type node) "section"))
+ t))
+ ;; first child is heading
+ (heading (treesit-node-child section 0))
+ (heading-level (treesit-node-type (treesit-node-child heading
0))))
+ (if section
+ (goto-char (treesit-node-end section))
+ ;; no headings so far
+ (setq heading-level "=")
+ (forward-line 1))
+ ;; something can be in the next line/section, the heading needs be on its
own line
+ ;; this has to be done after `goto-char' because it will invalidate the
node
+ (newline)
+ (forward-line -1)
+ ;; insert the heading and indent
+ (insert heading-level " ")
+ (indent-according-to-mode)))
+
+(defun typst-ts-mode-column-at-pos (point)
+ "Get the column at position POINT."
+ (save-excursion
+ (goto-char point)
+ (current-column)))
+
+;;;###autoload
+(defun typst-ts-mode-cycle (&optional _arg)
+ "Cycle."
+ (interactive "P")
+ (let (execute-result)
+ (setq
+ execute-result
+ ;; plz manually throw `\'success' to `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
+ ((equal parent-node-type "raw_blck")
+ (insert-tab)
+ (throw 'execute-result 'success))
+
+ ((or (equal cur-node-type "parbreak")
+ (equal parent-node-type "item")
+ ;; 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)
+ (point)))
+ (prev-nonwhite-pos (save-excursion
+ (goto-char cur-line-bol)
+ (skip-chars-backward "\s\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
+ ;; TODO typst-ts-core-get-node-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")))
+ ;; TODO cycle all its children
+ (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 if not successful
+ (unless (eq execute-result 'success)
+ (call-interactively (global-key-binding (kbd "TAB"))))))
+
+(provide 'typst-ts-editing)
+
+;;; typst-ts-editing.el ends here
diff --git a/typst-ts-embedding-lang-settings.el
b/typst-ts-embedding-lang-settings.el
index f5d6039a88..c663fb8c53 100644
--- a/typst-ts-embedding-lang-settings.el
+++ b/typst-ts-embedding-lang-settings.el
@@ -21,7 +21,7 @@
;;; Code:
(require 'treesit)
-(require 'typst-ts-utils)
+(require 'typst-ts-core)
(defcustom typst-ts-highlight-raw-block-langs-not-in-predefined-settings t
"Whether to highlight raw block of language that is not in settings.
@@ -773,10 +773,10 @@ Use this function as one notifier of
`treesit-parser-notifiers'."
;; 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 (typst-ts-utils-parser-list))
+ (mapcar #'treesit-parser-language (typst-ts-core-parser-list))
;; parsers created by `treesit-range-settings'
(mapcar #'treesit-parser-language
- (typst-ts-utils-local-parsers-on (point-min)
(point-max))))))
+ (typst-ts-core-local-parsers-on (point-min) (point-max))))))
lang-ts-mode settings)
(dolist (lang parser-langs)
(unless (member lang typst-ts-els--include-languages)
@@ -789,7 +789,7 @@ Use this function as one notifier of
`treesit-parser-notifiers'."
(typst-ts-els-merge-lang-settings lang)
;; some feature like cmake-ts-mode will create a parser when
;; the feature is required, so we need to clean thease
parsers
- (mapc #'treesit-parser-delete (typst-ts-utils-parser-list
nil lang))
+ (mapc #'treesit-parser-delete (typst-ts-core-parser-list nil
lang))
(message "Load %s language settings from configuration."
lang))
(error
;; if language not in setting or encounter error during loading,
@@ -801,7 +801,7 @@ Use this function as one notifier of
`treesit-parser-notifiers'."
(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
(typst-ts-utils-parser-list nil lang))
+ (mapc #'treesit-parser-delete
(typst-ts-core-parser-list nil lang))
;; find and merge settings
(setq lang-ts-mode
diff --git a/typst-ts-mode.el b/typst-ts-mode.el
index 37c24aca3c..15896330fb 100644
--- a/typst-ts-mode.el
+++ b/typst-ts-mode.el
@@ -34,11 +34,12 @@
(require 'outline)
(require 'typst-ts-embedding-lang-settings)
-(require 'typst-ts-utils)
+(require 'typst-ts-core)
(require 'typst-ts-faces)
(require 'typst-ts-compile)
(require 'typst-ts-watch-mode)
(require 'typst-ts-edit-indirect)
+(require 'typst-ts-editing)
(defgroup typst-ts nil
"Tree Sitter enabled Typst Writing."
@@ -396,13 +397,6 @@ If you want to customize the rules, please customize the
same name variable
(regexp-opt '("block" "content" "group" "math" "_math_group"))
"Container node types regexp.")
-(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--identation-item-linebreak (_node _parent bol)
"Where the current line is underneath a item with linebreak as ending.
Ignore whitespaces.
@@ -483,7 +477,7 @@ Used in `typst-ts-mode-indent-rules'."
(bol-col
(typst-ts-mode-column-at-pos bol))
(raw-block-bol
- (typst-ts-mode--get-node-bol (treesit-node-parent parent)))
+ (typst-ts-core-get-node-bol (treesit-node-parent parent)))
(raw-block-bol-col
(typst-ts-mode-column-at-pos raw-block-bol)))
(if (equal "blob" prev-line-node-type)
@@ -595,14 +589,14 @@ NODE, PARENT and BOL see `treesit-indent-function'."
(error "Variable `typst-ts-mode-indent-function' shouldn't be null!"))
(let ((res (funcall typst-ts-mode-indent-function node parent bol)))
;; if it is a highlighted raw block region (i.e. contains at least one
local parser)
- (when (typst-ts-utils-local-parsers-at (treesit-node-start node))
+ (when (typst-ts-core-local-parsers-at (treesit-node-start node))
;; when there is no matching rules
(unless (car res)
(setcar res bol)
(setcdr res 0))
(let* ((blob_node (treesit-node-at bol 'typst))
(raw_block_node (treesit-node-parent blob_node))
- (raw_block_bol (typst-ts-mode--get-node-bol raw_block_node))
+ (raw_block_bol (typst-ts-core-get-node-bol raw_block_node))
(raw_block_bol_column (typst-ts-mode-column-at-pos raw_block_bol))
(res-column (+ (typst-ts-mode-column-at-pos (car res)) (cdr
res))))
(when (> raw_block_bol_column res-column)
@@ -635,8 +629,7 @@ NODE, PARENT and BOL see `treesit-indent-function'."
"Generate name of NODE for displaying in Imenu."
(treesit-node-text node))
-;; outline-minor-mode
================================================================================
-
+;; outline-minor-mode
(defconst typst-ts-mode-outline-regexp "^[[:space:]]*\\(=+\\) "
"Regexp identifying Typst header.")
@@ -648,272 +641,6 @@ NODE, PARENT and BOL see `treesit-indent-function'."
(- (match-end 1) (match-beginning 1))
0)))
-(defun typst-ts-mode-heading--at-point-p ()
- "Whether the current line is a heading.
-Return the heading node when yes otherwise nil."
- (let ((node (treesit-node-parent
- (treesit-node-at
- (save-excursion
- (beginning-of-line-text)
- (point))))))
- (if (string= (treesit-node-type node) "heading")
- node
- nil)))
-
-;;;###autoload
-(defun typst-ts-mode-heading-up ()
- "Switch the current heading with the heading above."
- (interactive)
- (typst-ts-mode-meta--dwim 'up))
-
-;;;###autoload
-(defun typst-ts-mode-heading-down ()
- "Switch the current heading with the heading below."
- (interactive)
- (typst-ts-mode-meta--dwim 'down))
-
-;;;###autoload
-(defun typst-ts-mode-heading-increase ()
- "Increase the heading level."
- (interactive)
- (typst-ts-mode-meta--dwim 'right))
-
-;;;###autoload
-(defun typst-ts-mode-heading-decrease ()
- "Decrease heading level."
- (interactive)
- (typst-ts-mode-meta--dwim 'left))
-
-(defun typst-ts-mode-meta--dwim (direction)
- "Do something depending on the context with meta key + DIRECTION.
-`left': `typst-ts-mode-heading-decrease',
-`right': `typst-ts-mode-heading-increase',
-`up': `typst-ts-mode-heading-up',
-`down': `typst-ts-mode-heading-down'.
-When there is no relevant action to do it will execute the relevant function in
-the `GLOBAL-MAP' (example: `right-word')."
- (let ((heading (typst-ts-mode-heading--at-point-p))
- ;; car function, cdr string of function for
`substitute-command-keys'
- (call-me/string
- (pcase direction
- ('left
- (cons #'outline-promote
- "\\[typst-ts-mode-heading-decrease]"))
- ('right
- (cons #'outline-demote
- "\\[typst-ts-mode-heading-decrease]"))
- ('up
- (cons #'outline-move-subtree-up
- "\\[typst-ts-mode-heading-up]"))
- ('down
- (cons #'outline-move-subtree-down
- "\\[typst-ts-mode-heading-down]"))
- (_ (error "%s is not one of: `right' `left'" direction)))))
- (if heading
- (call-interactively (car call-me/string))
- (call-interactively
- (keymap-lookup global-map (substitute-command-keys (cdr
call-me/string)))))))
-
-(defun typst-ts-mode--item-on-line-p ()
- "Does the current line have an item node?
-Return the node when yes otherwise
-return the node that is one character left from the end of line."
- (treesit-node-parent
- (treesit-node-at
- (save-excursion
- ;; starting from the beginning because line could be 1. wow.
- (beginning-of-line)
- (condition-case nil
- (progn
- (search-forward-regexp (rx (or "+" "-" "."))
- (pos-eol)
- nil
- nil)
- (left-char))
- (search-failed
- ;; need to go to the end of line and then one left because end of
line is the next node
- (goto-char (1- (pos-eol)))))
- (point)))))
-
-(defun typst-ts-mode-meta-return (&optional arg)
- "Depending on context, insert a heading or insert an item.
-The new heading is created after the ending of current heading.
-Using ARG argument will ignore the context and it will insert a heading
instead."
- (interactive "P")
- (let ((node (typst-ts-mode--item-on-line-p)))
- (cond
- (arg (typst-ts-mode-insert--heading nil))
- ((string= (treesit-node-type node) "item")
- (typst-ts-mode-insert--item node))
- (t
- (typst-ts-mode-insert--heading node)))))
-
-(defun typst-ts-mode-return (&optional arg)
- "Handle RET depends on condition.
-When prefix ARG is non-nil, call global return function."
- (interactive "P")
- (let (execute-result node)
- (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
- (arg (throw 'execute-result 'default))
- ;; on item node end
- ((and (eolp)
- (setq node (typst-ts-mode--item-on-line-p))
- (string= (treesit-node-type node) "item")
- (not (string= (typst-ts-utils-node-get node '((child -1 nil)
(type))) "linebreak")))
- (if (> (treesit-node-child-count node) 1)
- (typst-ts-mode-insert--item node)
- ;; no text means delete the item on current line
- (beginning-of-line)
- (kill-line)
- (indent-according-to-mode))
- (throw 'execute-result 'success))
- ))))
- ;; execute default action if not successful
- (unless (eq execute-result 'success)
- (let ((global-ret-function
- (global-key-binding (kbd "RET"))))
- (if (and current-prefix-arg
- (yes-or-no-p
- (format
- "Execute function `%s' with the given prefix argument?"
- global-ret-function)))
- (call-interactively global-ret-function)
- (let ((current-prefix-arg nil))
- (call-interactively global-ret-function)))))))
-
-(defun typst-ts-mode-insert--item (node)
- "Insert an item after NODE.
-NODE must be an item node!
-This function respects indentation."
- (let* (;; +, -, or <num>.
- (item-type (treesit-node-text
- (treesit-node-child node 0)))
- (item-number (string-to-number item-type))
- (item-end (treesit-node-end node))
- (node-bol-column (typst-ts-mode-column-at-pos
- (typst-ts-mode--get-node-bol node))))
- (goto-char item-end)
- (newline)
- (indent-line-to node-bol-column)
- (insert (if (= item-number 0)
- item-type
- (concat (number-to-string (1+ item-number)) "."))
- " ")))
-
-(defun typst-ts-mode-insert--heading (node)
- "Insert a heading after the section that NODE is part of.
-When there is no section it will insert a heading below point."
- (let* ((section
- (treesit-parent-until
- node
- (lambda (node)
- (string= (treesit-node-type node) "section"))
- t))
- ;; first child is heading
- (heading (treesit-node-child section 0))
- (heading-level (treesit-node-type (treesit-node-child heading
0))))
- (if section
- (goto-char (treesit-node-end section))
- ;; no headings so far
- (setq heading-level "=")
- (forward-line 1))
- ;; something can be in the next line/section, the heading needs be on its
own line
- ;; this has to be done after `goto-char' because it will invalidate the
node
- (newline)
- (forward-line -1)
- ;; insert the heading and indent
- (insert heading-level " ")
- (indent-according-to-mode)))
-
-(defun typst-ts-mode-column-at-pos (point)
- "Get the column at position POINT."
- (save-excursion
- (goto-char point)
- (current-column)))
-
-;;;###autoload
-(defun typst-ts-mode-cycle (&optional _arg)
- "Cycle."
- (interactive "P")
- (let (execute-result)
- (setq
- execute-result
- ;; plz manually throw `\'success' to `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
- ((equal parent-node-type "raw_blck")
- (insert-tab)
- (throw 'execute-result 'success))
-
- ((or (equal cur-node-type "parbreak")
- (equal parent-node-type "item")
- ;; 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)
- (point)))
- (prev-nonwhite-pos (save-excursion
- (goto-char cur-line-bol)
- (skip-chars-backward "\s\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
- ;; TODO typst-ts-mode--get-node-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")))
- ;; TODO cycle all its children
- (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 if not successful
- (unless (eq execute-result 'success)
- (call-interactively (global-key-binding (kbd "TAB"))))))
;;;###autoload
(defun typst-ts-mode-preview (file)
@@ -1042,7 +769,7 @@ typst tree sitter grammar (at least %s)!"
(current-time-string min-time))
(typst-ts-els-merge-settings config)
;; some feature like cmake-ts-mode will create a parser when
;; the feature is required, so we need to clean thease parsers
- (mapc #'treesit-parser-delete (typst-ts-utils-parser-list nil
lang))
+ (mapc #'treesit-parser-delete (typst-ts-core-parser-list nil
lang))
(add-to-list 'typst-ts-els--include-languages lang))))
(typst-ts-mode-check-grammar-version))