simvx.core.scene_io.edits

Prefix-preserving editing primitives for parso trees.

parso stores leading whitespace and comments on each leaf’s prefix string; the prefix of a non-leaf node is the prefix of its first leaf. Edits that splice nodes in or out of the tree must transfer prefixes carefully so that trailing comments stay glued to the right line, blank-line spacing does not drift, and indent depth is preserved.

The primitives here operate directly on the parso tree (mutating parent.children lists). They are deliberately small — composition lives in higher tiers (scene_file, scene_module).

Module Contents

Functions

replace_node

Replace old with new in their shared parent’s children list.

insert_after

Insert new_node immediately after sibling in their shared parent.

insert_before

Insert new_node immediately before sibling in their shared parent.

remove_node

Remove node from its parent’s children list.

get_call_kwarg

Return the value subtree for kwarg name in a call, or None.

set_call_kwarg

Set kwarg name on a call expression.

API

simvx.core.scene_io.edits.replace_node(old: parso.tree.NodeOrLeaf, new: parso.tree.NodeOrLeaf, *, preserve_prefix: bool = True) None[source]

Replace old with new in their shared parent’s children list.

With preserve_prefix=True (default), the leading whitespace + comments of old’s first leaf are transferred onto new’s first leaf so that same-line trailing comments on the previous statement, leading blank lines, and decorators above remain attached.

simvx.core.scene_io.edits.insert_after(sibling: parso.tree.NodeOrLeaf, new_node: parso.tree.NodeOrLeaf, *, copy_indent: bool = True) None[source]

Insert new_node immediately after sibling in their shared parent.

With copy_indent=True (default), the indent run of sibling’s first leaf prefix is copied onto new_node so the new statement sits at the same column. new_node’s prefix is overwritten with "\n<indent>" — callers wanting custom prefixes should pass copy_indent=False and populate the prefix themselves.

simvx.core.scene_io.edits.insert_before(sibling: parso.tree.NodeOrLeaf, new_node: parso.tree.NodeOrLeaf, *, copy_indent: bool = True) None[source]

Insert new_node immediately before sibling in their shared parent.

With copy_indent=True (default), new_node inherits sibling’s full prefix (so any leading comments/blank lines stay above the inserted node) and sibling’s prefix is reset to "\n<indent>" so it sits at the same column it did originally.

Note: this transfers comments above sibling to the inserted node. To keep them attached to sibling, pass copy_indent=False and manage prefixes manually.

simvx.core.scene_io.edits.remove_node(node: parso.tree.NodeOrLeaf, *, collapse_blank_lines: bool = True) None[source]

Remove node from its parent’s children list.

With collapse_blank_lines=True (default), surplus blank lines in node’s prefix are collapsed onto the next sibling so deleting statements in sequence does not balloon vertical spacing. The collapse rule is: keep at most one blank line of separation; the indent run on the final line is preserved verbatim.

Same-line trailing comments stored in node’s prefix (which originate on the previous sibling — see module docstring) are re-attached to the next sibling so they stay on their original line.

simvx.core.scene_io.edits.get_call_kwarg(call_node: parso.tree.NodeOrLeaf, name: str) parso.tree.NodeOrLeaf | None[source]

Return the value subtree for kwarg name in a call, or None.

call_node may be either the trailer (the (...) after a name) or the enclosing atom_expr — both forms are accepted.

simvx.core.scene_io.edits.set_call_kwarg(call_node: parso.tree.NodeOrLeaf, name: str, value_expr: str) None[source]

Set kwarg name on a call expression.

Overwrites if name already exists (preserves the order of other args); appends if not. value_expr is parsed with :func:parse_snippet, so callers pass real Python source (e.g. "Vec2(0, 0)" or '"hello"').

A trailing comma in the original arglist is preserved when appending.