-
-
Notifications
You must be signed in to change notification settings - Fork 12
Description
The current fold method used for folding blocks in python-ts-mode is a generic method which folds the entire function it is located in. For example consider the below code:

- When point is on the for loop line, if I fold, this is what I get

... because the default fold method fold's at the enclosing method or enclosing class level, not at the block level.
- If I try try to fold the first if block under the for loop,

Again the entire method is folded.

I cannot fold the outer if block either.
The ideal behavior would be to fold just that code block. This can be achieved by using a custom fold method for blocks in python-ts-mode (code given at the end).
AFTER
After setting up a custom fold method for blocks in the python-ts-mode, if my point is on the for loop and then when I fold the code..

Only the for loop block is folded.

I can also fold any individual if/else/elif blocks as I like.

This is how I setup a custom method to fold blocks in python:
(defun my/treesit-fold-range-python-block (node offset)
"Define fold range for `if_statement` and other blocks in python.
For arguments NODE and OFFSET, see function `treesit-fold-range-seq' for
more information."
(when-let* ((colon-node (car (treesit-fold-find-children node ":")))
(beg (treesit-node-start colon-node)))
(let ((current-node (treesit-node-next-sibling colon-node))
(last-body-node nil)
(end nil))
;; Iterate through siblings until we hit an elif or else clause
(while (and current-node
(not (member (treesit-node-type current-node)
'("elif_clause" "else_clause"))))
;; Only consider non-comment nodes as body nodes
(unless (string-match-p "comment" (treesit-node-type current-node))
(setq last-body-node current-node))
(setq current-node (treesit-node-next-sibling current-node)))
;; Set end position based on the last body node or fallback to node end
(setq end (if last-body-node
(treesit-node-end last-body-node)
(treesit-node-end node)))
;; Return the range and offset to fold
(treesit-fold--cons-add (cons (+ beg 1) end) offset))))
(defun my/treesit-fold-parsers-python ()
(append
(treesit-fold-parsers-python)
(mapcar (lambda (keyword) (cons keyword 'my/treesit-fold-range-python-block))
'(while_statement for_statement if_statement elif_clause else_clause
match_statement case_clause try_statement except_clause with_statement))))
;; python mode
(setq treesit-fold-range-alist (assq-delete-all 'python-mode treesit-fold-range-alist))
(setq treesit-fold-range-alist (assq-delete-all 'python-ts-mode treesit-fold-range-alist))
(add-to-list 'treesit-fold-range-alist `(python-ts-mode . ,(my/treesit-fold-parsers-python)))
(add-to-list 'treesit-fold-range-alist `(python-mode . ,(my/treesit-fold-parsers-python)))
Not sure it can be added into the core since everyone's folding preferences are different. If it makes sense, then I can raise a PR for the same.
Otherwise, this issue migh help people who are searching for.