Next: , Previous: , Up: Parsing Program Source   [Contents][Index]

38.6 User-defined “Things” and Navigation

It’s often useful to be able to identify and find certain things in a buffer, like function and class definitions, statements, code blocks, strings, comments, etc. Emacs allows users to define what kind of tree-sitter node corresponds to a “thing”. This enables handy features like jumping to the next function, marking the code block at point, or transposing two function arguments.

The “things” feature in Emacs is independent of the pattern matching feature of tree-sitter, and comparatively less powerful, but more suitable for navigation and traversing the parse tree.

You can define things with treesit-thing-settings, retrieve the predicate of a defined thing with treesit-thing-definition, and test if a thing is defined with treesit-thing-defined-p.

Variable: treesit-thing-settings

This is an alist of thing definitions for each language. The key of each entry is a language symbol, and the value is a list of thing definitions of the form (thing pred), where thing is a symbol representing the thing, like defun, sexp, or sentence; and pred specifies what kind of tree-sitter node is this thing.

pred can be a regexp string that matches the type of the node; it can be a function that takes a node as the argument and returns a boolean that indicates whether the node qualifies as the thing; or it can be a cons (regexp . fn), which is a combination of a regular expression regexp and a function fn—the node has to match both the regexp and to satisfy fn to qualify as the thing.

pred can also be recursively defined. It can be (or pred…), meaning that satisfying any one of the preds qualifies the node as the thing. It can be (not pred), meaning that not satisfying pred qualifies the node.

Finally, pred can refer to other things defined in this list. For example, (or sexp sentence) defines something that’s either a sexp thing or a sentence thing, as defined by some other rule in the alist.

Here’s an example treesit-thing-settings for C and C++:

((c
  (defun "function_definition")
  (sexp (not "[](),[{}]"))
  (comment "comment")
  (string "raw_string_literal")
  (text (or comment string)))
 (cpp
  (defun ("function_definition" . cpp-ts-mode-defun-valid-p))
  (defclass "class_specifier")
  (comment "comment")))

Note that this example is modified for didactic purposes, and isn’t exactly how C and C++ modes define things.

Emacs builtin functions already make use some thing definitions. Command treesit-forward-sexp uses the sexp definition if major mode defines it; treesit-forward-sentence uses the sentence definition. Defun movement functions like treesit-end-of-defun uses the defun definition (defun definition is overridden by treesit-defun-type-regexp for backward compatibility). Major modes can also define comment, string, text (generally comments and strings).

The rest of this section lists a few functions that take advantage of the thing definitions. Besides the functions below, some other functions listed elsewhere also utilize the thing feature, e.g., tree-traversing functions like treesit-search-forward, treesit-induce-sparse-tree, etc. See Retrieving Nodes.

Function: treesit-node-match-p node thing &optional ignore-missing

This function checks whether node is a thing.

If node is a thing, return non-nil, otherwise return nil. For convenience, if node is nil, this function just returns nil.

The thing can be either a thing symbol like defun, or simply a predicate that defines a thing, like "function_definition", or (or comment string).

By default, if thing is undefined or malformed, this function signals treesit-invalid-predicate error. If ignore-missing is t, this function doesn’t signal the error when thing is undefined and just returns nil; but it still signals the error if thing is a malformed predicate.

Function: treesit-thing-prev position thing

This function returns the first node before position that is the specified thing. If no such node exists, it returns nil. It’s guaranteed that, if a node is returned, the node’s end position is less or equal to position. In other words, this function never returns a node that encloses position.

Again, thing can be either a symbol or a predicate.

Function: treesit-thing-next position thing

This function is similar to treesit-thing-prev, only it returns the first node after position that’s the thing. It also guarantees that if a node is returned, the node’s start position is greater or equal to position.

Function: treesit-navigate-thing position arg side thing &optional tactic

This function builds upon treesit-thing-prev and treesit-thing-next and provides functionality that a navigation command would find useful. It returns the position after moving across arg instances of thing from position. If there aren’t enough things to navigate across, it returns nil. The function doesn’t move point.

A positive arg means moving forward that many instances of thing; negative arg means moving backward. If side is beg, this function stops at the beginning of thing; if end, stop at the end of thing.

Like in treesit-thing-prev, thing can be a thing symbol defined in treesit-thing-settings, or a predicate.

tactic determines how this function moves between things. It can be nested, top-level, restricted, or nil. nested or nil means normal nested navigation: first try to move across siblings; if there aren’t any siblings left in the current level, move to the parent, then its siblings, and so on. top-level means only navigate across top-level things and ignore nested things. restricted means movement is restricted within the thing that encloses position, if there is such a thing. This tactic is useful for commands that want to stop at the current nesting level and not move up.

Function: treesit-thing-at position thing &optional strict

This function returns the smallest node that’s the thing and encloses position; if there’s no such node, it returns nil.

The returned node must enclose position, i.e., its start position is less or equal to position, and it’s end position is greater or equal to position.

If strict is non-nil, this function uses strict comparison, i.e., start position must be strictly greater than position, and end position must be strictly less than position.

thing can be either a thing symbol defined in treesit-thing-settings, or a predicate.

There are also some convenient wrapper functions. treesit-beginning-of-thing moves point to the beginning of a thing, treesit-end-of-thing moves to the end of a thing, and treesit-thing-at-point returns the thing at point.

There are also defun commands that specifically use the defun definition (as a fallback of treesit-defun-type-regexp), like treesit-beginning-of-defun, treesit-end-of-defun, and treesit-defun-at-point. In addition, these functions use treesit-defun-tactic as the navigation tactic. They are described in more detail in other sections (see Developing major modes with tree-sitter).

Next: Parsing Text in Multiple Languages, Previous: Pattern Matching Tree-sitter Nodes, Up: Parsing Program Source   [Contents][Index]