Skip to content

Editing Trees โ€‹

What you'll learn โ€‹

  • The six fields of InputEdit and what each one means.
  • How applyEdit shifts stored positions.

The six fields โ€‹

FieldMeaning
start_byteWhere the change begins (old and new text agree before this)
old_end_byteWhere the replaced old text ended
new_end_byteWhere the replacement new text ends
start_pointRow/column of start_byte
old_end_pointRow/column of old_end_byte in the old text
new_end_pointRow/column of new_end_byte in the new text

For a pure insertion, start_byte == old_end_byte. For a pure deletion, start_byte == new_end_byte.

Complete example โ€‹

zig
treesitter.applyEdit(&tree, .{
    .start_byte = 0,
    .old_end_byte = 0,
    .new_end_byte = 4,
    .start_point = .{},
    .old_end_point = .{},
    .new_end_point = .{ .row = 0, .column = 4 },
});
// tree.rootNode().startByte() == 4, endByte() == 9

How it works โ€‹

applyEdit rewrites every stored node position through the edit:

  • Bytes before start_byte are untouched.
  • Bytes at or after old_end_byte shift by new โˆ’ old length delta.
  • Bytes inside the edited span clamp to the new span.
  • Points translate with the same rules, row-aware: positions before the start point keep their row, positions after the old end shift rows, and columns on the edited rows rebase onto the new end column.

When to use this โ€‹

Call applyEdit when you keep a tree around while its source changes and want its positions to stay meaningful โ€” for example, to map cursor positions before reparsing. Parser.parse does its own translation internally, so the edit-and-reparse flow does not require a prior applyEdit.

API used โ€‹

Released under the MIT License.