Repository navigation
Close the parity gaps the upstream suites name - #48
metaphoric-dev wants to merge 240 commits into
Conversation
Commit fc59163 added an nvim_mcursor API function and edited the canonical metadata blob so nvim_get_api_info advertised it. Upstream at the reference commit has no such function: only internal multicursor plumbing exists, in input_cmdatom.c, and the oracle's --api-info is 32701 bytes without it. So just apidiff failed on the one semantic difference the criterion forbids. The blob is restored from the oracle's own --api-info output, api_function_names.rs is regenerated from it, and the handler, its registration, its tests, and the dead Editor::add_mcursor and mcursor_count are removed. The registry and metadata tests now pin 262 functions. The same file carries the scoped Lua dispatch fix: with_scoped_editor_api installs functions that outlive the scope instead of borrowing it, so Lua code that captures vim.fn or a vim.api entry at module load keeps a working binding after the originals are restored. BREAKING CHANGE: the nvim_mcursor RPC method is gone. It was never upstream API and no in-tree consumer called it.
The collection parser treated every `[` as an opener and raised E54 when no `]` followed, while upstream decides with a pre-scan and otherwise falls through to a literal `[`. A pattern such as `foo[` now compiles, and the strict entry point still reports E769 for vim.regex, which is the only caller that turns a lone bracket into an error. The parser gains a close scan that mirrors skip_anyof: a leading `^`, `]`, or `-` is a member, a `\` escape consumes two bytes, a POSIX class is one unit, and a nested `[` after `\_.` no longer swallows the opener. Reversed ranges report E944 through CompileError::code(), and the display no longer embeds a code, so callers can render `E54: Unmatched \(` without a doubled prefix. Covered by eleven behaviour tests that pin the oracle matrix, plus the strict-mode and range-error cases.
The modifier loop now re-skips space, tab, and `:` at the top of every iteration, as parse_command_modifiers does, so `:unsilent :norm! n` and `:silent :silent :echo 1` parse as modifiers over a command instead of one unknown name. `:put =expr` takes its expression through the register path, so the six shapes the oldtests exercise agree with the oracle and one dead parse helper is gone. `:scriptnames` lists sourced scripts as `%3d: name` with home replacement, edits a script given a count or a range, and reports upstream's invalid-argument error; the startup noise it used to cause is gone because upstream rplugin.vim calls it on every start. A substitute replacement expression now holds the text lock, so a nested `:s` inside `\=` raises E565 instead of recursing without bound, and the first non-normal flow from `:tabdo` stops the loop while restoring the original tabpage, with the check against the tab table happening immediately before each switch. Command dispatch reports a resolved but unimplemented builtin command as E492 rather than E117, and the regex call sites use CompileError::code() instead of a fixed E54 prefix.
…adly
A function defined in one script and called while another script is current
cloned a stale registry copy of the caller's `s:` map over the live one, so
`runtest.vim`'s `s:has_ffi` read as undefined from inside test functions.
Switching scripts now flushes the outgoing live map into its SID first and
the call frame reloads the caller from that SID on return, which removes the
whole class (41 oldtest failures across cmdline, search, and ins_complete).
`g:Name(...)` and `function('g:Name')` resolve a variable-held Funcref the
way upstream does, including E1085 with the written spelling when the
variable exists but is not callable, and `s:`/`<SID>` names translate to the
`<SNR>` form when stored.
screenchar, screenstring, screenchars, and screenattr answer the whole
lines by columns grid with blank cells, so `nr2char(screenchar(row, col))`
no longer produces E5070 outside the buffer text; -1 stays for out-of-grid
coordinates, matching the oracle.
getcmdline, getcmdpos, setcmdpos, getcmdtype, getcmdprompt, pumvisible, and wildmenumode now dispatch from editor state instead of reporting E117. The number coercion follows tv_get_number: floats truncate, strings take their numeric prefix, and a Dictionary is E728. setcmdpos stores a one-based slot that the next CTRL-R paste consumes and clears, matching upstream's static new_cmdpos: the slot is invisible to getcmdpos, resets with the command-line session, and paste writes into the command-line text rather than the buffer. CTRL-R CTRL-R shares that path. screenpos, win_screenpos, setcmdline, setcmdtype, and the completion-type queries are not part of this change.
Fold ranges, foldmethod evaluation, and the open and close commands now come from one model, so `:fold` reports E350 only for methods that need an expression the port does not evaluate, and a closed fold answers foldclosed and foldclosedend consistently. diffget and diffput work on the hunk table instead of reconstructing it per call, which fixes the added and deleted line cases and the fold refresh after a put.
`:abbreviate`, `:abclear`, and the insert-mode, command-line, and both-mode forms register on the same engine as mappings, with the `noabbrev` and `iabbrev` forms and the `maparg`, `mapcheck`, and `maplist` reporting the oldtests read. Resolution rules match the mapping side: a full match wins over a shorter one, and the expansion keeps the engine's one lookup per keystroke.
Key-notation escape and unescape now carry a UTF-8 continuation byte and a widened KS_MODIFIER third byte, so a register holding a modified key or a non-ASCII character round-trips instead of failing with E523 "invalid special-key third byte". Recording unescapes at the stop and playback escapes again, which is where upstream puts the conversion. Register writes take their type from str_to_reg, so an append keeps the existing type only when upstream does, and the dict-clear and slash-clear paths go through the model rather than editing text directly.
The initial highlight table now carries the 140 command-line groups, the `@` parents, the HLF interns, and the startup aliases the oracle reports, so `:highlight` answers over the same 388-visible, 11-hidden set instead of missing names the suite queries. Neighbouring editor surfaces carry the wave's small corrections: buffer variable ownership, insert-mode undo boundaries, and the autocmd entry liveness check used by the plan executor.
The API and UI crates follow the changed signatures: buffer attach subscriptions resolve through the editor's table, window text queries read the same option snapshot as the compositor, and the tabpage and UI entry points keep the existing validation order. The Lua bridge refactor groups attach subscriptions by buffer and channel so the callback table is looked up once per event, and vim.regex now compiles strictly, which is what reports E769 for a lone bracket. ox-tui, ox-sys, ox-text, ox-uv, ox-rpc codec, and the runtime locator carry only the adjustments those signature changes require.
The upstream Makefile wraps every oldtest file in runnvim.sh, which starts
the test process with jobstart(..., {'term': v:true}) and reads the result
back as terminal-buffer lines. Oxvim does not paint a terminal buffer yet, so
that path reported an empty screen and exited non-zero before a single test
ran, and just oldtest produced no messages file at all.
tests/oldtest/run.sh drives runtest.vim directly: one scratch copy of
testdir, one HOME, one XDG tree, and one TMPDIR per file, eight files at a
time, with the same sandbox the recipe used to build by hand. It writes an
aggregated messages file and reports executed, failed, skipped, clean,
blocked, and timed-out counts. A full sweep now takes about six minutes.
The PTY differential test fed the raw byte stream to a substring check that
only matched if the client skipped blank cells, which it does not by
construction, so it failed against every build. It now parses the stream with
vt100 and asserts on the rendered screen, and the subject path honours
OXVIM_BIN, so a build in a non-default CARGO_TARGET_DIR is the one tested.
The Windows job checks the whole workspace for the host MSVC target and runs
the platform startup tests, which is what proves the CRLF and packpath fixes
on a real Windows runner.
The page claimed Windows was untested and left both upstream suites unmeasured. It now records the 2026-10-28 counts: 1830 of 4076 executed functional tests pass with 58 skipped and one error, and 2323 of 3593 executed oldtests fail with 40 files blocked before their first test and six timed out. The oldtest row also explains why the gate drives runtest.vim directly, and the gap list gains the two defects this run measured: terminal output is not parsed into buffer cells, and a Lua to Vimscript builtin call costs about half a millisecond, which makes filetype detection on one file name take seconds.
…port The report states the gate results before and after this work, names the four root causes that blocked the deterministic gates, lists the defect clusters the waves closed with their measured effect, and lists what stays open with the two defects the run measured: the Lua to Vimscript call cost that makes filetype detection slow, and the terminal output that is not parsed into buffer cells. The ox-excmd test module now imports split_vimgrep_args from its own crate, which the workspace test build needed after the function moved.
Three probes in this run produced empty or misleading results before they were caught: a TEST_FILTER with `|` instead of Vim's `\|` selects no tests, a census binary copied outside target/release cannot resolve the runtime and reports every file blocked, and SIGTERM does not stop a hung oxvim on the shared PTY. Each cost a detour, so the report names them.
Every Lua-to-Vimscript builtin call re-synced the editor into the scope. That sync rebuilt two tables unconditionally: the mirrored `&opt` values for every option under its canonical name, short name, and aliases, and the mirrored `@r` registers for every register name. Measured on this host, one `vim.fn.abs()` call cost 620 microseconds, of which 597 were that read sync; upstream costs a few microseconds. The option store and the register bank now carry a monotonic version bumped by every mutation, and the sync rebuilds each mirror only when its stamp moved, the same gate the variable maps already use. The same loop now runs at three microseconds per call, and `cargo nextest run --workspace` dropped from 29 seconds to 17. Option and register tests that observe the mirror after a write still pass, which is what proves the stamps advance on every mutator.
Formatting only: the campaign's edits left several modules with the line breaks the workspace profile rejects, so `cargo fmt` was run over the crates that changed. No behaviour changes.
The compat page blamed the Lua to Vimscript bridge for the slow `:edit` path. That bridge is fixed: the option and register mirrors are version-gated and a call costs three microseconds instead of 620. The remaining loop is a different one, measured at about 1.4 million `fnamemodify` calls in fifteen seconds with `vim.filetype.match` never entered, so both documents now say what is fixed and what is still open.
`:split` with no argument keeps the current buffer and inherits the current
window's local options, which is what win_init_some does. `:new`, `:vnew`,
and `:split {file}` initialise the window with win_init instead, so every
window-local option starts at its global value. The port copied in all four
cases, so a `foldnestmax` or `winhl` set in one window leaked into the next
window the command created.
The split path now drops the copied overlay whenever the window shows a
different buffer from the one the command started in. Measured against the
oracle: `:new` and `:vnew` answer 20 for a `foldnestmax` set to -1 in the
source window, `:split` answers -1, and `:split {file}` answers 20.
OptionStore gains a version-bumping reset_window for that drop, and the
editor exposes options_mut for the command layer.
`fnamemodify('foo', ':h')` returned an empty string where upstream's
`path_head` answers ".". `vim.fs.parents` walks `:h` until the path stops
changing, so the empty answer made it loop forever: every `:edit` in headless
mode ran a buffer-lifecycle autocmd that walked the path for minutes, and one
oldtest file timed out before running a single test.
Measured after the fix: `:edit foo` takes 0.05 seconds instead of more than
three minutes, `fnamemodify('foo', ':h')` answers ".", and the oldtest sweep
executes 61 more tests because test_substitute.vim now finishes. Its failures
rose by 52 because those tests now run instead of being cut off.
The `:edit` hang is gone, so the compat page and the campaign report now name the five files that still exceed the runner's cap instead, and the oldtest row carries the fresh counts: 3654 executed with 2368 failing.
`call({func}, {arglist} [, {dict}])` now dispatches: a Funcref or Partial goes
through the evaluator's invocation path, a function name goes through the
host, and a third argument turns the call into `function({func}, {dict})` so
the callee reads `self` from its frame. The oracle agrees on the plain form,
the Funcref form, a lambda, E117 for an unknown name, E119 for missing
arguments, and E731 for a non-dictionary third argument.
The same change fixes a pre-existing defect the new tests exposed: a Partial
created by `function('Name', dict)` carried its dictionary but the invocation
path dropped it, so `self` was undefined inside the callee. The evaluator now
hands the dictionary to the host, which passes it to the user-function frame
that already knew how to bind it. `function('Get', d)()`,
`call(function('Get', d), [])`, and `call('Get', [], d)` all answer the oracle.
The oldtest sweep still executes 3652 tests and fails 2368, but the four
`not implemented: call` sites are gone.
`fs_builtins::call` has served `getfperm` for a long time, but the predicate
that routes filesystem builtins never listed it, so the name fell through to
the pure evaluator and answered `E117: not implemented: getfperm` at seven
oldtest sites while a working implementation sat unreachable.
The predicate now lists it, and a test pins the agreement: every name the
dispatcher serves must be claimed by the routing predicate. Verified against
the oracle, `getfperm('f.txt')` on a 0640 file answers `rw-r-----` from both.
The workspace suite covers 3646 tests, all passing, and the oldtest sweep now executes 3652 tests with 2365 failing after `call()` and the `getfperm` routing fix landed.
`uniq(list, cmp [, dict])` ignored its comparator, so every call behaved like
the two-argument form. It now walks the list comparing the last kept item
with the next original one, calls the comparator through the evaluator, and
binds a third argument as `self`. The comparator's result decides removal:
an item is dropped when the comparator answers false.
That rule is measured, not assumed: `uniq([1,2,3], {a,b -> a < b})` keeps
every item while `{a,b -> a > b}` keeps only the first, and the six list
cases in the new probe set match the oracle item for item. A non-list
argument reports E686 with upstream's text.
The list is snapshotted before the walk and a comparator that changes it
reports E741, so the removal indices cannot address a shifted list.
The oldtest sweep executes 3654 tests with 2365 failing, and the report now records that `call()` and the `uniq()` comparator are implemented while the missing Ex commands remain open.
Seven tests run through a real executor and evaluate Vimscript, so they exercise the route table, the dispatch arm, and the evaluator together: call() by name, by Funcref, and by lambda; a dictionary argument binding `self` through both call() and function()(); the E117, E119, and E731 argument errors; uniq() with and without a comparator, including the dictionary-method comparator form; and the E686 non-list error. The comparator tests were checked against a mutation: flipping the removal predicate back to `number != 0` fails two of them, so they hold the measured behaviour rather than the shape of the code.
Six read-only passes over the functional and oldtest logs produced the ranked causes, their owners, and two corrections: eight functional groups ended in a timeout so their counts are a floor, and the terminal surface already holds a VT emulator, a pty pump, and row projection, which means the oldtest Makefile path deserves a retry before new terminal work is scheduled.
The emulator, the pty pump, and the row projection all exist, but `:terminal echo hello` still leaves the buffer blank in headless mode, so the remaining terminal work is tracing that path rather than writing a new emulator. The report now says so instead of guessing from the inventory.
`configure_package_path` stripped every relative entry from `package.path`
and `package.cpath`, on the premise that upstream never keeps a `.` entry.
The oracle says otherwise: its `package.path` starts with `./?.lua` and its
`cpath` keeps `./?.so`. The strip therefore diverged from the compatibility
target, and it cost 418 functional failures: the harness starts its subject
inside a tree that exposes `test/` as a relative symlink, and the fixture
modules are required through that entry.
The function now prepends the runtime paths to the loader defaults and leaves
`package.cpath` untouched, which is what upstream does. Verified from a
launch tree that mirrors the harness: `package.path` lists
`runtime/lua/?.lua;runtime/lua/?/init.lua;./?.lua;...` and
`require('test.functional.testnvim.exec_lua')` answers true, where it used to
report the module missing with only the luajit install paths listed.
The path test is re-pinned to the oracle's shape, and the test that asserted a
planted launch-directory module stays unloadable is deleted: it pinned the
divergence, and upstream loads such a module.
The builtin was missing, so `test_scriptnames.vim` stopped on E117 and nothing
could ask which scripts a session has loaded. It now answers every form
`f_getscriptinfo` answers (`runtime.c:2670-2740`): no argument lists each
sourced script as `{name, sid, version, autoload}`, a `name` pattern filters
that list, and a `sid` query returns one entry with the script's `variables`
and `functions`.
The script id, the variable map and the function list read the live registry:
`s:` variables come from the script context, and a function counts for a script
when it was defined while that script was current, so a global defined there is
listed too, as upstream does.
Probe against the reference binary for one sourced file with `s:Fn` and
`s:var`: `count`, `sid`, `variables`, `functions` and the total agree; only the
dictionary key order differs, which is the known iteration-order gap.
`test_scriptnames.vim` now reaches its assertions instead of E117. Suite: 3941
passed.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
The line rewriter honoured single quotes but not double quotes, so `let x = "<SNR>9_a"` became `"<SNR>1_9_a"`. The reference rewrites a script prefix only when it translates a function name (`trans_function_name`, `eval/userfunc.c:1967`), so a marker inside any string literal stays as typed.
Three rules of `do_source_ext` were missing, and each one hid the next. `do_cmdline` breaks its loop on an error only for a line from the command line (`ex_docmd.c:745-753`): `getexline` is the sole getter that stops it. A sourced file therefore runs its remaining lines, while this port abandoned the file at the first failing command — `source` of a file with one bad line never set the variables declared after it. `do_source_ext` calls `save_funccal` (`runtime.c:2337`), so the file body is not the calling function's body. A bare name in a sourced file is global (`eval/vars.c:2505-2512`), even when a function asked for the file; the caller's frames are hidden by `source_bar` instead of by clearing the local map, which would drop explicit `l:` writes at script level. Measured against the reference: a file with `bogus` then `let g:after = 1` now sets `g:after`, and a file sourced from a function sets the global it declares. Suite: 3941 passed.
The builtin answered every bad `sid` with E1249. It now converts through the shared coercions, so a List reports E745 and a Dictionary E728 (`typval.c:4178-4179`), a non-positive id reports E475, and a List `name` reports E730 with E1206 for a non-Dictionary argument. `test_scriptnames.vim` keeps one failure: an invalid `name` pattern reports E54 here and E866 there, which is the regex engine's error text.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
After `:bcd` the reference reports the file's tail, so `bufname('%')` reads
`Xtest-cd-other` while this port kept the full path. `shorten_buf_fname`
(`fileio.c:2434-2463`) rewrites the stored name when the directory changes; this
port keeps the full name and trims on read, which answers the same string.
`cd_spec` T31 gets past its name assertion and now stops at the statusline
expectation: `'statusline'` with a `%!v:lua.*` item does not evaluate, so the
window shows an empty line where the reference shows `STL`. Suite: 3941 passed.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
The Lua prelude builds `vim.str_utfindex` and `vim.str_byteindex` on host functions that did not exist, and calls `vim.str_utf_pos`, `str_utf_start` and `str_utf_end` directly, so any path touching them failed with "attempt to call a nil value" (`vim/fs.lua:245`). The three walkers follow `mb_utflen`, `mb_utf_index_to_bytes` and `utf_ptr2len_len` (`mbyte.c`): a sequence cut by the byte limit still counts as one character and keeps its full codepoint width, an embedded NUL counts as one byte in the counting walks, and only `str_utf_pos` stops at NUL. `vim_spec` T14 now passes; the probe for both binaries agrees on every case. Suite: 3944 passed.
`ShaDa::read` called `read_to_end` before any limit applied, so the reader held the entire history in memory. The reference never does: `shada_read_next_item` reads type, timestamp and length from the descriptor and skips oversized payloads with `sd_reader_skip` (`shada.c:3016-3087`, `3101-3107`, `3170-3187`). The port now reads the same framing directly, skips a payload over `'shada'`'s per-item limit through a fixed buffer, and keeps `max_kbyte == 0` unrestricted (`shada.c:1342-1347`). It accepts every file the reference accepts; it just no longer buffers one. Two tests: an oversized payload is skipped without buffering the file, and a normal history round-trips through `write` then `read`.
`jump_to` used `std::fs::read(filename).unwrap_or_default()`, so an unreadable include opened an empty buffer instead of failing, steering clear of the `IdentSearchError` channel the rest of the function uses. A failed read now returns E484 with the file name, matching the reference, where `find_pattern_in_path` breaks out when `getfile` fails (`search.c:3425-3428`; the message is `errors.h:77-78`). The regression test asserts the error and that no buffer is created.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
`transfer` moved the pending map out of the mutex, then forwarded each deferred event with `events.put(owner, event)?`. `schedule_deferred` accepts any owner, while the destination `MultiQueue` only knows the owners it was given, so an unknown owner is reachable: the error returned early and every event still in the local map was dropped. The transfer now restores the current event and the whole tail, ahead of anything scheduled meanwhile, before returning the error. `MultiQueue::put` also validates its whole parent chain before it mutates, so its documented `UnknownOwner` failure leaves no partial state for any caller. Two tests: a transfer into a queue missing the owner delivers both events on the next pass, and `put` with a missing ancestor changes neither the event map nor the queue.
Decoding each character from the whole remaining slice made a malformed *later* byte widen or narrow the current one: for `F0 9F A4 A6 FF` at index 1 the port answered one UTF-16 unit where the reference answers two, and `_str_byteindex` returned 5 where the reference returns 4. The walk keeps the limit-bounded step (`utf_ptr2len_len`, `mbyte.c:852-872`) and decodes only the current sequence. The index conversion moved into one helper whose single float-to-integer narrowing carries its invariant, replacing the `as` casts the lint gate rejects.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Two divergences survived the first pass, both visible only on bytes a valid UTF-8 string never holds. `utf8len_tab` (`mbyte.c:99-117`) gives 0xC0 and 0xC1 a length of two and 0xF5 to 0xFD lengths of four to six, so `utf_ptr2len_len` walks those leads as one character; the port called each of them a single byte and split the sequence. `utf_ptr2char` (`mbyte.c:642-700`) also assembles the value from the bit layout and validates only trail bytes, so a lead like 0xF5 yields an out-of-range scalar that still counts as two UTF-16 units. Six malformed inputs now agree with the reference, including `F5 80 80 80` at `(1, 2)`. The runtime wrapper padded a missing index with `math.huge`; upstream uses `vim._maxint` (`_core/editor.lua:908`), which is why the host had to reason in floats. The copy matches upstream again.
The test stops at the unknown-owner preflight, before `put` runs, so its old name claimed a path it never reached.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
The compositor built the window statusline itself as `{name}{modified}`, so
`:set statusline=` changed nothing: `cd_spec` T31 set `'statusline'` to
`%!v:lua.stl()` and expected `STL` on the row.
The server now renders it where the evaluator lives and hands finished strings to
the compositor, which stays a pure function of prepared state: it never evaluates
an expression. Rendering reuses the existing `nvim_eval_statusline` grammar, so
`%` items, `%{...}` and `%!...` mean one thing on screen and in the API; the
evaluator gained the `%h`/`%w` items it lacked. A window whose expression raises
is omitted from the map and keeps the default text, so a bad `%!` cannot abort a
redraw.
`cd_spec` 36 of 36. `tabline_spec` measures 1 of 8 with and without this change,
so the remaining screen-rendering gap there is unchanged. Suite: 3947 passed.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
A single window never drew a statusline row: the layout reserved one only when the tabpage held more than one window, and nothing read the option. Upstream reserves the row at `'laststatus'` 2, its default (`window.c:1164-1171`, `drawscreen.c:2759-2762`), so one window now keeps its row while 0 and 1 behave as before. The renderer also evaluated `%!` items on the redraw path with no guard. A statusline expression may run `:redrawstatus`, so upstream keeps a `busy` flag and ignores the nested call (`statusline.c:81-92`); the session now carries the same guard, released on unwind, and a nested render keeps the text it already had. Two geometry expectations follow from the extra row: the PTY text height at 120x40 becomes 38, and the scrolled-window helper grows by one row so its scenarios keep the text height they describe. Probe against the reference: `&lines` 24, `winheight(0)` 23 at `laststatus` 0 and 1, 22 at 2, split 11.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Dropping a UvLoop without pumping it left queued completions holding an Arc to the queue they sat in, so the queue, the closures, and every value they captured leaked. close() now drains the pending deque under the same mutex post serialises on, and a post racing the close either lands before the drain or is rejected, so nothing is stranded. post() also enqueued before waking the loop; a failed wake left the completion queued while Pool::submit reported failure and ended the request, and the later dispatch ended it again. Request termination now lives in a RequestGuard captured by the completion, so end() runs exactly once whether the completion runs, panics, is drained, or is rolled back, and a failed wake pops the entry back off before returning.
vim.mpack.encode rejected NaN and the infinities where upstream packs them as float32 or float64 (conv.c mpack_pack_number: infinities fit single, NaN does not), so RPC payloads carrying them failed at encode time instead of on the wire. vim.mpack.Session required an options table with an unpacker. Upstream lmpack_session_new accepts no argument at all and attaches an unpacker only when a table is given, and receive then returns three values from the raw RPC header instead of five. The constructor now follows that contract, and both receive modes enforce the same header token widths as mpack_rpc_receive_tok (type at most one byte, id at most four), where the unpacker path previously accepted wider tokens.
The port drew a statusline in every window at 'laststatus' 3. Upstream reserves a single screen-width row at the bottom and replaces every non-bottom window's statusline with a one-row horizontal separator (window.c global_stl_height, last_status_rec), so layout, compositor, and emitter now share that model: text heights subtract the separator and the global row, the compositor paints the separator rows and the global statusline from the server-rendered text, and ext_multigrid clients see the statusline on grid 1 with no synthetic message grid where the old code emitted a blank grid that overlaid content. The global text is evaluated at screen width, not window width (statusline.c), and the render cache keys on width so a resize reevaluates. Window grid rows also account for a visible tabline again, which the direct layout-height path had dropped.
winheight() returned the frame height including the statusline and message rows, and nvim_win_get_height, nvim_win_set_height, nvim_win_resize, and :resize worked in frame rows too, so a window reported 24 rows where the reference reported 22 and a saved height restored through :resize shrank the window each time. All of these now use text rows (eval/window.c w_view_height, api/window.c w_height, win_setheight_win), converted through the existing layout owner, with floating windows keeping the requested height and clamping to the same minimum the reference applies (window.c win_setheight_win).
nvim_get_context serialized a blockwise register as a bare Ctrl-V type, and load re-derived its width from the longest row's byte length, so a register cut wider than its content (setreg 'b7' with short rows) came back narrower and later pastes padded to the wrong width. The type now carries the public width the reference stores in ShaDa (shada.c rw), explicit widths survive byte-for-byte, and bare Ctrl-V keeps its previous inference, widened by display cells rather than bytes. Malformed types are rejected instead of silently downgraded to characterwise, widths are bounded before they can reach paste allocation, and invalid UTF-8 rows count four cells per bad byte as the reference's <xx> translation does, with the raw bytes preserved.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
encode() wrote every finite number as a float64 token. The reference packs integral doubles inside the int64/uint64 range as integer tokens, -0.0 as integer zero, and other finite doubles as float32 when the value survives the narrowing (conv.c mpack_pack_number with mpack_fits_single), so wire bytes now match: 1.5 packs ca 3f c0 00 00, 1.0 packs 01, and the signed/unsigned boundaries pack d3/cf tokens as the reference does.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Close the parity gaps the upstream suites name
The
oxvimbinary answers the same--api-infodocument as the oracle — theschema is byte-identical and
just apidiffreports no differences — but thebehavioural surface was missing large pieces the functional and oldtest suites
point at directly: Lua loader paths, terminal buffers, put and register
semantics, a dozen Ex commands, history, channels, timers, closures and a set
of high-count builtins.
This branch closes those, each commit holding one concern with the probes that
justify it. Highlights, with the failure counts a full functional-gate census
ranked:
package.pathkeeps its relative entries like the oracle,which alone recovered the 418 harness-module failures;
vim._core.keyparseexists, and
<Tab>/<NL>encode as their control bytes.:terminalsetsbuftype=terminal,:sleeppumps the jobreactor, and
termopenexists with the oracle's name shape and E475 refusal.:put/:iputhonour range, direction,PUT_CURSENDandPUT_FIXINDENT; blockwise put pads by display cells; the normal-mode countguard answers E1240 instead of allocating.
:join,:change,:move,:uniq,:badd,:checktime,:tabfirst,:tablast,:helpclose,:cpfile,:lpfile, the:bufdo/:cdo/:ldo/:cfdo/:lfdofamily, generic:defer,++once/++nested,:checkhealth, and directory views for:edit.sockconnect,rpcnotify,rpcrequest,chanclose,jobclosewith upstream error codes and a real msgpack-RPC request path.and a closure body now runs against the caller's live
g:,b:,w:,t:,v:ands:maps. A stored lambda callback fires as a value.win_execute,win_screenpos,screenpos,state,mapset,complete_check,diff_filler,win_findbuf,getcmdwintype,shiftwidth,haslocaldir,bufloaded,msgpackparse/msgpackdump,histadd/histdel/histget/histnr,dictwatcheradd/dictwatcherdel.Evidence
cargo nextest run --workspace: 3769 passed, 1 skipped.cargo fmt --all --checkdoes not pass: it reports 199 diffs across theworkspace, a state that predates this branch. A workspace-wide rustfmt
sweep was prepared and then dropped rather than published, because its
diff could not be proven formatting-only; formatting belongs in its own
reviewed change.
just apidiff: schemas match.test_put.vimtest_cdo.vimtest_winfixbuf.vimtest_user_func.vimGates that still fail
This branch does not pass the task's acceptance suites, and the PR does not
claim it does:
just functionalexits 123. Groups end inProcess terminated due to timeout; the largest remaining causes are notification delivery on thestdio channel, screen/row mismatches, and harness timing.
just oldtesthas not been run green. The table above is afive-file census.
Known gaps left open on purpose, each with a probe on file
timer_infodrops a stopped timer synchronously where upstream keeps ituntil the close callback runs.
sites, so a watcher registers and validates but does not observe.
:checkhealthcannot run a real provider re-entrantly and uses a nativefallback.
vim.waitcannot pump terminal jobs while both executor slots are busy, so a-lscript still misses mid-wait output.:menu,:syntaxand:mkspellremain absent; the scope assessments are inthe campaign notes.
Commit boundary note: most commits hold one concern. Three commit bodies
(
aaa779d,6a0b5e2,6f62361) enumerate the files where two concerns shareda file, rather than pretending the split was clean.