Spec-Zone.ru › Elixir 1.15

Code.Fragment

Этот модуль предоставляет удобства для анализа фрагментов текстового кода и извлечения доступной информации, когда это возможно.

Этот модуль следует считать экспериментальным.

Типы

position()

Функции

container_cursor_to_quoted(fragment, opts \\ [])

Принимает строку и возвращает цитируемое выражение с позицией курсора AST внутри родительского выражения.

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()}}

Получает строку и возвращает заключённое в кавычки выражение с позицией курсора AST внутри его родительского выражения.

Эта функция получает строку с фрагментом кода Elixir, представляющим позицию курсора, и преобразует эту строку в AST с включением специального узла __cursor__() представляющего позицию курсора внутри его контейнера (т.е. его родителя).

Например, возьмём этот код, который будет дан в качестве входных данных:

max(some_value,

Эта функция вернёт эквивалент AST:

max(some_value, __cursor__())

Другими словами, эта функция способна закрыть любые открытые скобки и вставить позицию курсора. Другое содержимое в позиции курсора, которое не является родителем, отбрасывается. Например, если это задано в качестве входных данных:

max(some_value, another_val

Она вернёт тот же AST:

max(some_value, __cursor__())

Аналогично, если дано только это:

max(some_va

Тогда она возвращает:

max(__cursor__())

Вызовы без круглых скобок также поддерживаются, так как мы предполагаем, что скобки неявные.

Кортежи, списки, карты и бинарные данные сохраняют позицию курсора:

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("if(is_atom(var)")
{:ok, {:if, [line: 1], [{:__cursor__, [line: 1], []}]}}

это означает, что полные выражения сами по себе возвращают только курсор:

iex> Code.Fragment.container_cursor_to_quoted("if(is_atom(var))")
{:ok, {:__cursor__, [line: 1], []}}

Операторы также включены начиная с Elixir v1.15:

iex> Code.Fragment.container_cursor_to_quoted("foo +")
{:ok, {:+, [line: 1], [{:foo, [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()}
       | :expr,
     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} - контекст — это незаключенный в кавычки атом. Это может быть любой атом или атом, представляющий модуль

Мы рекомендуем посмотреть на набор тестов этой функции для полного списка примеров и их возвращаемых значений.

Ограничения

Анализ основан на текущем токене, анализируя последнюю строку входных данных. Например, этот код:

iex> Code.Fragment.cursor_context("%URI{")
:expr

возвращает :expr, что предполагает, что можно использовать любую переменную, локальную функцию или псевдоним. Однако, учитывая, что мы находимся внутри структуры, лучшим предложением будет поле структуры. В таких случаях вы можете использовать container_cursor_to_quoted, что вернёт контейнер AST, в котором в данный момент находится курсор. Затем вы можете проанализировать этот AST, чтобы обеспечить завершение имён полей.

Как следствие реализации на основе токенов, эта функция учитывает только последнюю строку входных данных. Это означает, что она будет показывать предложения внутри строк, 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.15.4/Code.Fragment.html

Spec-Zone.ru

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