Spec-Zone.ru › Elisp

Пользовательские «сущности» и навигация

Часто бывает полезно иметь возможность распознавать и находить в буфере определённые сущности, например определения функций и классов, операторы, блоки кода, строки, комментарии и т. д., используя типы узлов, определённые грамматикой tree-sitter, применяемой в буфере. Emacs позволяет программам на Lisp определять, каким видам узлов tree-sitter соответствуют те или иные «сущности». Это позволяет реализовать удобные возможности, например переход к следующей функции, выделение блока кода в точке, перестановку двух аргументов функции и т. д.

Возможность работы с «сущностями» в Emacs не зависит от механизма сопоставления с образцом tree-sitter (см. Сопоставление узлов tree-sitter с образцом) и сравнительно менее мощная, но лучше подходит для навигации и перемещения по тексту буфера в соответствии с деревом разбора tree-sitter.

Вы можете определять сущности с помощью treesit-thing-settings, получать предикат определённой сущности с помощью treesit-thing-definition и проверять, определена ли сущность, с помощью treesit-thing-defined-p.

Переменная: treesit-thing-settings

Это список определений сущностей для каждого языка, поддерживаемого грамматикой, используемой в буфере; он должен задаваться основным режимом буфера (значение по умолчанию — nil). Ключ каждой записи — символ языка (например, c для C, cpp для C++ и т. д.), а значение — список определений сущностей в форме (thing pred), где thing — символ, представляющий сущность, а pred задаёт виды узлов tree-sitter, считающиеся этой thing.

Символ, используемый для определения thing, может быть любым осмысленным для основного режима символом: defun, defclass, sentence, comment, string и т. д. Для поддержки команд навигации на основе tree-sitter (см. Перемещение по сбалансированным выражениям) режим должен определять две сущности: list и sexp.

pred может быть строкой регулярного выражения, соответствующей типу узла; функцией, которая принимает узел в качестве аргумента и возвращает логическое значение, указывающее, соответствует ли узел сущности; или конструкцией cons (regexp . fn), сочетающей регулярное выражение regexp и функцию fn: чтобы узел соответствовал сущности, он должен соответствовать regexp и удовлетворять условию fn.

pred также может задаваться рекурсивно. Это может быть (or pred…), что означает: узел соответствует сущности, если удовлетворяет хотя бы одному из pred. Это может быть (and pred…), что означает: узел соответствует сущности, если удовлетворяет всем pred. Это может быть (not pred), что означает: узел соответствует сущности, если не удовлетворяет условию pred.

Наконец, pred может ссылаться на другие thing, определённые в этом списке. Например, (or sexp sentence) определяет сущность, которая является либо сущностью sexp, либо сущностью sentence, как задано другими правилами в списке ассоциаций.

Есть два предопределённых предиката: named и anonymous, которым соответствуют именованные и анонимные узлы грамматики tree-sitter соответственно. Их можно комбинировать с and, чтобы сузить область сопоставления.

Вот пример treesit-thing-settings для C и C++:

((c
  (defun "function_definition")
  (sexp (not "[](),[{}]"))
  (comment "comment")
  (string "raw_string_literal")
  (text (or comment string)))
 (cpp
  (defun ("function_definition" . cpp-ts-mode-defun-valid-p))
  (defclass "class_specifier")
  (comment "comment")))

Обратите внимание, что этот пример изменён в учебных целях и не полностью соответствует тому, как режимы C и C++ на основе tree-sitter определяют сущности.

Встроенные функции Emacs уже используют некоторые определения сущностей. Команда treesit-forward-sexp использует определение sexp, если оно задано основным режимом (см. Перемещение по сбалансированным выражениям); treesit-forward-list, treesit-down-list, treesit-up-list, treesit-show-paren-data используют определение list (его символ list имеет свойство символа treesit-thing-symbol, чтобы избежать неоднозначности с одноимённой функцией); treesit-forward-sentence использует определение sentence. Функции перемещения по defun, такие как treesit-end-of-defun, используют определение defun (определение defun переопределяется переменной treesit-defun-type-regexp для обратной совместимости). Основные режимы также могут определять сущности comment, string и text (для сопоставления с комментариями и строками).

В оставшейся части этого раздела перечислены некоторые функции, использующие определения сущностей. Помимо приведённых ниже функций, возможность работы с сущностями применяют и некоторые функции, описанные в других разделах, например функции обхода дерева treesit-search-forward, treesit-induce-sparse-tree и т. д. См. Получение узлов.

Функция: treesit-node-match-p node thing &optional ignore-missing

Эта функция проверяет, представляет ли node сущность thing.

Если node представляет thing, функция возвращает значение, отличное от nil; в противном случае она возвращает nil. Для удобства, если node равно nil, функция просто возвращает nil.

thing может быть либо символом сущности, например defun, либо просто предикатом, определяющим сущность, например "function_definition" или (or comment string).

По умолчанию, если thing не определена или имеет неправильный формат, эта функция сигнализирует об ошибке treesit-invalid-predicate. Если ignore-missing равно t, функция не сигнализирует об ошибке, когда thing не определена, а просто возвращает nil; однако она по-прежнему сигнализирует об ошибке, если предикат thing имеет неправильный формат.

Следующие функции предназначены для поиска сущностей и перемещения по ним; они должны учитывать, что буфер иногда содержит несколько соседних или вложенных парсеров. По умолчанию эти функции стараются быть полезными и выполняют поиск во всех подходящих парсерах в точке, от наиболее конкретного (самого глубоко вложенного) к наименее конкретному. При использовании этих функций в качестве строительных блоков других функций программам на Lisp следует внимательно оценить, желаемо ли такое поведение; если нет, нужно явно передать парсер или язык.

Функция: treesit-thing-prev position thing &optional parser

Эта функция возвращает первый узел перед position в текущем буфере, соответствующий указанной сущности thing. Если такого узла нет, она возвращает nil.

Гарантируется, что если узел возвращён, его конечная позиция меньше или равна position. Иными словами, эта функция никогда не возвращает узел, охватывающий position.

И снова, thing может быть либо символом, либо предикатом.

Если parser не равен nil, используется только дерево разбора этого парсера. В противном случае функция перебирает все парсеры, охватывающие точку, от наиболее конкретного (самого глубоко вложенного) к наименее конкретному. Если в position есть несколько парсеров с одинаковым уровнем вложенности (см. parser-embed-level), порядок их перебора не определён. Если parser — символ языка, функция ограничивает поиск парсерами этого языка.

Функция: treesit-thing-next position thing &optional parser

Эта функция похожа на treesit-thing-prev, но возвращает первый узел после position, соответствующий сущности thing. Также гарантируется, что если узел возвращён, его начальная позиция больше или равна position. Параметр parser такой же, как в treesit-thing-prev.

Функция: treesit-navigate-thing position arg side thing &optional tactic

Эта функция основана на treesit-thing-prev и treesit-thing-next и предоставляет возможности, полезные для команд навигации. Она возвращает позицию после перемещения через arg экземпляров сущности thing от position. Если сущностей для перемещения недостаточно, функция возвращает nil. Точка не перемещается.

Положительное значение arg означает перемещение вперёд через указанное число экземпляров thing; отрицательное значение arg означает перемещение назад. Если side равно beg, функция возвращает позицию в начале thing; если оно равно end, возвращается позиция в конце thing.

Как и в treesit-thing-prev, thing может быть символом сущности, определённым в treesit-thing-settings, или предикатом, а parser может быть nil, парсером или символом языка. Как и в той функции, parser определяет, в каких парсерах или языках выполняется поиск. Если доступно несколько парсеров, функция перебирает их, пока не добьётся успеха.

tactic определяет способ перемещения функции между сущностями. Это может быть nested, top-level, restricted, parent-first или nil. nested или nil означает обычную навигацию по вложенным сущностям: сначала выполняется попытка перемещения по соседним элементам; если на текущем уровне соседних элементов больше нет, выполняется переход к родительскому элементу, затем к его соседним элементам и так далее. top-level означает перемещение только по сущностям верхнего уровня с игнорированием вложенных сущностей. restricted означает, что перемещение ограничено сущностью, охватывающей position, если такая имеется. Эта тактика полезна для команд, которым нужно остановиться на текущем уровне вложенности и не переходить вверх. parent-first означает переход к родительскому элементу, если он есть, и перемещение по соседним элементам, если родительского элемента нет.

Функция: treesit-thing-at position thing &optional strict parser

Эта функция возвращает наименьший узел, соответствующий сущности thing и охватывающий position; если такого узла нет, она возвращает nil.

Возвращённый узел должен охватывать position, то есть его начальная позиция должна быть меньше или равна position, а конечная позиция должна быть больше или равна position.

Если strict не равен nil, функция использует строгое сравнение: начальная позиция должна быть строго меньше position, а конечная — строго больше position.

thing может быть либо символом сущности, определённым в treesit-thing-settings, либо предикатом.

Если parser не равен nil, используется только дерево разбора этого парсера. В противном случае функция перебирает все парсеры, охватывающие точку, от наиболее конкретного (самого глубоко вложенного) к наименее конкретному. Если в position есть несколько парсеров с одинаковым уровнем вложенности (см. parser-embed-level), порядок их перебора не определён. parser также может быть символом языка.

Есть также несколько удобных функций-обёрток. treesit-beginning-of-thing перемещает точку в начало сущности, treesit-end-of-thing — в её конец, а treesit-thing-at-point возвращает сущность в точке.

Существуют также команды defun, использующие именно определение defun (как запасной вариант для treesit-defun-type-regexp), например treesit-beginning-of-defun, treesit-end-of-defun и treesit-defun-at-point. Кроме того, эти функции используют treesit-defun-tactic в качестве тактики навигации. Они подробнее описаны в других разделах (см. Разработка основных режимов с помощью 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/User_002ddefined-Things.html

Spec-Zone.ru

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