Отступы на основе синтаксического анализатора
При сборке с библиотекой 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
-
Эта локальная переменная хранит правила отступов для каждого языка. Это список элементов вида
(language rule…), где language — символ языка, а каждый rule — это либо список с элементами вида(matcher anchor offset), либо функция.Ниже сначала описан вариант со списком, а затем — вариант с функцией.
Сначала Emacs передаёт узел tree-sitter наименьшего размера в начале текущей строки функции matcher; если она возвращает значение, отличное от
nil, это правило применимо. Затем Emacs передаёт узел функции anchor, которая возвращает позицию в буфере. Emacs берёт номер столбца этой позиции, прибавляет к нему offset, и результат становится столбцом отступа для текущей строки.matcher и anchor — это функции, для которых Emacs предоставляет удобные значения по умолчанию.
Каждая функция matcher или anchor принимает три аргумента: node, parent и bol. Аргумент bol — это позиция в буфере, для которой требуется определить отступ: позиция первого символа, отличного от пробела, после начала строки. Аргумент node — это самый большой узел, начинающийся в этой позиции (и не являющийся корневым узлом); parent — родительский узел для node. Однако, если эта позиция находится в пробельном символе или внутри многострочной строки, в ней не может начинаться узел, поэтому node равен
nil. В этом случае parent будет наименьшим узлом, охватывающим эту позицию.Функция matcher должна возвращать значение, отличное от
nil, если правило применимо, а функция anchor должна возвращать позицию в буфере.offset может быть целым числом, переменной, значение которой является целым числом, или функцией, возвращающей целое число. Если это функция, ей передаются аргументы node, parent и bol, как и функциям сопоставления и привязки.
Если rule — функция, она удобна в сложных случаях, когда правило должно совместно учитывать условие сопоставления и привязку. Функции rule передаются те же аргументы, что и функции matcher: node, parent и bol. Если условие выполнено, rule должна возвращать cons
(anchor-pos . offset), где anchor-pos — позиция в буфере, а offset — смещение отступа. Если условие для rule не выполнено, она должна возвращатьnil.
- Переменная: treesit-simple-indent-presets
-
Это список значений по умолчанию для функций matcher и anchor в
treesit-simple-indent-rules. Каждое из них представляет собой функцию, принимающую 3 аргумента: node, parent и bol. Доступны следующие функции по умолчанию:-
no-node -
Это функция сопоставления, принимающая 3 аргумента: node, parent и bol. Она возвращает значение, отличное от
nil, указывая на совпадение, если node равенnil, то есть в позиции bol нет начинающегося узла. Это происходит, когда bol находится на пустой строке или внутри многострочной строки и т. п. -
parent-is -
Эта функция сопоставления принимает один аргумент — type; она возвращает функцию, принимающую 3 аргумента: node, parent и bol и возвращающую значение, отличное от
nil(то есть указывающее на совпадение), если тип parent соответствует регулярному выражению type. -
node-is -
Эта функция сопоставления принимает один аргумент — type; она возвращает функцию, принимающую 3 аргумента: node, parent и bol и возвращающую значение, отличное от
nil, если тип node соответствует регулярному выражению type. -
field-is -
Эта функция сопоставления принимает один аргумент — name; она возвращает функцию, принимающую 3 аргумента: node, parent и bol и возвращающую значение, отличное от
nil, если имя поля node в parent соответствует регулярному выражению name. -
query -
Эта функция сопоставления принимает один аргумент — query; она возвращает функцию, принимающую 3 аргумента: node, parent и bol и возвращающую значение, отличное от
nil, если запрос к parent с помощью query захватывает node (см. раздел Сопоставление с образцом узлов Tree-sitter). -
match -
Эта функция сопоставления принимает 5 аргументов: node-type, parent-type, node-field, node-index-min и node-index-max). Она возвращает функцию, принимающую 3 аргумента: node, parent и bol и возвращающую значение, отличное от
nil, если тип node соответствует регулярному выражению node-type, тип parent соответствует регулярному выражению parent-type, имя поля node в parent соответствует регулярному выражению node-field, а индекс node среди соседних узлов находится в диапазоне от node-index-min до node-index-max. Если значением аргумента являетсяnil, эта функция сопоставления не проверяет соответствующий аргумент. Например, чтобы сопоставить первый дочерний узел, у которого родитель равенargument_list, используйте(match nil "argument_list" nil 0 0)
Кроме того, node-type может принимать специальное значение
null, которое соответствует случаю, когда значение node равноnil. -
n-p-gp -
Сокращение от «узел-родитель-прародитель»; эта функция сопоставления принимает 3 аргумента: node-type, parent-type и grandparent-type. Она возвращает функцию, принимающую 3 аргумента: node, parent и bol и возвращающую значение, отличное от
nil, если: (1) node-type соответствует типу node, (2) parent-type соответствует типу parent и (3) grandparent-type соответствует типу родителя parent. Если для любого из аргументов node-type, parent-type и grandparent-type задано значениеnil, эта функция не проверяет его. -
comment-end -
Это функция сопоставления, принимающая 3 аргумента: node, parent и bol и возвращающая значение, отличное от
nil, если позиция находится перед токеном завершения комментария. Токены завершения комментария задаются регулярным выражениемcomment-end-skip. -
catch-all -
Это функция сопоставления, принимающая 3 аргумента: node, parent и bol. Она всегда возвращает значение, отличное от
nil, указывая на совпадение. -
first-sibling -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает начало первого дочернего узла parent.
-
nth-sibling -
Эта функция привязки принимает два аргумента: n и необязательный аргумент named. Она возвращает функцию, принимающую 3 аргумента: node, parent и bol и возвращающую начало n-го дочернего узла parent. Если named не равно
nil, учитываются только именованные дочерние узлы (см. раздел именованный узел). -
parent -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает начало parent.
-
grand-parent -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает начало родителя parent.
-
great-grand-parent -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает начало родителя родителя parent.
-
parent-bol -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает первый символ, отличный от пробела, в строке, на которой начинается parent.
-
standalone-parent -
Эта функция привязки принимает 3 аргумента: node, parent и bol. Она находит первый узел-предок (родителя, прародителя и т. д.) node, который начинается на отдельной строке, и возвращает начало этого узла. «Начинаться на отдельной строке» означает, что перед узлом в строке, на которой он начинается, есть только пробельные символы. Точное определение выражения «начинаться на отдельной строке» можно сделать менее строгим, задав
treesit-simple-indent-standalone-predicate; некоторым основным режимам это может понадобиться, чтобы упростить отступы при цепочечных вызовах методов. -
prev-sibling -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает начало предыдущего соседнего узла node.
-
no-indent -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает начало node.
-
prev-line -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает первый символ, отличный от пробельного, в предыдущей строке.
-
column-0 -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает начало текущей строки, то есть столбец 0.
-
comment-start -
Эта функция привязки принимает 3 аргумента: node, parent и bol и возвращает позицию после токена начала комментария. Токены начала комментария задаются регулярным выражением
comment-start-skip. Эта функция предполагает, что parent — это узел комментария. -
prev-adaptive-prefix -
Эта функция привязки принимает 3 аргумента: node, parent и bol. Она пытается сопоставить
adaptive-fill-regexpс текстом в начале предыдущей непустой строки. При совпадении эта функция возвращает конец совпадения, в противном случае она возвращаетnil. Однако, если текущая строка начинается с префикса (например, «-»), вместо этого возвращается начало префикса предыдущей строки, чтобы выровнять оба префикса. Эта привязка полезна для поведения отступов, подобногоindent-relative, в блочных комментариях.
-
Вспомогательные средства для отступов
Ниже приведены некоторые вспомогательные функции, которые могут помочь при написании правил отступов на основе синтаксического анализатора.
- Команда: treesit-check-indent mode
Эта команда проверяет отступы в текущем буфере на соответствие основному режиму mode. Она задаёт отступы в текущем буфере согласно mode и сравнивает полученный результат с текущими отступами. Затем она открывает буфер с различиями. Правильные отступы (целевые) отображаются зелёным цветом, текущие — красным.
При написании правил отступов также полезно использовать treesit-inspect-mode (см. раздел Грамматика языка Tree-sitter).
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Parser_002dbased-Indentation.html