Spec-Zone.ru › Elixir 1.18

Исходный код Code.Fragment

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

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

Краткое описание

Типы

position()

Функции

container_cursor_to_quoted(fragment, opts \\ [])

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

cursor_context(fragment, opts \\ [])

Принимает строку и возвращает контекст курсора.

surround_context(fragment, position, options \\ [])

Принимает строку и возвращает окружающий контекст.

Типы

position()Исходный код

@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], []}]}}

Для правильного разбора левой части ->, которая встречается как в анонимных функциях, так и в блоках do-end, параметр trailing fragment должен быть задан вместе с остальным содержимым:

iex> Code.Fragment.container_cursor_to_quoted("fn x", trailing_fragment: " -> :ok end")
{:ok, {:fn, [line: 1], [{:->, [line: 1], [[{:__cursor__, [line: 1], []}], :ok]}]}}

Параметры

  • :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.

  • :trailing_fragment (начиная с v1.18.0) - остальная часть содержимого после курсора. Это необходимо для правильного завершения анонимных функций и левой части ->

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()}
  | {:anonymous_call, inside_caller}
  | {: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()},
     inside_caller: {:var, charlist()} | {:module_attribute, charlist()}

Получает строку и возвращает контекст курсора.

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

Эта функция выполняет свой анализ на токенах. Это означает, что она не понимает, как конструкции вложены друг в друга. См. раздел «Ограничения» ниже.

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

Примеры

iex> Code.Fragment.cursor_context("")
:expr

iex> Code.Fragment.cursor_context("hello_wor")
{:local_or_var, ~c"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

  • {:anonymous_call, inside_caller} - контекст - это анонимный вызов, например fun.( и @fun.(.

  • {: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()}
       | {:key, charlist()}
       | {:capture_arg, charlist()},
     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 и 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, ~c"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, ~c"@"} (в отличие от {:module_attribute, ~c""} в cursor_context/2

  • Эта функция никогда не возвращает пустые знаки {:sigil, ~c""} или пустые структуры {:struct, ~c""} в качестве контекста

  • Эта функция возвращает ключевые слова как {:keyword, ~c"do"}

  • Эта функция никогда не возвращает :expr

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

Скачать версию ePub

Создано с помощью ExDoc (v0.36.1) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.18.1/Code.Fragment.html

Spec-Zone.ru

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