<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rneovim.git/src/nvim/diff.c, branch master</title>
<subtitle>Neovim fork with Rahm's personal hacks.</subtitle>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/'/>
<entry>
<title>vim-patch:9.2.1026: heap-use-after-free via DiffUpdated autocommand (#42238)</title>
<updated>2026-10-05T02:48:50+00:00</updated>
<author>
<name>Jan Edmund Lazo</name>
<email>janedmundlazo@hotmail.com</email>
</author>
<published>2026-10-05T02:48:50+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=561857c4a88072407c79e9707e6f2e81bce097d2'/>
<id>561857c4a88072407c79e9707e6f2e81bce097d2</id>
<content type='text'>
Problem:  A DiffUpdated autococmd wiping the current buffer
          can cause a use-after-free (Evaopo).
Solution: Disallow changing the window layout while DiffUpdated
          autocommand runs.

closes: vim/vim#21177

https://github.com/vim/vim/commit/d81720e01a7ce79afa2c55aff5270d9f394ccbbe

Co-authored-by: Christian Brabandt &lt;cb@256bit.org&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:  A DiffUpdated autococmd wiping the current buffer
          can cause a use-after-free (Evaopo).
Solution: Disallow changing the window layout while DiffUpdated
          autocommand runs.

closes: vim/vim#21177

https://github.com/vim/vim/commit/d81720e01a7ce79afa2c55aff5270d9f394ccbbe

Co-authored-by: Christian Brabandt &lt;cb@256bit.org&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>vim-patch:9.2.1151: reading before the linemap array with inline:word diff</title>
<updated>2026-09-30T08:01:09+00:00</updated>
<author>
<name>zeertzjq</name>
<email>zeertzjq@outlook.com</email>
</author>
<published>2026-09-30T07:47:49+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=d6364a6e96da7d2bc748c12c9411ed561af8abda'/>
<id>d6364a6e96da7d2bc748c12c9411ed561af8abda</id>
<content type='text'>
Problem:  diff_refine_inline_word_highlight() checks the index of the
          line after the block, but uses the index of the last line of
          the block. A block with zero lines makes the index negative
          and causes heap-buffer underflow (Yuyao Jiang).
Solution: Check that the indexes are not negative.

related: vim/vim#21373

https://github.com/vim/vim/commit/f84ab19890c467fe2d1c001494e996178ece6e11

Co-authored-by: Christian Brabandt &lt;cb@256bit.org&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:  diff_refine_inline_word_highlight() checks the index of the
          line after the block, but uses the index of the last line of
          the block. A block with zero lines makes the index negative
          and causes heap-buffer underflow (Yuyao Jiang).
Solution: Check that the indexes are not negative.

related: vim/vim#21373

https://github.com/vim/vim/commit/f84ab19890c467fe2d1c001494e996178ece6e11

Co-authored-by: Christian Brabandt &lt;cb@256bit.org&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>vim-patch:9.2.1099: diff mode redraws slowly with many changes (#41906)</title>
<updated>2026-09-14T01:38:12+00:00</updated>
<author>
<name>zeertzjq</name>
<email>zeertzjq@outlook.com</email>
</author>
<published>2026-09-14T01:38:12+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=e7e29d9b6d11919c35991e843ab1de8cc4e10328'/>
<id>e7e29d9b6d11919c35991e843ab1de8cc4e10328</id>
<content type='text'>
Problem:  Redrawing or folding a diff with many changes is slow because for
          every screen line the list of diff blocks is scanned from the
          start.
Solution: Remember the last examined diff block and resume the scan from
          there while the line number does not move backwards
          (Julien Voisin).

This change is similar to v9.2.1042 (5feaa6c6c201d4d05b833a7230d07da44bf2504b)
and v9.2.1036 (f1b454912996d6417acd0d738de0eb7b60902c56) quadratic
behaviour replaced with a linear one by keeping track of previous
ordered insertions.

diff_check_with_linestatus() and diff_infold() are called for every line
during redraw and fold updates, with a line number that usually
increases monotonically, yet each restarted its scan at tp_first_diff. A
cursor into the block list is now kept and cleared whenever a block is
freed, allocated or has its line numbers shifted, so the next call
continues where the previous one stopped.

Scanning the diff blocks during a scroll of a 20000-line diff drops from
4.12G to 1.27G instructions with ~3300 changes, and scales with the
number of changes.

Tests were added as the change is non-trivial.

closes: vim/vim#21256

https://github.com/vim/vim/commit/2ec2a612c7ac9315a17d70f6a2a5ea89ddaea854

Co-authored-by: Julien Voisin &lt;julien.voisin@dustri.org&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:  Redrawing or folding a diff with many changes is slow because for
          every screen line the list of diff blocks is scanned from the
          start.
Solution: Remember the last examined diff block and resume the scan from
          there while the line number does not move backwards
          (Julien Voisin).

This change is similar to v9.2.1042 (5feaa6c6c201d4d05b833a7230d07da44bf2504b)
and v9.2.1036 (f1b454912996d6417acd0d738de0eb7b60902c56) quadratic
behaviour replaced with a linear one by keeping track of previous
ordered insertions.

diff_check_with_linestatus() and diff_infold() are called for every line
during redraw and fold updates, with a line number that usually
increases monotonically, yet each restarted its scan at tp_first_diff. A
cursor into the block list is now kept and cleared whenever a block is
freed, allocated or has its line numbers shifted, so the next call
continues where the previous one stopped.

Scanning the diff blocks during a scroll of a 20000-line diff drops from
4.12G to 1.27G instructions with ~3300 changes, and scales with the
number of changes.

Tests were added as the change is non-trivial.

closes: vim/vim#21256

https://github.com/vim/vim/commit/2ec2a612c7ac9315a17d70f6a2a5ea89ddaea854

Co-authored-by: Julien Voisin &lt;julien.voisin@dustri.org&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>vim-patch:9.2.0914: diff: undo after :diffget into an empty buffer leaves a line behind (#41181)</title>
<updated>2026-08-05T23:17:17+00:00</updated>
<author>
<name>zeertzjq</name>
<email>zeertzjq@outlook.com</email>
</author>
<published>2026-08-05T23:17:17+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=a19dcb3108440806361cab4f81fb42f66971ca8e'/>
<id>a19dcb3108440806361cab4f81fb42f66971ca8e</id>
<content type='text'>
Problem:  After :diffget into an empty buffer, undo does not restore the
          empty buffer, the last line stays behind (Narendran
          Gopalakrishnan)
Solution: Include the empty line of the empty buffer in the undo
          information, it is deleted once the first line was obtained
          (Hirohito Higashi).

fixes:  vim/vim#20950
closes: vim/vim#20951

https://github.com/vim/vim/commit/c44f35ca1a4d8c0c78f327800fe2677c91c6cecb

Co-authored-by: Hirohito Higashi &lt;h.east.727@gmail.com&gt;
Co-authored-by: Claude Opus 5 (1M context) &lt;noreply@anthropic.com&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:  After :diffget into an empty buffer, undo does not restore the
          empty buffer, the last line stays behind (Narendran
          Gopalakrishnan)
Solution: Include the empty line of the empty buffer in the undo
          information, it is deleted once the first line was obtained
          (Hirohito Higashi).

fixes:  vim/vim#20950
closes: vim/vim#20951

https://github.com/vim/vim/commit/c44f35ca1a4d8c0c78f327800fe2677c91c6cecb

Co-authored-by: Hirohito Higashi &lt;h.east.727@gmail.com&gt;
Co-authored-by: Claude Opus 5 (1M context) &lt;noreply@anthropic.com&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>feat(options): lua closure/function options</title>
<updated>2026-07-31T19:50:04+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-29T17:09:48+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=726d1a92d243a8b7cb4b221d64e4523b7a89aaf4'/>
<id>726d1a92d243a8b7cb4b221d64e4523b7a89aaf4</id>
<content type='text'>
Problem:
Cannot assign Lua functions/closures to "func" ('completefunc',
'tagfun', …) or "expr" ('foldexpr', 'indentexpr', …) options.

Solution:
- Store "func"/"expr" options as `Callback` instead of string.
- Delete oceans of copy-pasted code.
- BREAKING: LuaRef returned via RPC/Vimscript is now represented as
  `"&lt;Lua N: file:line&gt;"` (like what `:map` shows) instead of `nil`.
- Note: `man.vim` still uses `v:lua` string, bc it's a vimscript ftplugin.

Helped-by: Lewis Russell &lt;lewis6991@gmail.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
Cannot assign Lua functions/closures to "func" ('completefunc',
'tagfun', …) or "expr" ('foldexpr', 'indentexpr', …) options.

Solution:
- Store "func"/"expr" options as `Callback` instead of string.
- Delete oceans of copy-pasted code.
- BREAKING: LuaRef returned via RPC/Vimscript is now represented as
  `"&lt;Lua N: file:line&gt;"` (like what `:map` shows) instead of `nil`.
- Note: `man.vim` still uses `v:lua` string, bc it's a vimscript ftplugin.

Helped-by: Lewis Russell &lt;lewis6991@gmail.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor(options): drop OptVal, use Object</title>
<updated>2026-07-29T13:27:45+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-28T20:14:21+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=cb7c0191675454ed81be73aef6c08596b89d9985'/>
<id>cb7c0191675454ed81be73aef6c08596b89d9985</id>
<content type='text'>
Problem:
The object subsystem has an intermediate representation for no real
reason. Besides the code cost, this also adds an extra (api &lt;=&gt; OptVal)
conversion step, which is a (small) perf cost.

Solution:
We already have `Object`, so use it instead.

- drop `OptVal`, `OptValData`, `OptValType`, and related boilerplate.
- add `kObjectTypeUnset`.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
The object subsystem has an intermediate representation for no real
reason. Besides the code cost, this also adds an extra (api &lt;=&gt; OptVal)
conversion step, which is a (small) perf cost.

Solution:
We already have `Object`, so use it instead.

- drop `OptVal`, `OptValData`, `OptValType`, and related boilerplate.
- add `kObjectTypeUnset`.
</pre>
</div>
</content>
</entry>
<entry>
<title>perf(options): no-alloc keysets</title>
<updated>2026-07-24T11:05:20+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-24T10:32:46+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=9604c758b36fd76227997d425a3b8220bdf90679'/>
<id>9604c758b36fd76227997d425a3b8220bdf90679</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor(options): store dict options in :set-string form</title>
<updated>2026-07-24T11:05:20+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-23T20:25:57+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=3fceb84560f8e7a9b3ea68a20eb3b74d01c24416'/>
<id>3fceb84560f8e7a9b3ea68a20eb3b74d01c24416</id>
<content type='text'>
The parent commit made a valiant effort to store "dict options" in their
reified form, but this is more trouble than it's worth:
- inconsistent model for developers to understand.
- string lifetime issues (the "varp" convention is to pass around an
  aliased, long-lived option value).
- lots of extra plumbing to deal with the 2 different option-storage
  paradigms.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The parent commit made a valiant effort to store "dict options" in their
reified form, but this is more trouble than it's worth:
- inconsistent model for developers to understand.
- string lifetime issues (the "varp" convention is to pass around an
  aliased, long-lived option value).
- lots of extra plumbing to deal with the 2 different option-storage
  paradigms.
</pre>
</div>
</content>
</entry>
<entry>
<title>feat(options): schema, "dict" options, messages</title>
<updated>2026-07-24T11:05:20+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-21T16:43:55+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=f8cfd7f06ae87d47aac04ddce860b302f7820858'/>
<id>f8cfd7f06ae87d47aac04ddce860b302f7820858</id>
<content type='text'>
Problem:
Options parsing is still painful for dict-style options.

Solution:
schema-maxxing =&gt; better `opt:get()` (will be the basis for `vim.o()`),
unified (and more-detailed) err msgs.

- Drop bespoke structure-builder in `_core/options.lua`.
- Define `schema` for all non-primitive options (except 'guicursor' and
  statusline-style options); generate reified keysets `OptKeyDict`).
  - Generate 'fillchars' =&gt; `fcs_tab`, 'listchars' =&gt; `lcs_tab`.
- `nvim_set_option_value`:
  - Return the improved structures. Also from `vim.opt.x:get()`.
  - Eliminate api &lt;=&gt; lua roundtrip, centralize option structure
    handling.
- Improve/unify errors.
  - Bump ERR_BUFLEN 80 → 256 so the "one of" list isn't truncated.
- Eliminate old 'diffopt' order-dependence (`iwhiteall` before `iwhite`)

Error samples:

    Typed-key path (opt_strings_check → diffopt/mousescroll/breakindentopt):
    E474: Unknown item 'foo'
    E474: 'context' requires a number
    E474: 'ver' number is out of range
    E474: 'algorithm' must be one of: myers, minimal, patience, histogram
    E474: 'filler' does not take a value

Related:

- #31084
- #34661
- #31820
- #14739
- #20107
- fix #18875
  - :get() returns `{ sbr = true, shift = '3' }` (reified-keyset) instead of `{'sbr', 'shift:3'}`
  - Setting via table now works too. `object_as_optval_for` `is_map` now recognizes struct options.
- fix #30296
  - instead of `E474: Invalid argument`, errors now look like:
    ```
    E474: Invalid value 'x', expected one of: single, double: ambiwidth=x
    E474: Unknown item 'foo': diffopt=foo
    E474: 'context' requires a number: diffopt=context:x
    ```

simplify `win_float_parse_option` from #26799.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
Options parsing is still painful for dict-style options.

Solution:
schema-maxxing =&gt; better `opt:get()` (will be the basis for `vim.o()`),
unified (and more-detailed) err msgs.

- Drop bespoke structure-builder in `_core/options.lua`.
- Define `schema` for all non-primitive options (except 'guicursor' and
  statusline-style options); generate reified keysets `OptKeyDict`).
  - Generate 'fillchars' =&gt; `fcs_tab`, 'listchars' =&gt; `lcs_tab`.
- `nvim_set_option_value`:
  - Return the improved structures. Also from `vim.opt.x:get()`.
  - Eliminate api &lt;=&gt; lua roundtrip, centralize option structure
    handling.
- Improve/unify errors.
  - Bump ERR_BUFLEN 80 → 256 so the "one of" list isn't truncated.
- Eliminate old 'diffopt' order-dependence (`iwhiteall` before `iwhite`)

Error samples:

    Typed-key path (opt_strings_check → diffopt/mousescroll/breakindentopt):
    E474: Unknown item 'foo'
    E474: 'context' requires a number
    E474: 'ver' number is out of range
    E474: 'algorithm' must be one of: myers, minimal, patience, histogram
    E474: 'filler' does not take a value

Related:

- #31084
- #34661
- #31820
- #14739
- #20107
- fix #18875
  - :get() returns `{ sbr = true, shift = '3' }` (reified-keyset) instead of `{'sbr', 'shift:3'}`
  - Setting via table now works too. `object_as_optval_for` `is_map` now recognizes struct options.
- fix #30296
  - instead of `E474: Invalid argument`, errors now look like:
    ```
    E474: Invalid value 'x', expected one of: single, double: ambiwidth=x
    E474: Unknown item 'foo': diffopt=foo
    E474: 'context' requires a number: diffopt=context:x
    ```

simplify `win_float_parse_option` from #26799.
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor(ctx): drop aucmd_prepbuf/aucmd_restbuf #40692</title>
<updated>2026-07-11T16:04:31+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-11T16:04:31+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=0f1e0a79006f4b758f448606918597e6b213eb5d'/>
<id>0f1e0a79006f4b758f448606918597e6b213eb5d</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
</feed>
