diff options
| author | Yuan Fu | 2022-10-28 17:54:43 -0700 |
|---|---|---|
| committer | Yuan Fu | 2022-10-28 17:54:43 -0700 |
| commit | 0c7a7df98e1fb0bc156707b379e4147fac97359a (patch) | |
| tree | ef517530077b515034b38833e7014623988b710c | |
| parent | 434fc2a22e4fd65fd63018e9373cbf56b51f8ab2 (diff) | |
| download | emacs-0c7a7df98e1fb0bc156707b379e4147fac97359a.tar.gz emacs-0c7a7df98e1fb0bc156707b379e4147fac97359a.zip | |
Add treesit-indent-region
Now indenting a large buffer is reasonably fast.
* lisp/treesit.el (treesit-indent): Move meat to treesit--indent-1.
(treesit--indent-1)
(treesit-indent-region): New functions.
(treesit-major-mode-setup): Setup indent-region-function.
| -rw-r--r-- | lisp/treesit.el | 79 |
1 files changed, 65 insertions, 14 deletions
diff --git a/lisp/treesit.el b/lisp/treesit.el index f1440412028..9c4d4535342 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el | |||
| @@ -922,11 +922,13 @@ is a point (not a node), and OFFSET is a number. Emacs finds the | |||
| 922 | column of ANCHOR and adds OFFSET to it as the final indentation | 922 | column of ANCHOR and adds OFFSET to it as the final indentation |
| 923 | of the current line.") | 923 | of the current line.") |
| 924 | 924 | ||
| 925 | (defun treesit-indent () | 925 | (defun treesit--indent-1 () |
| 926 | "Indent according to the result of `treesit-indent-function'." | 926 | "Indent the current line. |
| 927 | (treesit-update-ranges) | 927 | Return the column we should indent this line to, or nil if we |
| 928 | (let* ((orig-pos (point)) | 928 | can't figure it out. This function is used by `treesit-indent' |
| 929 | (bol (save-excursion | 929 | and `treesit-indent-region'." |
| 930 | ;; Basically holds the common part between the two indent function. | ||
| 931 | (let* ((bol (save-excursion | ||
| 930 | (forward-line 0) | 932 | (forward-line 0) |
| 931 | (skip-chars-forward " \t") | 933 | (skip-chars-forward " \t") |
| 932 | (point))) | 934 | (point))) |
| @@ -957,14 +959,62 @@ of the current line.") | |||
| 957 | (funcall treesit-indent-function node parent bol))) | 959 | (funcall treesit-indent-function node parent bol))) |
| 958 | (if (or (null anchor) (null offset)) | 960 | (if (or (null anchor) (null offset)) |
| 959 | nil | 961 | nil |
| 960 | (let ((col (+ (save-excursion | 962 | (+ (save-excursion |
| 961 | (goto-char anchor) | 963 | (goto-char anchor) |
| 962 | (current-column)) | 964 | (current-column)) |
| 963 | offset))) | 965 | offset))))) |
| 964 | (if (< bol orig-pos) | 966 | |
| 965 | (save-excursion | 967 | (defun treesit-indent () |
| 966 | (indent-line-to col)) | 968 | "Indent according to the result of `treesit-indent-function'." |
| 967 | (indent-line-to col))))))) | 969 | (treesit-update-ranges) |
| 970 | (let* ((orig-pos (point)) | ||
| 971 | (bol (current-indentation)) | ||
| 972 | (col (treesit--indent-1))) | ||
| 973 | (when col | ||
| 974 | (if (< bol orig-pos) | ||
| 975 | (save-excursion | ||
| 976 | (indent-line-to col)) | ||
| 977 | (indent-line-to col))))) | ||
| 978 | |||
| 979 | (defvar treesit--indent-region-batch-size 1000 | ||
| 980 | "How many lines of indent value do we precompute. | ||
| 981 | In `treesit-indent-region' we indent in batches: precompute | ||
| 982 | indent for each line, apply them in one go, let parser reparse, | ||
| 983 | and do it again. This way the parser don't need to unnecessarily | ||
| 984 | reparse after indenting every single line.") | ||
| 985 | |||
| 986 | (defun treesit-indent-region (beg end) | ||
| 987 | "Indent the region between BEG and END. | ||
| 988 | Similar to `treesit-indent', but indent a region instead." | ||
| 989 | (treesit-update-ranges) | ||
| 990 | (let ((indents (make-vector treesit--indent-region-batch-size 0)) | ||
| 991 | (lines-left-to-move 0) | ||
| 992 | (idx 0) | ||
| 993 | (jdx 0) | ||
| 994 | (starting-pos 0) | ||
| 995 | (announce-progress (> (- end beg) 80000))) | ||
| 996 | (save-excursion | ||
| 997 | (goto-char beg) | ||
| 998 | (while (and (eq lines-left-to-move 0) (< (point) end)) | ||
| 999 | (setq idx 0 jdx 0 | ||
| 1000 | starting-pos (point)) | ||
| 1001 | (while (and (eq lines-left-to-move 0) | ||
| 1002 | (< idx treesit--indent-region-batch-size) | ||
| 1003 | (< (point) end)) | ||
| 1004 | (setf (aref indents idx) (or (treesit--indent-1) 0)) | ||
| 1005 | (cl-incf idx) | ||
| 1006 | (setq lines-left-to-move (forward-line 1))) | ||
| 1007 | ;; Now IDX = last valid IDX + 1. | ||
| 1008 | (goto-char starting-pos) | ||
| 1009 | (while (< jdx idx) | ||
| 1010 | (let ((col (aref indents jdx))) | ||
| 1011 | (when (not (eq col 0)) | ||
| 1012 | (indent-line-to col))) | ||
| 1013 | (forward-line 1) | ||
| 1014 | (cl-incf jdx)) | ||
| 1015 | (when announce-progress | ||
| 1016 | (message "Indenting region...%s%%" | ||
| 1017 | (/ (* (- (point) beg) 100) (- end beg)))))))) | ||
| 968 | 1018 | ||
| 969 | (defun treesit-simple-indent (node parent bol) | 1019 | (defun treesit-simple-indent (node parent bol) |
| 970 | "Calculate indentation according to `treesit-simple-indent-rules'. | 1020 | "Calculate indentation according to `treesit-simple-indent-rules'. |
| @@ -1235,7 +1285,8 @@ If `treesit-defun-type-regexp' is non-nil, setup | |||
| 1235 | (treesit-font-lock-recompute-features)) | 1285 | (treesit-font-lock-recompute-features)) |
| 1236 | ;; Indent. | 1286 | ;; Indent. |
| 1237 | (when treesit-simple-indent-rules | 1287 | (when treesit-simple-indent-rules |
| 1238 | (setq-local indent-line-function #'treesit-indent)) | 1288 | (setq-local indent-line-function #'treesit-indent) |
| 1289 | (setq-local indent-region-function #'treesit-indent-region)) | ||
| 1239 | ;; Navigation. | 1290 | ;; Navigation. |
| 1240 | (when treesit-defun-type-regexp | 1291 | (when treesit-defun-type-regexp |
| 1241 | (setq-local beginning-of-defun-function #'treesit-beginning-of-defun) | 1292 | (setq-local beginning-of-defun-function #'treesit-beginning-of-defun) |