╭ changed ──────────╮ │src/embed/script.js│ ╰───────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │294 function sendTextInputValue(focusId, value) { │ │295 const bytes = encoder.encode(value); │ │296 const ptr = wasmInstance.exports._alloc(bytes.length); │ │297 - new Uint8Array(wasmInstance.exports.memory.buffer, ptr, bytes.length).set(bytes); │ │297 + // an empty allocation's pointer lies outside the buffer, so a view onto it │ │298 + // would throw and leave the wasm holding the old value │ │299 + if (bytes.length > 0) { │ │300 + new Uint8Array(wasmInstance.exports.memory.buffer, ptr, bytes.length).set(bytes);│ │301 + } │ │302 wasmInstance.exports._setTextInputValue(focusId, ptr, bytes.length); │ │303 wasmInstance.exports._tick(minRows(), maxCols()); │ │304 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │366 wasmInstance.exports._tick(minRows(), maxCols()); │ │367 return; │ │368 } else if (tag === "INPUT" && event.key === "Enter") { │ │365 - // enter in a text input never submits the form; only the │ │366 - // submit button does │ │369 + // enter in a form's text input never submits it; only the │ │370 + // submit button does. an input outside a form has no submit │ │371 + // button, so the TUI handles its enter instead. │ │372 event.preventDefault(); │ │373 + if (!document.activeElement.form) { │ │374 + wasmInstance.exports._onKeyDown(event.keyCode); │ │375 + wasmInstance.exports._tick(minRows(), maxCols()); │ │376 + } │ │377 return; │ │378 } else if (tag === "INPUT" && (event.key === "ArrowUp" || event.key === "ArrowDown")) {│ │379 // up/down moves between widgets; left/right stay in the input │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───╮ │src/fork.zig│ ╰────────────╯ ╭────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const evt = @import("event.zig");│ │3 +const find = @import("find.zig");│ │4 const xit = @import("xit"); │ │5 const rp = xit.repo; │ │6 const hash = xit.hash; │ ╰────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │162 try fork_repo.addConfig(io, allocator, .{ .name = "core.bare", .value = "true" }); │ │163 try fork_repo.addConfig(io, allocator, .{ .name = "receive.denydeletes", .value = "true" }); │ │164 │ │165 + // the copied db carries the target's file index, so the patch branch's │ │166 + // entry starts from one of those rather than walking the tree │ │167 + find.refresh(repo_opts, io, allocator, &fork_repo) catch |err| { │ │168 + std.log.warn("failed to refresh file index: {s}", .{@errorName(err)}); │ │169 + }; │ │170 + │ │171 // create the patch event │ │172 try evt.consume(.server, .fork, .xit, repo_opts, io, allocator, &fork_repo, evt.events_ref, &.{.{│ │173 .id = input.id, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/lib.zig│ ╰───────────╯ ╭────────────────────────────────────────────╮ │3 pub const main = @import("./main.zig"); │ │4 pub const event = @import("./event.zig");│ │5 pub const push = @import("./push.zig"); │ │6 +pub const find = @import("./find.zig"); │ │7 pub const fork = @import("./fork.zig"); │ │8 pub const pch = @import("./patch.zig"); │ │9 pub const serve = @import("./serve.zig");│ ╰────────────────────────────────────────────╯ ╭ changed ────────╮ │src/main_wasm.zig│ ╰─────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │52 // apply actions queued during input. the wasm path has no repo, so this is │ │53 // in-memory only; logged-in web persistence goes through the /ansi POST. │ │54 session.applyPending(); │ │55 + // a widget asked to move to another page, so hand it to the host instead of│ │56 + // rendering this one again. │ │57 + if (session.next_page) |route| { │ │58 + session.next_page = null; │ │59 + const url = try route.toUrl(&page_arena); │ │60 + _navigate(url.ptr, @intCast(url.len)); │ │61 + return; │ │62 + } │ │63 // bind the UI to the browser viewport (cols x rows) like the terminal: │ │64 // min == max height fills it exactly, and each Scroll clips to its │ │65 // viewport while handing its full content to a native-scrollable element. │ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────╮ │src/patch.zig│ ╰─────────────╯ ╭─────────────────────────────────────────────────────╮ │ 6 const obj = xit.object; │ │ 7 const rf = xit.ref; │ │ 8 const mrg = xit.merge; │ │ 9 +const find = @import("find.zig"); │ │10 const fork = @import("fork.zig"); │ │11 const serve_common = @import("serve_common.zig");│ │12 │ ╰─────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │744 }); │ │745 } │ │746 refreshMergeability(repo_opts, io, allocator, target_repo, null); │ │747 + // the merge moved the target branch, so its file index follows │ │748 + find.refresh(repo_opts, io, allocator, target_repo) catch |err| { │ │749 + std.log.warn("failed to refresh file index: {s}", .{@errorName(err)});│ │750 + }; │ │751 } │ │752 │ │753 // merge a published patch and remove its fork │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───╮ │src/push.zig│ ╰────────────╯ ╭─────────────────────────────────────────────────────╮ │ 7 const rf = xit.ref; │ │ 8 const evt = @import("event.zig"); │ │ 9 const pch = @import("patch.zig"); │ │10 +const find = @import("find.zig"); │ │11 const fork = @import("fork.zig"); │ │12 const serve_common = @import("serve_common.zig");│ │13 │ ╰─────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │155 pch.refreshBranches(.server, .xit, repo_opts, io, allocator, repo, updates.items.items, &progress) catch |err| {│ │156 serve_common.logError(io, error_writer, "failed to refresh branch patches: {s}\n", .{@errorName(err)}); │ │157 pch.refreshMergeability(repo_opts, io, allocator, repo, null); │ │158 + }; │ │159 + find.refresh(repo_opts, io, allocator, repo) catch |err| { │ │160 + serve_common.logError(io, error_writer, "failed to refresh file index: {s}\n", .{@errorName(err)}); │ │161 }; │ │162 try response.finish(writer, null); │ │163 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯