aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYuan Fu2022-10-29 09:04:35 -0700
committerYuan Fu2022-10-29 09:09:09 -0700
commitbde8e87cb7b3be0e0bc9e72c3634f108570cac3e (patch)
tree76b52c4dacc6fa49106c37535e4b0f7a9c42515f
parent4552b01d8c8052f607dca2fcddcf7b2e270f1db6 (diff)
downloademacs-bde8e87cb7b3be0e0bc9e72c3634f108570cac3e.tar.gz
emacs-bde8e87cb7b3be0e0bc9e72c3634f108570cac3e.zip
Fix treesit-indent-region
* lisp/treesit.el (treesit-simple-indent-presets): Remove extra comma. (treesit--indent-1): Return (ANCHOR . OFFSET) instead of column. (treesit-indent): Accept (ANCHOR . OFFSET) from treesit--indent-1. (treesit--indent-region-batch-size): Reduce to 400. (treesit-indent-region): Put a marker on each line's ANCHOR and compute the indentation with ANCHOR + OFFSET. Precomputing column gives wrong indentation when the ANHOR line doesn't have correct indent yet.
-rw-r--r--lisp/treesit.el103
1 files changed, 63 insertions, 40 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 264935f1854..22d1fe5f89b 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -724,10 +724,10 @@ See `treesit-simple-indent-presets'.")
724 (and (or (null node-t) 724 (and (or (null node-t)
725 (string-match-p 725 (string-match-p
726 node-t (or (treesit-node-type node) ""))) 726 node-t (or (treesit-node-type node) "")))
727 (or (null ,parent-t) 727 (or (null parent-t)
728 (string-match-p 728 (string-match-p
729 parent-t (treesit-node-type parent))) 729 parent-t (treesit-node-type parent)))
730 (or (null ,grand-parent-t) 730 (or (null grand-parent-t)
731 (string-match-p 731 (string-match-p
732 grand-parent-t 732 grand-parent-t
733 (treesit-node-type 733 (treesit-node-type
@@ -941,9 +941,8 @@ of the current line.")
941 941
942(defun treesit--indent-1 () 942(defun treesit--indent-1 ()
943 "Indent the current line. 943 "Indent the current line.
944Return the column we should indent this line to, or nil if we 944Return (ANCHOR . OFFSET). This function is used by
945can't figure it out. This function is used by `treesit-indent' 945`treesit-indent' and `treesit-indent-region'."
946and `treesit-indent-region'."
947 ;; Basically holds the common part between the two indent function. 946 ;; Basically holds the common part between the two indent function.
948 (let* ((bol (save-excursion 947 (let* ((bol (save-excursion
949 (forward-line 0) 948 (forward-line 0)
@@ -960,7 +959,7 @@ and `treesit-indent-region'."
960 smallest-node 959 smallest-node
961 (lambda (node) 960 (lambda (node)
962 (eq bol (treesit-node-start node)))))) 961 (eq bol (treesit-node-start node))))))
963 (pcase-let* 962 (let*
964 ((parser (if smallest-node 963 ((parser (if smallest-node
965 (treesit-node-parser smallest-node) 964 (treesit-node-parser smallest-node)
966 nil)) 965 nil))
@@ -971,29 +970,26 @@ and `treesit-indent-region'."
971 (treesit-node-parent node)) 970 (treesit-node-parent node))
972 (parser 971 (parser
973 (treesit-node-at bol parser)) 972 (treesit-node-at bol parser))
974 (t nil))) 973 (t nil))))
975 (`(,anchor . ,offset) 974 (funcall treesit-indent-function node parent bol))))
976 (funcall treesit-indent-function node parent bol)))
977 (if (or (null anchor) (null offset))
978 nil
979 (+ (save-excursion
980 (goto-char anchor)
981 (current-column))
982 offset)))))
983 975
984(defun treesit-indent () 976(defun treesit-indent ()
985 "Indent according to the result of `treesit-indent-function'." 977 "Indent according to the result of `treesit-indent-function'."
986 (treesit-update-ranges) 978 (treesit-update-ranges)
987 (let* ((orig-pos (point)) 979 (pcase-let* ((orig-pos (point))
988 (bol (current-indentation)) 980 (bol (current-indentation))
989 (col (treesit--indent-1))) 981 (`(,anchor . ,offset) (treesit--indent-1)))
990 (when col 982 (when (and anchor offset)
991 (if (< bol orig-pos) 983 (let ((col (+ (save-excursion
992 (save-excursion 984 (goto-char anchor)
993 (indent-line-to col)) 985 (current-column))
994 (indent-line-to col))))) 986 offset)))
995 987 (if (< bol orig-pos)
996(defvar treesit--indent-region-batch-size 1000 988 (save-excursion
989 (indent-line-to col))
990 (indent-line-to col))))))
991
992(defvar treesit--indent-region-batch-size 400
997 "How many lines of indent value do we precompute. 993 "How many lines of indent value do we precompute.
998In `treesit-indent-region' we indent in batches: precompute 994In `treesit-indent-region' we indent in batches: precompute
999indent for each line, apply them in one go, let parser reparse, 995indent for each line, apply them in one go, let parser reparse,
@@ -1004,34 +1000,61 @@ reparse after indenting every single line.")
1004 "Indent the region between BEG and END. 1000 "Indent the region between BEG and END.
1005Similar to `treesit-indent', but indent a region instead." 1001Similar to `treesit-indent', but indent a region instead."
1006 (treesit-update-ranges) 1002 (treesit-update-ranges)
1007 (let ((indents (make-vector treesit--indent-region-batch-size 0)) 1003 (let* ((meta-len 2)
1008 (lines-left-to-move 0) 1004 (vector-len (* meta-len treesit--indent-region-batch-size))
1009 (idx 0) 1005 ;; This vector saves the indent meta for each line in the
1010 (jdx 0) 1006 ;; batch. It is a vector of [ANCHOR OFFSET BOL DELTA], where
1011 (starting-pos 0) 1007 ;; BOL is the position of BOL of that line, and DELTA =
1012 (announce-progress (> (- end beg) 80000))) 1008 ;; DESIRED-INDENT - CURRENT-INDENT.
1009 (meta-vec (make-vector vector-len 0))
1010 (lines-left-to-move 0)
1011 (end (copy-marker end t))
1012 (idx 0)
1013 (starting-pos 0)
1014 (announce-progress (> (- end beg) 80000)))
1013 (save-excursion 1015 (save-excursion
1014 (goto-char beg) 1016 (goto-char beg)
1017 ;; First pass. Go through each line and compute the
1018 ;; indentation.
1015 (while (and (eq lines-left-to-move 0) (< (point) end)) 1019 (while (and (eq lines-left-to-move 0) (< (point) end))
1016 (setq idx 0 jdx 0 1020 (setq idx 0
1017 starting-pos (point)) 1021 starting-pos (point))
1018 (while (and (eq lines-left-to-move 0) 1022 (while (and (eq lines-left-to-move 0)
1019 (< idx treesit--indent-region-batch-size) 1023 (< idx treesit--indent-region-batch-size)
1020 (< (point) end)) 1024 (< (point) end))
1021 (setf (aref indents idx) (or (treesit--indent-1) 0)) 1025 (pcase-let* ((`(,anchor . ,offset) (treesit--indent-1))
1026 (marker (aref meta-vec (* idx meta-len))))
1027 ;; Set ANCHOR.
1028 (when anchor
1029 (if (markerp marker)
1030 (move-marker marker anchor)
1031 (setf (aref meta-vec (* idx meta-len))
1032 (copy-marker anchor t))))
1033 ;; SET OFFSET.
1034 (setf (aref meta-vec (+ 1 (* idx meta-len))) offset))
1022 (cl-incf idx) 1035 (cl-incf idx)
1023 (setq lines-left-to-move (forward-line 1))) 1036 (setq lines-left-to-move (forward-line 1)))
1024 ;; Now IDX = last valid IDX + 1. 1037 ;; Now IDX = last valid IDX + 1.
1025 (goto-char starting-pos) 1038 (goto-char starting-pos)
1026 (while (< jdx idx) 1039 ;; Second pass, go to each line and apply the indentation.
1027 (let ((col (aref indents jdx))) 1040 (dotimes (jdx idx)
1028 (when (not (eq col 0)) 1041 (let ((anchor (aref meta-vec (* jdx meta-len)))
1029 (indent-line-to col))) 1042 (offset (aref meta-vec (+ 1 (* jdx meta-len)))))
1030 (forward-line 1) 1043 (when offset
1031 (cl-incf jdx)) 1044 (let ((col (save-excursion
1045 (goto-char anchor)
1046 (+ offset (current-column)))))
1047 (indent-line-to col))))
1048 (forward-line 1))
1032 (when announce-progress 1049 (when announce-progress
1033 (message "Indenting region...%s%%" 1050 (message "Indenting region...%s%%"
1034 (/ (* (- (point) beg) 100) (- end beg)))))))) 1051 (/ (* (- (point) beg) 100) (- end beg)))))
1052 ;; Delete markers.
1053 (dotimes (idx treesit--indent-region-batch-size)
1054 (let ((marker (aref meta-vec (* idx meta-len))))
1055 (when (markerp marker)
1056 (move-marker marker nil))))
1057 (move-marker end nil))))
1035 1058
1036(defun treesit-simple-indent (node parent bol) 1059(defun treesit-simple-indent (node parent bol)
1037 "Calculate indentation according to `treesit-simple-indent-rules'. 1060 "Calculate indentation according to `treesit-simple-indent-rules'.