Code.Fragment
Этот модуль предоставляет удобства для анализа фрагментов текстового кода и извлечения доступной информации, когда это возможно.
Большинство функций в этом модуле предоставляют оптимальный вариант и могут быть неточными во всех обстоятельствах. Читайте каждую документацию для получения дополнительной информации.
Этот модуль следует считать экспериментальным.
Краткое описание
Типы
Функции
- container_cursor_to_quoted(fragment, opts \\ [])
-
Принимает строку и возвращает выражение в кавычках с курсором в позиции ближайшего аргумента.
- cursor_context(fragment, opts \\ [])
-
Принимает строку и возвращает контекст курсора.
- surround_context(fragment, position, options \\ [])
-
Принимает строку и возвращает окружающий контекст.
Типы
position()Source
@type position() :: {line :: pos_integer(), column :: pos_integer()}Функции
container_cursor_to_quoted(fragment, opts \\ [])Source
@spec container_cursor_to_quoted(
List.Chars.t(),
keyword()
) ::
{:ok, Macro.t()}
| {:error, {location :: keyword(), binary() | {binary(), binary()}, binary()}}Принимает строку и возвращает выражение в кавычках с курсором в позиции ближайшего аргумента.
Эта функция получает строку с фрагментом кода Elixir, представляющим положение курсора, и преобразует эту строку в AST с включением специального __cursor__() узла на основе положения курсора с контейнером.
Контейнер — это любое выражение Elixir, начинающееся с (, {, и [. Это включает вызовы функций, кортежи, списки, карты и так далее. Например, рассмотрим этот код, который будет передан в качестве входных данных:
max(some_value,
Эта функция вернёт эквивалентный AST:
max(some_value, __cursor__())
Другими словами, эта функция способна закрыть любые открытые скобки и вставить позицию курсора. Любое содержимое в позиции курсора, что стоит после запятой или открывающей скобки, отбрасывается. Например, если в качестве входных данных предоставлен:
max(some_value, another_val
Он вернёт тот же AST:
max(some_value, __cursor__())
Аналогично, если предоставлено только это:
max(some_va
Тогда он возвращает:
max(__cursor__())
Также поддерживаются вызовы без скобок, так как мы предполагаем, что скобки являются неявными.
Операторы и анонимные функции не являются контейнерами и, следовательно, будут отброшены. Следующие все вернут тот же AST:
max(some_value, max(some_value, fn x -> x end max(some_value, 1 + another_val max(some_value, 1 |> some_fun() |> another_fun
С другой стороны, кортежи, списки, карты и двоичные данные сохраняют позицию курсора:
max(some_value, [1, 2,
Возвращает следующий AST:
max(some_value, [1, 2, __cursor__()])
Ключевые списки (и блоки do-end) также сохраняются. Следующие:
if(some_value, do: if(some_value, do: :token if(some_value, do: 1 + val
Все возвращают:
if(some_value, do: __cursor__())
Возвращаемый этой функцией AST не является безопасным для оценки, но его можно анализировать и расширять.
Примеры
Вызов функции:
iex> Code.Fragment.container_cursor_to_quoted("max(some_value, ")
{:ok, {:max, [line: 1], [{:some_value, [line: 1], nil}, {:__cursor__, [line: 1], []}]}}
Контейнеры (например, список):
iex> Code.Fragment.container_cursor_to_quoted("[some, value")
{:ok, [{:some, [line: 1], nil}, {:__cursor__, [line: 1], []}]}
Для двоичных данных :: сохраняется исключительно как оператор:
iex> Code.Fragment.container_cursor_to_quoted("<<some::integer")
{:ok, {:<<>>, [line: 1], [{:"::", [line: 1], [{:some, [line: 1], nil}, {:__cursor__, [line: 1], []}]}]}}
Параметры
:file- имя файла, которое будет сообщено в случае ошибок разбора. По умолчанию"nofile".:line- начальная строка анализируемой строки. По умолчанию 1.:column- начальный столбец анализируемой строки. По умолчанию 1.:columns- приtrue, прикрепить ключ:columnк метаданным в кавычках. По умолчаниюfalse.:token_metadata- приtrue, включает метаданные, связанные с маркерами, в выражение AST, такие как метаданные дляdoиendмаркеров, для закрывающих маркеров, конца выражений, а также разделителей для сигилов. См.Macro.metadata/0. По умолчаниюfalse.:literal_encoder- функция для кодирования литералов в AST. См. документацию дляCode.string_to_quoted/2для получения дополнительной информации.
cursor_context(fragment, opts \\ [])Source
@spec cursor_context(
List.Chars.t(),
keyword()
) ::
{:alias, charlist()}
| {:alias, inside_alias, charlist()}
| {:dot, inside_dot, charlist()}
| {:dot_arity, inside_dot, charlist()}
| {:dot_call, inside_dot, charlist()}
| :expr
| {:local_or_var, charlist()}
| {:local_arity, charlist()}
| {:local_call, charlist()}
| {:module_attribute, charlist()}
| {:operator, charlist()}
| {:operator_arity, charlist()}
| {:operator_call, charlist()}
| :none
| {:sigil, charlist()}
| {:struct, inside_struct}
| {:unquoted_atom, charlist()}
when inside_dot:
{:alias, charlist()}
| {:alias, inside_alias, charlist()}
| {:dot, inside_dot, charlist()}
| {:module_attribute, charlist()}
| {:unquoted_atom, charlist()}
| {:var, charlist()},
inside_alias: {:local_or_var, charlist()} | {:module_attribute, charlist()},
inside_struct:
charlist()
| {:alias, inside_alias, charlist()}
| {:local_or_var, charlist()}
| {:module_attribute, charlist()}
| {:dot, inside_dot, charlist()}Принимает строку и возвращает контекст курсора.
Эта функция получает строку с фрагментом кода Elixir, представляющим положение курсора, и на основе строки предоставляет контекстную информацию об этом положении. Результат этой функции затем можно использовать для предоставления подсказок, предложений и функциональности автодополнения.
Эта функция предоставляет оптимальный вариант обнаружения и может быть неточной во всех обстоятельствах. См. раздел "Ограничения" ниже.
Рассмотрите добавление обработчика по умолчанию при обработке возвращаемого типа этой функции, так как в будущих версиях могут быть добавлены новые данные о положении курсора.
Примеры
iex> Code.Fragment.cursor_context("")
:expr
iex> Code.Fragment.cursor_context("hello_wor")
{:local_or_var, 'hello_wor'}
Возвращаемые значения
{:alias, charlist}- контекст является псевдонимом, потенциально вложенным, например,Hello.WorилиHelloWor{:alias, inside_alias, charlist}- контекст является псевдонимом, потенциально вложенным, гдеinside_aliasявляется выражением{:module_attribute, charlist}или{:local_or_var, charlist}иcharlistявляется статической частью. Примеры__MODULE__.Submoduleили@hello.Submodule{:dot, inside_dot, charlist}- контекст является точкой, гдеinside_dotявляется либо{:var, charlist},{:alias, charlist},{:module_attribute, charlist},{:unquoted_atom, charlist}или самимdot. Если указана переменная, это может быть удалённый вызов или доступ к полю карты. ПримерыHello.wor,:hello.wor,hello.wor,Hello.nested.wor,hello.nested.wor, и@hello.world. Еслиcharlistпусто, аinside_dotявляется псевдонимом, то автодополнение может быть либо псевдонимом, либо удалённым вызовом.{:dot_arity, inside_dot, charlist}- контекст - арифметичность точки, гдеinside_dotявляется либо{:var, charlist},{:alias, charlist},{:module_attribute, charlist},{:unquoted_atom, charlist}или самимdot. Если указана переменная, это должен быть удалённый арифметичность. ПримерыHello.world/,:hello.world/,hello.world/2, и@hello.world/2{:dot_call, inside_dot, charlist}- контекст - вызов точки. Это означает, что после выражения были добавлены скобки или пробел. гдеinside_dotявляется либо{:var, charlist},{:alias, charlist},{:module_attribute, charlist},{:unquoted_atom, charlist}или самимdot. Если указана переменная, это должен быть удалённый вызов. ПримерыHello.world(,:hello.world(,Hello.world,hello.world(,hello.world, и@hello.world(:expr- может быть любым выражением. Автодополнение может предложить псевдоним, локальную или переменную.{:local_or_var, charlist}- контекст - переменная или локальный вызов (импорт или локальный), например,hello_wor{:local_arity, charlist}- контекст - локальный арифметичность (импорт или локальный), например,hello_world/{:local_call, charlist}- контекст - локальный вызов (импорт или локальный), например,hello_world(иhello_world{:module_attribute, charlist}- контекст - атрибут модуля, например,@hello_wor{:operator, charlist}- контекст - оператор, например,+или==. Обратите внимание, что текстовые операторы, например,when, не отображаются как операторы, а скорее как:local_or_var.@никогда не является:operatorи всегда:module_attribute{:operator_arity, charlist}- контекст - арифметичность оператора, это оператор, за которым следует /, например,+/,not/илиwhen/{:operator_call, charlist}- контекст - вызов оператора, это оператор, за которым следует пробел, например,left +,notилиx when:none- контекст невозможен{:sigil, charlist}- контекст - сигил. Это может быть либо начало сигила, например,~или~s, либо оператор, начинающийся с~, например,~>и~>>{:struct, inside_struct}- контекст - структура, например,%,%URили%URI.inside_structможет быть либоcharlistв случае статического псевдонима, либо выражение{:alias, inside_alias, charlist},{:module_attribute, charlist},{:local_or_var, charlist},{:dot, inside_dot, charlist}{:unquoted_atom, charlist}- контекст - необрамлённый атом. Это может быть любой атом или атом, представляющий модуль
Ограничения
Текущий алгоритм учитывает только последнюю строку входных данных. Это означает, что он также будет отображать предложения внутри строк, heredocs и т. д., что является намеренным, так как это помогает с doctests, ссылками и т. д.
surround_context(fragment, position, options \\ [])Source
@spec surround_context(List.Chars.t(), position(), keyword()) ::
%{begin: position(), end: position(), context: context} | :none
when context:
{:alias, charlist()}
| {:alias, inside_alias, charlist()}
| {:dot, inside_dot, charlist()}
| {:local_or_var, charlist()}
| {:local_arity, charlist()}
| {:local_call, charlist()}
| {:module_attribute, charlist()}
| {:operator, charlist()}
| {:sigil, charlist()}
| {:struct, inside_struct}
| {:unquoted_atom, charlist()}
| {:keyword, charlist()},
inside_dot:
{:alias, charlist()}
| {:alias, inside_alias, charlist()}
| {:dot, inside_dot, charlist()}
| {:module_attribute, charlist()}
| {:unquoted_atom, charlist()}
| {:var, charlist()},
inside_alias: {:local_or_var, charlist()} | {:module_attribute, charlist()},
inside_struct:
charlist()
| {:alias, inside_alias, charlist()}
| {:local_or_var, charlist()}
| {:module_attribute, charlist()}
| {:dot, inside_dot, charlist()} Принимает строку и возвращает окружающий контекст.
Эта функция получает строку с фрагментом кода Elixir и position. Она возвращает карту, содержащую начало и конец идентификатора вместе с его контекстом, или :none если нет ничего с известным контекстом.
Разница между cursor_context/2 и surround_context/3 заключается в том, что первая предполагает, что выражение во фрагменте кода неполное. Например, do в cursor_context/2 может быть ключевым словом, переменной или локальным вызовом, тогда как surround_context/3 предполагает, что выражение во фрагменте кода полное, поэтому do всегда будет ключевым словом.
position содержит как line, так и column, оба начинаются с индекса 1. Столбец должен предшествовать окружающему выражению. Например, выражение foo, вернёт что-то для столбцов 1, 2 и 3, но не для 4:
foo ^ column 1 foo ^ column 2 foo ^ column 3 foo ^ column 4
Возвращаемая карта содержит столбец, с которого начинается выражение, и первый столбец после окончания выражения.
Подобно cursor_context/2, эта функция также предоставляет определение с наилучшим результатом и может быть неточной во всех случаях. Смотрите раздел "Возвращаемые значения" и "Ограничения" в cursor_context/2 для получения дополнительной информации.
Примеры
iex> Code.Fragment.surround_context("foo", {1, 1})
%{begin: {1, 1}, context: {:local_or_var, 'foo'}, end: {1, 4}}
Отличия от cursor_context/2
Поскольку surround_context/3 работает с полным кодом, она имеет некоторые различия с cursor_context/2:
dot_call/dot_arityиoperator_call/operator_arityсвёрнуты вdotиoperatorконтексты соответственно, так как между ними нет значимых различийС другой стороны, эта функция всё ещё различает
local_call/local_arityиlocal_or_var, так как последнее может быть локальной переменной@при отсутствии последующего идентификатора возвращается как{:operator, '@'}(в отличие от{:module_attribute, ''}вcursor_context/2Эта функция никогда не возвращает пустые сигилы
{:sigil, ''}или пустые структуры{:struct, ''}в качестве контекстаЭта функция возвращает ключевые слова как
{:keyword, 'do'}Эта функция никогда не возвращает
:expr
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.14.1/Code.Fragment.html