╭ changed ──────────╮ │src/embed/script.js│ ╰───────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │52 return control ? [control] : Array.from(grid.querySelectorAll(`[data-focus-id="${id}"]`)); │ │53 } │ │54 │ │55 +// whether an input's caret sits past its last character, with nothing selected │ │56 +function caretAtEnd(input) { │ │57 + return input.selectionStart === input.value.length && input.selectionEnd === input.value.length;│ │58 +} │ │59 + │ │60 function focusedNativeScroll() { │ │61 const id = grid.dataset.focusId; │ │62 if (!id) return null; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │380 wasmInstance.exports._tick(minRows(), maxCols()); │ │381 } │ │382 return; │ │383 + } else if (tag === "INPUT" && !document.activeElement.form && !document.activeElement.readOnly &&│ │384 + (event.key === "Tab" && !event.shiftKey || │ │385 + event.key === "ArrowRight" && caretAtEnd(document.activeElement))) { │ │386 + // an input outside a form (a search box) reaches the widgets │ │387 + // beside it: Tab, and ArrowRight once the caret is at the end. │ │388 + // blurred first, so the next key isn't the input's; the tick │ │389 + // refocuses it if the TUI focus stayed. │ │390 + event.preventDefault(); │ │391 + document.activeElement.blur(); │ │392 + wasmInstance.exports._onKeyDown(event.keyCode); │ │393 + wasmInstance.exports._tick(minRows(), maxCols()); │ │394 + return; │ │395 } else if (tag === "INPUT" && (event.key === "ArrowUp" || event.key === "ArrowDown")) { │ │396 // up/down moves between widgets; left/right stay in the input │ │397 document.activeElement.blur(); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────────╮ │src/event/Discussion.zig│ ╰────────────────────────╯ ╭────────────────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const evt = @import("../event.zig"); │ │3 +const srch = @import("../search_thread.zig");│ │4 const xit = @import("xit"); │ │5 const rp = xit.repo; │ │6 const hash = xit.hash; │ ╰────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 90 const ids = try DB.SortedSet(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, all_id_set_key))); │ │ 91 try ids.put(&evt.orderKeyDesc(record_to_write.created_order, event_id)); │ │ 92 } │ │ 93 + │ │ 94 + // the search index is keyed by creation, not activity: ordering is the │ │ 95 + // list's business, so a comment moving the discussion up leaves it alone │ │ 96 + const search_key = evt.orderKeyDesc(record_to_write.created_order, event_id); │ │ 97 + try srch.update(DB, hash_kind, .discuss, haxy_moment, arena.child_allocator, if (existing_record_maybe) |existing| srch.doc(&search_key, existing) else null, srch.doc(&search_key, record_to_write));│ │ 98 │ │ 99 if (!record_to_write.removed) { │ │100 try active.put(&order_key); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────╮ │src/event/Issue.zig│ ╰───────────────────╯ ╭────────────────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const evt = @import("../event.zig"); │ │3 const diff3 = @import("../diff3.zig"); │ │4 +const srch = @import("../search_thread.zig");│ │5 const xit = @import("xit"); │ │6 const rp = xit.repo; │ │7 const hash = xit.hash; │ ╰────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │139 const issue_id_set = try DB.SortedSet(.read_write).init(issue_id_set_cursor); │ │140 try issue_id_set.put(&order_key); │ │141 } │ │142 + │ │143 + // the search index is keyed by the same order key as the sets above │ │144 + try srch.update(DB, hash_kind, .issue, haxy_moment, arena.child_allocator, if (existing_record_maybe) |existing| srch.doc(&order_key, existing) else null, srch.doc(&order_key, record_to_write));│ │145 │ │146 if (!record_to_write.removed) { │ │147 const status_set = try statusSet(DB, status_to_issues, record_to_write.event.status); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────╮ │src/event/Patch.zig│ ╰───────────────────╯ ╭────────────────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const evt = @import("../event.zig"); │ │3 const diff3 = @import("../diff3.zig"); │ │4 +const srch = @import("../search_thread.zig");│ │5 const xit = @import("xit"); │ │6 const rp = xit.repo; │ │7 const hash = xit.hash; │ ╰────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │252 try children.put(&order_key); │ │253 } │ │254 } │ │255 + │ │256 + // the search index is keyed by the same order key as the sets above │ │257 + try srch.update(DB, hash_kind, .patch, haxy_moment, arena.child_allocator, if (existing_maybe) |existing| srch.doc(&order_key, existing) else null, srch.doc(&order_key, record));│ │258 │ │259 if (!record.removed) { │ │260 const status = try statusSet(DB, statuses, status_kind); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/main_wasm.zig│ ╰─────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │112 fn onKeyDown(key_code: u32) !void { │ │113 const root_ptr = if (root) |*root_value| root_value else return error.NotStarted;│ │114 const key: Key = switch (key_code) { │ │115 + 9 => .tab, │ │116 13 => .enter, │ │117 33 => .page_up, │ │118 34 => .page_down, │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────╮ │src/search.zig│ ╰──────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────╮ │11 // still reaches it. │ │12 const max_word_len = 32; │ │13 // how many distinct words one document contributes. │ │14 -const max_words_per_doc = 64; │ │14 +const max_words_per_doc = 256; │ │15 // how much of a document is tokenized. │ │16 -pub const max_indexed_bytes = 4 * 1024; │ │16 +pub const max_indexed_bytes = 16 * 1024; │ │17 // how many indexed words one typed word expands to. │ │18 const max_expansions = 50; │ │19 // the largest doc key, so results are read into a buffer rather than allocated.│ ╰────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯