A query is a set of patterns, written in a Lisp-like syntax.

Queries are language-specific. Different language grammars use different node types and field names. Examples in this section apply to Rust.


A pattern is an S-expression (Lisp form), optionally preceded by a field name, suffixed with a quantifier, and/or followed by a capture name.

A node form is a list form whose first element is a symbol (except for the special symbols, described later). The symbol specifies the type of node to match, while the remaining elements describe what the inner structure of a matched node (i.e. its child nodes) should look like.

;; Match any function call.

;; Match any function call where at least one arg is an identifier.
(call_expression (arguments (identifier)))

A string literal denotes an anonymous node.

;; Match the operator `==' .

Captures and Fields

Captures allow associating names with specific nodes in a pattern. A symbol starting with the character @ denotes a capture name. It is written after the pattern it refers to. When used for syntax highlighting, capture names are then mapped to display faces, which determine the appearance of the corresponding nodes.

;; Match function calls. For each match, the function name is captured
;; under the name `function.call', and the argument list is associated
;; with the name `function.args'.
 (identifier) @function.call
 (arguments) @function.args)

Certain node types assign unique field names to specific child nodes. Within a pattern, a field name is denoted by a symbol ending with the character :, written before the child pattern it refers to.

;; Using field names, for clarity.
 function: (identifier) @function.call
 arguments: (arguments) @function.args)

A symbol prefixed with the character ! denotes a negated field, which requires that the pattern matches only nodes that lack the specified field.

;; Match non-generic struct definitions.
 name: (type_identifier) @struct_name

Groups and Predicates

A group form is a list form whose first element is a node form. It is used to denote a sequence of sibling nodes, and to group predicate forms with node forms.

;; Match a comment followed by a function declaration.

A predicate form can appear anywhere in a group form. It is a list form whose first element is a symbol starting with the character .. Each remaining element is either a capture name, or a string literal.

;; Match identifiers written in SCREAMING_SNAKE_CASE.
((identifier) @constant
 (.match? @constant "^[A-Z][A-Z_\\d]+"))

Currently, the supported predicates for syntax highlighting are .match?, .not-match?, .eq? and .not-eq?.


An alternation form is a vector of patterns. It denotes a pattern that matches a node when any of the alternative patterns matches.

[(self) (super) (crate)
 (mutable_specifier)] @keyword

["==" "!=" "<" "<=" ">" ">="] @operator

 function: [(identifier) @function.call
            (field_expression field: (field_identifier) @method.call)])

Repetitions and Wildcards

A form can be suffixed by one of the quantification operators: at-most-once ?, at-least-once +, zero-or-more *.

;; Match any function call. Capture a string arg, if any.
  function: (identifier) @function.call
  arguments: (arguments (string_literal)? @the-string-arg))

The special wildcard symbol _ matches any node (except for anonymous nodes).

;; Leaving out child nodes' types, for brevity.
 function: (_) @function.call
 arguments: (_) @function.args)


The special dot symbol . denotes an anchor, which effectively “glues together” its 2 sides, disallowing any nodes in between (except for anonymous nodes).

;; A string anywhere in the argument list.
(call_expression (arguments (string_literal)))

;; 2 consecutive strings anywhere in the argument list.
(call_expression (arguments (string_literal) . (string_literal)))

;; First argument is a string.
(call_expression (arguments . (string_literal)))

;; Last argument is a string.
(call_expression (arguments (string_literal) .))

The dot symbol . is not a valid read syntax in Emacs Lisp, so it has to be escaped in query patterns embedded in code:

(tree-sitter-hl-add-patterns 'c
    function: (identifier) @keyword
    arguments: (argument_list \. (string_literal) @function))
   (.eq? @keyword "DEFUN"))])

For more details, see Tree-sitter’s documentation: