Igniter.Code.Common (igniter v0.2.0)

General purpose utilities for working with Sourceror.Zipper.

Summary

Functions

Adds the provided code to the zipper.

Expands the environment at the current zipper position and returns the expanded environment. Currently used for properly working with aliases.

Enters a block, and moves to the first child, or returns the zipper unmodified.

Enters a block with a single child, and moves to that child, or returns the zipper unmodified

Moves right in the zipper, until the provided predicate returns true.

Moves to the next node that matches the predicate.

Matches and moves to the location of a __cursor__ in provided source code.

Moves to the cursor that matches the provided pattern or one of the provided patterns, in the current scope.

Moves to a do block for the current call.

Moves to the next node that matches the given pattern.

Returns true if the current node matches the given pattern.

Moves the zipper right n times, returning :error if it can't move that many times.

Runs the function fun on the subtree of the currently focused node and returns the updated zipper.

Functions

Link to this function

add_code(zipper, new_code, placement \\ :after)

@spec add_code(Sourceror.Zipper.t(), String.t() | Macro.t(), :after | :before) ::
  Sourceror.Zipper.t()

Adds the provided code to the zipper.

Use placement to determine if the code goes :after or :before the current node.

Example:

existing_zipper = """
IO.inspect("Hello, world!")
"""
|> Sourceror.parse_string!()
|> Sourceror.Zipper.zip()

new_code = """
IO.inspect("Goodbye, world!")
"""

existing_zipper
|> Igniter.Common.add_code(new_code)
|> Sourceror.Zipper.root()
|> Sourceror.to_string()

Which will produce

"""
IO.inspect("Hello, world!")
IO.inspect("Goodbye, world!")
"""
Link to this function

current_env(zipper)

Expands the environment at the current zipper position and returns the expanded environment. Currently used for properly working with aliases.

Link to this function

expand_aliases(zipper)

@spec expand_aliases(Sourceror.Zipper.t()) :: Sourceror.Zipper.t()
Link to this function

maybe_move_to_block(zipper)

@spec maybe_move_to_block(Sourceror.Zipper.t()) :: Sourceror.Zipper.t()

Enters a block, and moves to the first child, or returns the zipper unmodified.

Link to this function

maybe_move_to_single_child_block(zipper)

@spec maybe_move_to_single_child_block(Sourceror.Zipper.t()) :: Sourceror.Zipper.t()

Enters a block with a single child, and moves to that child, or returns the zipper unmodified

Link to this function

move_right(zipper, pred)

@spec move_right(Sourceror.Zipper.t(), (Sourceror.Zipper.t() -> boolean())) ::
  {:ok, Sourceror.Zipper.t()} | :error

Moves right in the zipper, until the provided predicate returns true.

Returns :error if the end is reached without finding a match.

Link to this function

move_to(zipper, pred)

@spec move_to(Sourceror.Zipper.t(), (Sourceror.Zipper.tree() -> Sourceror.Zipper.t())) ::
  {:ok, Sourceror.Zipper.t()} | :error

Moves to the next node that matches the predicate.

Link to this function

move_to_cursor(zipper, pattern)

@spec move_to_cursor(Sourceror.Zipper.t(), Sourceror.Zipper.t() | String.t()) ::
  {:ok, Sourceror.Zipper.t()} | :error

Matches and moves to the location of a __cursor__ in provided source code.

Use __cursor__() to match a cursor in the provided source code. Use __ to skip any code at a point.

For example:

zipper =
  """
  if true do
    10
  end
  """
  |> Sourceror.Zipper.zip()

pattern =
  """
  if __ do
    __cursor__
  end
  """

zipper
|> Igniter.Code.Common.move_to_cursor(pattern)
|> Zipper.subtree()
|> Zipper.node()
# => 10
Link to this function

move_to_cursor_match_in_scope(zipper, patterns)

@spec move_to_cursor_match_in_scope(Sourceror.Zipper.t(), String.t() | [String.t()]) ::
  {:ok, Sourceror.Zipper.t()} | :error

Moves to the cursor that matches the provided pattern or one of the provided patterns, in the current scope.

See move_to_cursor/2 for an example of a pattern

Link to this function

move_to_do_block(zipper)

@spec move_to_do_block(Sourceror.Zipper.t()) :: {:ok, Sourceror.Zipper.t()} | :error

Moves to a do block for the current call.

For example, at a node like:

foo do
  10
end

You would get a zipper back at 10.

Link to this macro

move_to_pattern(zipper, pattern)

(macro)

Moves to the next node that matches the given pattern.

Link to this macro

node_matches_pattern?(zipper, pattern)

(macro)

Returns true if the current node matches the given pattern.

Examples:

list_zipper =
  "[1, 2, 3]"
  |> Sourceror.parse_string!()
  |> Sourceror.Zipper.zip()

Common.node_matches_pattern?(list_zipper, value when is_list(value)) # true
Link to this function

nodes_equal?(left, right)

@spec nodes_equal?(Sourceror.Zipper.t() | Macro.t(), Macro.t()) :: boolean()
Link to this function

nth_right(zipper, n)

@spec nth_right(Sourceror.Zipper.t(), non_neg_integer()) ::
  {:ok, Sourceror.Zipper.t()} | :error

Moves the zipper right n times, returning :error if it can't move that many times.

Link to this function

replace_code(zipper, code)

Link to this function

use_aliases(new_code, current_code)

Link to this function

within(top_zipper, fun)

Runs the function fun on the subtree of the currently focused node and returns the updated zipper.

fun must return {:ok, zipper} or :error, which may be positioned at the top of the subtree.