//! Interactive demo of the `leaves.Tree` component: a collapsible file-tree //! style view. Navigate with `↓`/`j` and `↑`/`k`, expand/collapse the current //! node with `⏎`, jump to top/bottom with `g`/`G`, and open the full help with //! `?`. Quit with `q` or `Ctrl+C`. const std = @import("std"); const matcha = @import("blacktea"); const leaves = @import("buds"); const Writer = std.Io.Writer; const Allocator = std.mem.Allocator; const State = struct { model: matcha.Model = .{ .vtable = &.{ .init = init, .update = update, .view = view, } }, tree: leaves.Tree = .{}, quitting: bool = false, fn init(m: *matcha.Model) ?matcha.Cmd { const self: *State = @fieldParentPtr("model", m); self.tree.gpa = m.gpa; self.tree.setRoot(buildProject(m.gpa)); return null; } fn buildProject(gpa: Allocator) *leaves.Tree.Node { const root = leaves.Tree.Node.new(gpa, "charm") catch unreachable; root.setOpen(true); const src = leaves.Tree.Node.new(gpa, "src") catch unreachable; src.setOpen(true); src.child(gpa, "main.zig") catch unreachable; const ui = leaves.Tree.Node.new(gpa, "ui") catch unreachable; ui.setOpen(true); ui.child(gpa, "theme.zig") catch unreachable; ui.child(gpa, "spinner.zig") catch unreachable; src.childNode(gpa, ui) catch unreachable; root.childNode(gpa, src) catch unreachable; root.child(gpa, "build.zig") catch unreachable; root.child(gpa, "build.zig.zon") catch unreachable; const examples = leaves.Tree.Node.new(gpa, "examples") catch unreachable; examples.setOpen(false); examples.child(gpa, "basic.zig") catch unreachable; examples.child(gpa, "styled.zig") catch unreachable; root.childNode(gpa, examples) catch unreachable; root.child(gpa, "README.md") catch unreachable; return root; } fn update(m: *matcha.Model, msg: matcha.Msg) ?matcha.Cmd { const self: *State = @fieldParentPtr("model", m); switch (msg) { .key_press => |k| { if (k.kind == .rune and k.rune == 'q') { self.quitting = true; return .quit; } if (k.kind == .rune and k.rune == 'c' and k.mods.ctrl) { self.quitting = true; return .quit; } }, .window_size => |ws| { self.tree.setSize(ws.width, ws.height); return null; }, .interrupt => return .quit, else => {}, } return self.tree.update(msg); } fn view(m: *matcha.Model, w: *Writer) Writer.Error!matcha.View { const self: *State = @fieldParentPtr("model", m); if (self.quitting) { try w.writeAll("\n bye!\n\n"); return .{}; } try self.tree.view(w); return .{ .alt_screen = true }; } }; pub fn tree(init: std.process.Init) !void { var s: State = .{}; s.tree.gpa = init.gpa; defer s.tree.deinit(); var program: matcha.Program = try .init(init, &s.model, .{}); defer program.deinit(); try program.run(); }