# Tab after a dot in insert mode: "what could go here, and where is each of # those defined". The answer is a `+Search` buffer of DEFINITION rows, the same # rows `gr` fills it with — nothing is inserted and nothing pops up. # # a.zig is std-free for the reason lsp.snap's is: these goldens must not encode # this machine's stdlib version or its install path. Its enum members are # nonsense words, and the dot is TYPED into an empty switch body, so a row # naming line 2 or 3 can only have come from a member's declaration — the line # the cursor is on is line 8 and holds nothing but the dot. # # Typing it is the point rather than pointing at one already there: the moment # the dot lands the file STOPS PARSING (`switch (s) { . }` loses the whole # switch to the parser's error recovery), and that is the normal input to a # completion, not a corner case. # # The helix corpora cannot reach any of this — hxOpenFileContent names its pane # `/hxcase.txt`, so lsp.speaks is false for all 1042 cases — which makes this # script the only end-to-end coverage the feature has. file a.zig const Shade = enum {\n verdigris,\n cinnabar,\n};\n\nfn pick(s: Shade) u8 {\n return switch (s) {\n \n };\n}\n\n// note. see below\n file notes.txt abc.def ghi\n start 40 120 a.zig wait 8000 verdigris stable 700 20000 snap opened # Tab with no dot before it is still Tab: line 10 is the closing `}`, and this # is the plain insert_tab path putting spaces in front of it. press left 8 12 release left 8 12 key i key tab stable 400 5000 snap indent key esc settle 100 # A dot the backend cannot answer must STILL indent. Line 12 is a comment, so # the position context is `.comment` and no candidate can exist — and because # Tab had already diverted to the backend, the indent has to happen # retroactively when the empty answer arrives (lspResponse), on the condition # that the cursor has not moved meanwhile. Four spaces go in after `// note.` # and the keystroke is not eaten, which is the whole contract. press left 16 14 release left 16 14 stable 400 5000 key i key tab stable 700 15000 snap commentindent key esc settle 100 # Line 8 (grid row 9, 1-based click row 10) is the switch's empty body. End # puts the cursor past its indent, and then the dot is typed. press left 8 10 release left 8 10 stable 400 5000 key i key end text . stable 400 5000 snap athedot key tab # The row that proves it: `a.zig:2:` is `verdigris`'s own declaration line. # The cursor is on line 8; nothing about line 2 is reachable from the text # under it, so this row can only have come from resolving the switch's # condition to `Shade` and asking `Shade` what it declares. Line 8 still reads # `.` and nothing else — a completion INSERTS NOTHING. wait 15000 a.zig:2: stable 700 15000 snap completion # Nineteen more Tabs. Every one of them answers, and every answer REFILLS the # one `+Search` rather than opening its twin: before that fix six presses left # six byte-identical panes, twenty left fifteen with the file crushed to a # single visible line, and from the sixteenth on freeSlot returned null and the # keystroke was eaten for the rest of the session with nothing said. The golden # below is the assertion — one file pane, one results pane, same as after the # first press. key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab settle 150 key tab stable 700 20000 snap twentytabs # The pane is still in insert mode, which is right — the query answered beside # the cursor and typing goes on — so walking the answer means leaving it first, # the same as for any other results buffer. key esc settle 100 # Several rows, so the buffer IS the picker and n walks it; completion does not # jump the way a goto with one row does. The first step looks row 1 and lands # SELECTING `verdigris` on line 2 of a.zig. key n stable 700 15000 snap step # A pane the backend does not speak: same keystrokes, same dot before the # cursor, and Tab must still indent — synchronously this time, since the core # never asks. The gate is lsp.speaks, which the core consults and the backend # owns. start 40 120 notes.txt wait 8000 abc.def stable 700 20000 press left 12 3 release left 12 3 key i key tab stable 400 5000 snap txtindent # ---- the two genuinely INCOMPLETE states ---- # # Everything above types its dot into syntax that is otherwise finished, which # is the easy half and is why a repair chosen by parse-error count looked like # it worked. Mid-typing, the line is short of its terminator too. # # `const z: Shade = .` is ONE parse error with or without a placeholder # identifier spliced in, so the repair has to be chosen by whether it makes the # dot reachable in the tree, never by counting errors. file c.zig const Shade = enum {\n verdigris,\n cinnabar,\n};\n\npub fn nosemi() void {\n const z: Shade = \n}\n start 18 100 c.zig wait 8000 nosemi stable 700 20000 press left 8 9 release left 8 9 stable 400 5000 key i key end text . stable 400 5000 key tab wait 15000 c.zig:2: stable 700 15000 snap nosemi # ...and a construct still hanging OPEN. The switch has no closing brace at # all — the one `}` in the file closes it and leaves the function unclosed — # which makes Zig's recovery throw the whole declaration away. No placeholder # sitting at the dot can survive that, so the repair has to close the construct # as well, on the same line (a spelling containing a newline would move every # line number the rows are built from). file d.zig const Shade = enum {\n verdigris,\n cinnabar,\n};\n\npub fn nobrace(s: Shade) void {\n switch (s) {\n \n}\n start 18 100 d.zig wait 8000 nobrace stable 700 20000 press left 8 10 release left 8 10 stable 400 5000 key i key end text . stable 400 5000 key tab wait 15000 d.zig:2: stable 700 15000 snap nobrace