Customization

Theming

tree-sitter-hl-mode provides a richer set of faces than font-lock-mode. For example, function definitions are highlighted with tree-sitter-hl-face:function, while function calls are highlighted with tree-sitter-hl-face:function.call. However, for compatibility with existing themes, the default values for most of these faces inherit from built-in font-lock faces.

If you want to leverage the full power of Tree-sitter’s syntax highlighting approach, you should customize these faces.

Face Mappings

By default, when the highlighting query associates a node with CAPTURE-NAME, it will be highlighted with the face tree-sitter-hl-face:CAPTURE-NAME. This behavior can be changed by customizing the variable tree-sitter-hl-face-mapping-function.

;; Don't highlight strings, in any language.
(add-function :before-while tree-sitter-hl-face-mapping-function
  (lambda (capture-name)
    (not (string= capture-name "string"))))
;; Highlight only keywords in Python.
(add-hook 'python-mode-hook
  (lambda ()
    (add-function :before-while (local 'tree-sitter-hl-face-mapping-function)
      (lambda (capture-name)
	(string= capture-name "keyword")))))
;; Highlight Python docstrings with a different face.
(add-hook 'python-mode-hook
  (lambda ()
    (add-function :before-until (local 'tree-sitter-hl-face-mapping-function)
      (lambda (capture-name)
	(pcase capture-name
	  ("doc" 'font-lock-comment-face))))))

Additional Patterns

You can use the function tree-sitter-hl-add-patterns to add custom highlighting patterns for a specific language, or in a buffer. These patterns will be prioritized over patterns defined by major modes or language bundles (tree-sitter-hl-default-patterns). Below are some examples:

Language-specific patterns:

;; Highlight Python's single-quoted strings as constants.
(tree-sitter-hl-add-patterns 'python
  [((string) @constant
    (.match? @constant "^'"))])

Buffer-local patterns:

;; Map @rust.unsafe.use capture to a custom face.
(add-function :before-until tree-sitter-hl-face-mapping-function
  (lambda (capture-name)
    (pcase capture-name
      ("rust.unsafe.use" 'my-dangerous-code-pattern-face))))

;; Add highlighting patterns for @rust.unsafe.use.
(add-hook 'rust-mode-hook
  (lambda ()
    (tree-sitter-hl-add-patterns nil
      [(unsafe_block) @rust.unsafe.use
       (impl_item "unsafe") @rust.unsafe.use])))

Project-specific patterns (through .dir-locals.el):

;; Highlight DEFUN macros (in Emacs's C source).
((c-mode . ((tree-sitter-hl--extra-patterns-list
	     [((call_expression
		function: (identifier) @keyword
		arguments: (argument_list
			    (string_literal) @function))
	       (.eq? @keyword "DEFUN"))]))))

When a node matches multiple patterns in a highlighting query, earlier patterns are prioritized.

;; More specific patterns should be written earlier.
((lifetime (identifier) @type.builtin)
 (.eq? @type.builtin "static"))
(lifetime (identifier) @label)