Skip to content

Instantly share code, notes, and snippets.

@bjourne
Last active July 26, 2026 05:23
Show Gist options
  • Select an option

  • Save bjourne/63ffea0c420bf84104c3f98ca1623ea6 to your computer and use it in GitHub Desktop.

Select an option

Save bjourne/63ffea0c420bf84104c3f98ca1623ea6 to your computer and use it in GitHub Desktop.
(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