Spec-Zone.ru › Elisp

Отступы на основе синтаксического анализатора

При сборке с библиотекой 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API