24.8.2 Отступ на основе парсера

При сборке с библиотекой tree-sitter (см. Разбор исходного кода программы) Emacs способен анализировать исходный код программы и строить синтаксическое дерево. Это синтаксическое дерево можно использовать для управления командами отступа исходного кода программы. Для максимальной гибкости можно написать собственную функцию отступа, которая запрашивает синтаксическое дерево и соответственно выставляет отступ для каждого языка, но это требует большой работы. Удобнее использовать простой движок отступов, описанный ниже: тогда основному режиму нужно лишь написать несколько правил отступа, а движок позаботится об остальном.

Чтобы включить движок отступов на основе парсера, установите либо treesit-simple-indent-rules, либо treesit-indent-function, затем вызовите treesit-major-mode-setup. (Всё, что делает treesit-major-mode-setup — это устанавливает значение indent-line-function в treesit-indent и indent-region-function в treesit-indent-region.)

Переменная: treesit-indent-function

Эта переменная хранит фактическую функцию, вызываемую treesit-indent. По умолчанию её значение равно treesit-simple-indent. В будущем мы можем добавить другие, более сложные движки отступов.

Написание правил отступов

Переменная: treesit-simple-indent-rules

Эта локальная переменная хранит правила отступа для каждого языка. Она представляет собой ассоциативный список с элементами вида (язык . правила), где язык — это символ языка, а правила — это список с элементами вида (сопоставитель якорь смещение).

Сначала Emacs передаёт наименьший узел tree-sitter в начале текущей строки в сопоставитель; если он возвращает не nil, это правило применимо. Затем Emacs передаёт узел в якорь, который возвращает позицию в буфере. Emacs берёт номер колонки этой позиции, добавляет к нему смещение, и результат является колонкой отступа для текущей строки.

Сопоставитель и якорь являются функциями, и Emacs предоставляет для них удобные значения по умолчанию.

Каждый сопоставитель или якорь — это функция, принимающая три аргумента: узел, родитель и нол. Аргумент нол — это позиция в буфере, для которой требуется отступ: позиция первого непробельного символа после начала строки. Аргумент узел — это наибольший узел, который начинается в этой позиции (и не является корневым узлом); а родитель — это родитель узла. Однако когда эта позиция находится в пробеле или внутри многострочной строки, ни один узел не может начинаться в этой позиции, поэтому узел равен nil. В этом случае родитель будет наименьшим узлом, который охватывает эту позицию.

Сопоставитель должен возвращать не nil, если правило применимо, а якорь должен возвращать позицию в буфере.

Смещение может быть целым числом, переменной, значение которой является целым числом, или функцией, возвращающей целое число. Если это функция, ей передаются узел, родитель и нол, как сопоставителям и якорям.

Переменная: treesit-simple-indent-presets

Это список значений по умолчанию для сопоставителей и якорей в treesit-simple-indent-rules. Каждый из них представляет функцию, принимающую 3 аргумента: узел, родитель и нол. Доступные стандартные функции:

no-node

Этот сопоставитель — функция, вызываемая с 3 аргументами: узел, родитель и нол. Он возвращает не nil, указывая на совпадение, если узел равен nil, то есть нет узла, который начинается в нол. Это бывает, когда нол находится на пустой строке или внутри многострочной строки и т.п.

parent-is

Этот сопоставитель — функция одного аргумента, тип; он возвращает функцию, вызываемую с 3 аргументами: узел, родитель и нол, и возвращает не nil (т.е. совпадение), если тип родителя соответствует регулярному выражению тип.

node-is

Этот сопоставитель — функция одного аргумента, тип; он возвращает функцию, вызываемую с 3 аргументами: узел, родитель и нол, и возвращает не nil, если тип узла соответствует регулярному выражению тип.

field-is

Этот сопоставитель — функция одного аргумента, имя; он возвращает функцию, вызываемую с 3 аргументами: узел, родитель и нол, и возвращает не nil, если имя поля узла в родителе соответствует регулярному выражению имя.

query

Этот сопоставитель — функция одного аргумента, запрос; он возвращает функцию, вызываемую с 3 аргументами: узел, родитель и нол, и возвращает не nil, если запрос к родителю с запросом захватывает узел (см. Сопоставление с образцом для узлов Tree-sitter).

match

Этот сопоставитель — функция 5 аргументов: тип-узла, тип-родителя, поле-узла, мин-индекс-узла и макс-индекс-узла). Он возвращает функцию, вызываемую с 3 аргументами: узел, родитель и нол, и возвращает не nil, если тип узла соответствует регулярному выражению тип-узла, тип родителя соответствует регулярному выражению тип-родителя, имя поля узла в родителе соответствует регулярному выражению поле-узла, и индекс узла среди его сиблингов находится между мин-индекс-узла и макс-индекс-узла. Если значение аргумента равно nil, этот сопоставитель не проверяет этот аргумент. Например, чтобы сопоставить первого потомка, где родитель — argument_list, используйте

(match nil "argument_list" nil 0 0)

Кроме того, тип-узла может иметь специальное значение null, которое соответствует случаю, когда значение узла равно nil.

n-p-gp

Сокращение от «узел-родитель-прародитель», этот сопоставитель — функция 3 аргументов: тип-узла, тип-родителя и тип-прародителя. Он возвращает функцию, вызываемую с 3 аргументами: узел, родитель и нол, и возвращает не nil, если: (1) тип-узла соответствует типу узла, и (2) тип-родителя соответствует типу родителя, и (3) тип-прародителя соответствует типу родителя родителя. Если любой из тип-узла, тип-родителя и тип-прародителя равен nil, эта функция не проверяет соответствующий аргумент.

comment-end

Этот сопоставитель — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает не nil, если точка находится перед токеном, завершающим комментарий. Токены, завершающие комментарий, определяются регулярным выражением comment-end-skip.

catch-all

Этот сопоставитель — функция, вызываемая с 3 аргументами: узел, родитель и нол. Он всегда возвращает не nil, указывая на совпадение.

first-sibling

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает начало первого потомка родителя.

nth-sibling

Этот якорь — функция двух аргументов: n и необязательного аргумента именованный. Он возвращает функцию, вызываемую с 3 аргументами: узел, родитель и нол, и возвращает начало n-го потомка родителя. Если именованный не равен nil, учитываются только именованные потомки (см. именованный узел).

parent

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает начало родителя.

grand-parent

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает начало родителя родителя.

great-grand-parent

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает начало родителя родителя родителя.

parent-bol

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает первый непробельный символ на строке, на которой находится начало родителя.

standalone-parent

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол. Он находит первый узел-предок (родитель, прародитель и т.д.) узла, который начинается на своей собственной строке, и возвращает начало этого узла. «Начинается на своей собственной строке» означает, что перед узлом на строке, на которой находится начало узла, есть только пробельные символы.

prev-sibling

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает начало предыдущего сиблинга узла.

no-indent

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает начало узла.

prev-line

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает первый непробельный символ на предыдущей строке.

column-0

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает начало текущей строки, которое находится в колонке 0.

comment-start

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол, и возвращает позицию после токена начала комментария. Токены начала комментария определяются регулярным выражением comment-start-skip. Эта функция предполагает, что родитель является узлом комментария.

prev-adaptive-prefix

Этот якорь — функция, вызываемая с 3 аргументами: узел, родитель и нол. Он пытается сопоставить adaptive-fill-regexp с текстом в начале предыдущей непустой строки. При совпадении эта функция возвращает конец совпадения, в противном случае возвращает nil. Однако если текущая строка начинается с префикса (например, «-»), возвращает начало префикса предыдущей строки, чтобы оба префикса выровнялись. Этот якорь полезен для поведения отступа, аналогичного indent-relative, для блочных комментариев.

Утилиты отступов

Ниже приведены некоторые вспомогательные функции, которые могут помочь при написании правил отступов на основе парсера.

Команда: treesit-check-indent режим

Эта команда проверяет отступ текущего буфера по основному режиму режим. Она расставляет отступы в текущем буфере согласно режиму и сравнивает результаты с текущими отступами. Затем она показывает буфер с различиями. Правильный отступ (целевой) показан зелёным цветом, текущий отступ показан красным цветом.

Также полезно использовать treesit-inspect-mode (см. Грамматика языка Tree-sitter) при написании правил отступов.