Last active
July 26, 2026 05:23
-
-
Save bjourne/63ffea0c420bf84104c3f98ca1623ea6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (defconst my/container-fields | |
| '(("if_statement" . "consequence") | |
| ("case_statement" . nil) | |
| ("compound_statement" .nil) | |
| ("else_clause" . nil) | |
| ("for_statement" . "body") | |
| ("while_statement" . "body"))) | |
| (defconst my/container-types | |
| (map-keys my/container-fields)) | |
| (defun my/preproc-node-p (node) | |
| (string-prefix-p "preproc" (treesit-node-type node))) | |
| (defun my/empty-container (node) | |
| (when-let* ((type (treesit-node-type node)) | |
| (field (cdr (assoc type my/container-fields))) | |
| (body (treesit-node-child-by-field-name node field))) | |
| (zerop (- (treesit-node-end body) (treesit-node-start body))))) | |
| ;; Nearest non-preprocessor sibling. | |
| (defun my/c-prev-sibling (node) | |
| (let ((s (treesit-node-prev-sibling node))) | |
| (if (my/preproc-node-p s) | |
| (my/c-prev-sibling s) | |
| s))) | |
| ;; Sibling is the actual C parent if it is an empty container and | |
| ;; there is a macro in the way. | |
| (defun my/sibling-is-parent (node sibling) | |
| (and | |
| sibling | |
| (member (treesit-node-type sibling) my/container-types) | |
| (my/empty-container sibling) | |
| (or (string-match-p "preproc_if" | |
| (treesit-node-type node)) | |
| (string-match-p "preproc_def" | |
| (treesit-node-type | |
| (treesit-node-prev-sibling node)))))) | |
| (defun my/c-parent (node) | |
| (let ((sibl (my/c-prev-sibling node))) | |
| (if (my/sibling-is-parent node sibl) | |
| sibl | |
| (let ((parent (treesit-node-parent node))) | |
| (if (my/preproc-node-p parent) | |
| (my/c-parent parent) | |
| parent))))) | |
| ;; Figures out what the C parent of a node is by walking the tree | |
| ;; upwards. It ignores preprocessor macros and tree-sitter parser | |
| ;; errors. | |
| (defun my/c-parent2 (node parent) | |
| (let ((c-par (if node (my/c-parent node) parent))) | |
| (message "c-parent of %s is %s" node c-par) | |
| c-par)) | |
| ;; True if the actual parent is a container | |
| (defun my/c-parent-is-container (node parent &rest _) | |
| (member (treesit-node-type (my/c-parent2 node parent)) | |
| my/container-types)) | |
| (defun my/c-parent-is (type) | |
| (lambda (node parent &rest _) | |
| (when-let* ((c-par (my/c-parent2 node parent))) | |
| (string-match-p type (treesit-node-type c-par))))) | |
| ;; Indentation of node's C parent. | |
| (defun my/c-parent-bol (node parent &rest _) | |
| (save-excursion | |
| (let ((c-par (my/c-parent2 node parent))) | |
| (goto-char (treesit-node-start c-par)) | |
| (back-to-indentation) | |
| (point)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment