При сборке с библиотекой 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. По умолчанию её значение равно
treesit-simple-indent. В будущем мы можем добавить другие,
более сложные движки отступов.
Эта локальная переменная хранит правила отступа для каждого языка. Она
представляет собой ассоциативный список с элементами вида (язык . правила), где язык — это символ языка, а
правила — это список с элементами вида
(сопоставитель якорь смещение).
Сначала Emacs передаёт наименьший узел tree-sitter в начале
текущей строки в сопоставитель; если он возвращает не nil, это
правило применимо. Затем Emacs передаёт узел в якорь, который
возвращает позицию в буфере. Emacs берёт номер колонки этой
позиции, добавляет к нему смещение, и результат является колонкой отступа
для текущей строки.
Сопоставитель и якорь являются функциями, и Emacs предоставляет для них удобные значения по умолчанию.
Каждый сопоставитель или якорь — это функция, принимающая три
аргумента: узел, родитель и нол. Аргумент
нол — это позиция в буфере, для которой требуется отступ:
позиция первого непробельного символа после начала строки. Аргумент
узел — это наибольший узел, который начинается в этой
позиции (и не является корневым узлом); а родитель — это родитель
узла. Однако когда эта позиция находится в пробеле или
внутри многострочной строки, ни один узел не может начинаться в этой позиции,
поэтому узел равен nil. В этом случае родитель будет
наименьшим узлом, который охватывает эту позицию.
Сопоставитель должен возвращать не nil, если правило применимо,
а якорь должен возвращать позицию в буфере.
Смещение может быть целым числом, переменной, значение которой является целым числом, или функцией, возвращающей целое число. Если это функция, ей передаются узел, родитель и нол, как сопоставителям и якорям.
Это список значений по умолчанию для сопоставителей и якорей в
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-inspect-mode (см. Грамматика языка Tree-sitter) при написании правил отступов.