branch: elpa/typst-ts-mode commit e2309a468c5f7212c0ce0ca53e3cfb45a4f93c8d Author: meowking <mr.meowk...@tutamail.com> Commit: meowking <mr.meowk...@tutamail.com>
fix: typst-ts-mode-cycle --- typst-ts-core.el | 35 +++++++++++++- typst-ts-editing.el | 136 +++++++++++++++++++++++++--------------------------- 2 files changed, 97 insertions(+), 74 deletions(-) diff --git a/typst-ts-core.el b/typst-ts-core.el index 52ae4108fe..b89c16b8e1 100644 --- a/typst-ts-core.el +++ b/typst-ts-core.el @@ -69,14 +69,45 @@ POS. May return nil." (typst-ts-core-get-node-at-bol-nonwhite pos))) (defun typst-ts-core-for-lines-covered-by-node (node fn) + "Execute FN on all lines covere by NODE. +Currently the effect of FN shouldn't change line number." (let ((ns (treesit-node-start node)) - (ne (treesit-node-end node))) + ;; use line number not position since when editing, position of node end + ;; changes, but the information is not updated + (ne-line-num (line-number-at-pos (treesit-node-end node)))) (save-excursion (goto-char ns) - (while (and (< (point) ne) (not (eobp))) + (while (<= (line-number-at-pos) ne-line-num) (funcall fn) (forward-line 1))))) + +;; Emacs 29 doesn't support string type PRED, so this function is created for +;; convenience +(defun typst-ts-core-parent-util-type (node type include-node) + "See `treesit-parent-until'. +TYPE is an regexp expression for matching types. +NODE TYPE INCLUDE-NODE." + (treesit-parent-until + node + (lambda (node) + (string-match-p type (treesit-node-type node))) + include-node)) + +(defun typst-ts-core-prev-sibling-ignore-types (node types) + "Find previous sibling node ignoring nodes whose type matches TYPES. +NODE: current node. +TYPES is an regexp expression." + (let* ((prev-node (treesit-node-prev-sibling node)) + (prev-node-type (treesit-node-type prev-node))) + (while (and prev-node-type + (string-match-p types prev-node-type)) + (message "%s" prev-node) + (setq + prev-node (treesit-node-prev-sibling prev-node) + prev-node-type (treesit-node-type prev-node))) + prev-node)) + (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." diff --git a/typst-ts-editing.el b/typst-ts-editing.el index 922439e990..e7d9056dcb 100644 --- a/typst-ts-editing.el +++ b/typst-ts-editing.el @@ -210,10 +210,25 @@ When there is no section it will insert a heading below point." (insert heading-level " ") (indent-according-to-mode))) +(defun typst-ts-editing--indent-item-node-lines (node offset) + (let ((item-node-min-column + (typst-ts-core-column-at-pos + (typst-ts-core-line-bol-pos + (treesit-node-start node))))) + (if (< (+ item-node-min-column offset) 0) + (setq offset (- item-node-min-column))) + (typst-ts-core-for-lines-covered-by-node + node + (lambda () + (indent-line-to + (+ (typst-ts-core-column-at-pos + (typst-ts-core-line-bol-pos)) + offset)))))) + (defun typst-ts-mode-cycle (&optional _arg) "Cycle." (interactive "P") - (let (execute-result) + (let (execute-result node) (setq execute-result ;; plz manually throw `\'success' to `execute-result' @@ -221,6 +236,10 @@ When there is no section it will insert a heading below point." (when-let* ((cur-pos (point)) (cur-node (treesit-node-at cur-pos)) (cur-node-type (treesit-node-type cur-node)) + (cur-line-nonwhite-bol-node + (typst-ts-core-get-node-at-bol-nonwhite)) + (cur-line-nonwhite-bol-node-type + (treesit-node-type cur-line-nonwhite-bol-node)) (parent-node (treesit-node-parent cur-node)) ; could be nil (parent-node-type (treesit-node-type parent-node))) (cond @@ -228,78 +247,51 @@ When there is no section it will insert a heading below point." (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-top-node - (treesit-node-parent - (treesit-node-at prev-nonwhite-line-bol))) - (cur-line-bol-column (typst-ts-core-column-at-pos cur-line-bol)) - (prev-nonwhite-line-top-node-start-column - (typst-ts-core-column-at-pos - (treesit-node-start prev-nonwhite-line-top-node)))) - (cond - ;; 1. el - ;; 2. psy| <- can toggle indent (of all its descendant nodes) - ((and - (equal (treesit-node-type prev-nonwhite-line-top-node) "item") - ;; previous nonwhite-line ending is not '\' character - (not (equal (treesit-node-type prev-nonwhite-line-node) "linebreak"))) - (let* ((cur-line-top-node - (typst-ts-core-get-parent-of-node-at-bol-nonwhite)) - (cur-line-top-node-start-column - (typst-ts-core-column-at-pos - (treesit-node-start cur-line-top-node))) - (offset - (- cur-line-top-node-start-column - prev-nonwhite-line-top-node-start-column))) - (if (= offset 0) - (typst-ts-core-for-lines-covered-by-node - cur-line-top-node - (lambda () - (let ((pos (point))) - (indent-line-to - (+ (typst-ts-core-column-at-pos - (typst-ts-core-line-bol-pos)) - typst-ts-mode-indent-offset)) - ;; (goto-char (+ typst-ts-mode-indent-offset point)) - ))) - (typst-ts-core-for-lines-covered-by-node - cur-line-top-node - (lambda () - (let ((pos (point))) - (indent-line-to - (max (- (typst-ts-core-column-at-pos - (typst-ts-core-line-bol-pos)) - offset) - 0)) - ;; (goto-char (- pos typst-ts-mode-indent-offset)) - ))))) - (throw 'execute-result 'success) - )))) + ((setq node + (typst-ts-core-parent-util-type + cur-line-nonwhite-bol-node "item" t)) + (let* ((cur-item-node node) + (prev-significant-node + (typst-ts-core-prev-sibling-ignore-types + cur-item-node + "parbreak")) + (prev-significant-node-type + (treesit-node-type prev-significant-node)) + prev-item-node) + + (if (equal prev-significant-node-type "item") + (setq prev-item-node prev-significant-node) + (if (equal + "item" + (treesit-node-type + (treesit-node-parent prev-significant-node))) + (setq prev-item-node (treesit-node-parent + prev-significant-node)))) + + ;; (message "%s, %s" cur-item-node prev-item-node) + + (unless prev-item-node + (throw 'execute-result 'default)) + + (let* ((cur-item-node-start-column + (typst-ts-core-column-at-pos + (treesit-node-start cur-item-node))) + (prev-item-node-start-column + (typst-ts-core-column-at-pos + (treesit-node-start prev-item-node))) + (offset + (- cur-item-node-start-column + prev-item-node-start-column))) + (if (>= offset typst-ts-mode-indent-offset) + (typst-ts-editing--indent-item-node-lines + cur-item-node + (- (+ offset typst-ts-mode-indent-offset))) + (typst-ts-editing--indent-item-node-lines + cur-item-node + (- typst-ts-mode-indent-offset (abs offset))))) + )) + (t nil))))) ;; execute default action if not successful (unless (eq execute-result 'success)