From e87e16547a17864b2a0cd574c1aa42d44125bc6c Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 16:35:27 -0300 Subject: Alt-o, Alt-i and the other tree-sitter keys walk the file's syntax tree helix's expand/shrink, previous/next sibling, all siblings, all children and parent-node end/start (Alt-o/up, Alt-i/down, Alt-p/left, Alt-right, Alt-a, Alt-I, Alt-e, Alt-b; Alt-n stays the new terminal) walk a whole-file parse the file keeps (File.node_tree), made on the first such key after an edit and reused until the next, never per key. syntax.walkNodes follows helix's TreeCursor over every node, anonymous ones included, and Alt-i goes back to what Alt-o grew from while the selection still holds it. The harness runs without grammars, so the cases prove the plain-text no-op; a test replays eleven JSON walks whose results were taken from the installed hx. Co-Authored-By: Claude Opus 5.5 --- src/File.zig | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/File.zig') diff --git a/src/File.zig b/src/File.zig index 8ba58fbc..2c4f0aec 100644 --- a/src/File.zig +++ b/src/File.zig @@ -69,9 +69,19 @@ pub const State = struct { tree_context: bool = false, context_declarations: []syntax.ContextDeclaration = &.{}, context_revision: ?u32 = null, + /// The whole file's parse for the keys that walk its nodes (Alt-o and + /// kin), made on the first of them after an edit and kept until the next + /// one: `syntax.parseTree`'s, opaque here. + node_tree: ?*anyopaque = null, + node_tree_revision: u32 = 0, + /// helix's object_selections: what Alt-o grew from, for Alt-i to go back + /// to; gpa-owned ranges and the primary's index. + node_history: std.ArrayList(NodeStep) = .empty, history: *History, }; +pub const NodeStep = struct { ranges: []modal.Selection, primary: usize }; + pub fn dumpPane( arena: std.mem.Allocator, pane: *const Pane, @@ -816,6 +826,9 @@ pub fn deinit(p: *Pardes, pane: *Pane, file: *State) void { if (file.highlights.len > 0) p.tree_sitter_gpa.free(file.highlights); locations.freeRows(p.gpa, file.location_rows); if (file.context_declarations.len > 0) p.tree_sitter_gpa.free(file.context_declarations); + if (file.node_tree) |tree| syntax.freeTree(tree); + for (file.node_history.items) |step| p.gpa.free(step.ranges); + file.node_history.deinit(p.gpa); for (file.history.undo[0..file.history.undo_len]) |snap| p.gpa.free(snap.content); for (file.history.redo[0..file.history.redo_len]) |snap| p.gpa.free(snap.content); p.gpa.destroy(file.history); -- cgit v1.3