View Source Igniter.Code.Common (igniter v0.4.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.

Expands a literal value using the env at the cursor, if possible

Returns a list of zippers to each node that satisfies the predicate function, or an empty list if none are found.

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 a zipper to the left.

Moves nextwards (depth-first), until the provided predicate returns true.

Moves a zipper to the right.

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.

Moves to the next zipper that matches the predicate.

Moves a zipper upwards.

Moves to the last node before the node that matches the predicate, going upwards.

Returns true if the current node matches the given pattern.

Removes any nodes matching the provided pattern, until there are no matches left.

Removes all nodes matching the given predicate with the given function.

Moves the zipper all the way to the right, potentially entering a single value block.

Updates all nodes matching the given predicate with the given function.

Replaces full module names in new_code with any aliases for that module found in the current_code environment.

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)

View Source
@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!")
"""

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

@spec expand_alias(Sourceror.Zipper.t()) :: Sourceror.Zipper.t()
@spec expand_aliases(Sourceror.Zipper.t()) :: Sourceror.Zipper.t()
@spec expand_literal(Sourceror.Zipper.t()) :: {:ok, any()} | :error

Expands a literal value using the env at the cursor, if possible

Link to this function

find_all(zipper, predicate)

View Source
@spec find_all(Sourceror.Zipper.t(), predicate :: (Sourceror.Zipper.t() -> boolean())) ::
  [
    Sourceror.Zipper.t()
  ]

Returns a list of zippers to each node that satisfies the predicate function, or an empty list if none are found.

The optional second parameters specifies the direction, defaults to :next.

Link to this function

maybe_move_to_block(zipper)

View Source
@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)

View Source
@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_left(zipper, pred_or_n)

View Source
@spec move_left(
  Sourceror.Zipper.t(),
  non_neg_integer() | (Sourceror.Zipper.t() -> boolean())
) ::
  {:ok, Sourceror.Zipper.t()} | :error

Moves a zipper to the left.

If the second argument is a predicate function, it will be called on the zipper and then move leftwards until the predicate returns true. This function will automatically enter and exit blocks.

If the second argument is a non-negative integer, it will move left that many times if possible, returning :error otherwise.

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

Moves nextwards (depth-first), until the provided predicate returns true.

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

Link to this function

move_right(zipper, pred_or_n)

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

Moves a zipper to the right.

If the second argument is a predicate function, it will be called on the zipper and then move rightwards until the predicate returns true. This function will automatically enter and exit blocks.

If the second argument is a non-negative integer, it will move right that many times if possible, returning :error otherwise.

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

Moves to the next node that matches the predicate.

Link to this function

move_to_cursor(zipper, pattern)

View Source
@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.node()
# => 10
Link to this function

move_to_cursor_match_in_scope(zipper, patterns)

View Source
@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)

View Source
@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)

View Source (macro)

Moves to the next node that matches the given pattern.

Link to this function

move_to_zipper(zipper, pred)

View Source

Moves to the next zipper that matches the predicate.

Link to this function

move_upwards(zipper, pred_or_n)

View Source
@spec move_upwards(
  Sourceror.Zipper.t(),
  non_neg_integer() | (Sourceror.Zipper.t() -> boolean())
) ::
  {:ok, Sourceror.Zipper.t()} | :error

Moves a zipper upwards.

If the second argument is a predicate function, it will be called on the zipper and then move upwards until the predicate returns true.

If the second argument is a non-negative integer, it will move upwards that many times if possible, returning :error otherwise.

Link to this function

move_upwards_until(zipper, pred)

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

Moves to the last node before the node that matches the predicate, going upwards.

Link to this macro

node_matches_pattern?(zipper, pattern)

View Source (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)

View Source
@spec nodes_equal?(Sourceror.Zipper.t() | Macro.t(), Macro.t()) :: boolean()
This function is deprecated. Use `move_right/2` instead, passing an integer as the second argument..
@spec nth_right(Sourceror.Zipper.t(), non_neg_integer()) ::
  {:ok, Sourceror.Zipper.t()} | :error

Removes any nodes matching the provided pattern, until there are no matches left.

Link to this function

remove_all_matches(zipper, pred)

View Source
@spec remove_all_matches(
  Sourceror.Zipper.t(),
  (Sourceror.Zipper.t() -> boolean())
) :: Sourceror.Zipper.t()

Removes all nodes matching the given predicate with the given function.

Recurses until the predicate no longer returns false

Link to this function

replace_code(zipper, code)

View Source
@spec rightmost(Sourceror.Zipper.t()) :: Sourceror.Zipper.t()

Moves the zipper all the way to the right, potentially entering a single value block.

Link to this function

single_child_block?(zipper)

View Source
@spec single_child_block?(Sourceror.Zipper.t()) :: boolean()
Link to this function

update_all_matches(zipper, pred, fun)

View Source
@spec update_all_matches(
  Sourceror.Zipper.t(),
  (Sourceror.Zipper.t() -> boolean()),
  (Sourceror.Zipper.t() ->
     {:ok, Sourceror.Zipper.t() | {:code, term()}} | {:warning | :error, term()})
) :: {:ok, Sourceror.Zipper.t()} | {:warning | :error, term()}

Updates all nodes matching the given predicate with the given function.

Recurses until the predicate no longer returns false

Link to this function

use_aliases(new_code, current_code)

View Source

Replaces full module names in new_code with any aliases for that module found in the current_code environment.

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.