<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rneovim.git/src/nvim/lua/executor.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>fix(lua): regression with `print()` in headless mode</title>
<updated>2026-10-06T09:05:43+00:00</updated>
<author>
<name>bfredl</name>
<email>bjorn.linse@gmail.com</email>
</author>
<published>2026-10-03T11:20:33+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=adc0700dc4589e59de2c17a2f8cfc2ba2fb1181f'/>
<id>adc0700dc4589e59de2c17a2f8cfc2ba2fb1181f</id>
<content type='text'>
This is a bunch of hacks so we can override msg_puts_printf specifically
while still allowing redirecting and "normal" message flow to happen,
as this still has observable side-effects (even with no screen attached,
screenstring() is still valid..)

fixes #42218
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This is a bunch of hacks so we can override msg_puts_printf specifically
while still allowing redirecting and "normal" message flow to happen,
as this still has observable side-effects (even with no screen attached,
screenstring() is still valid..)

fixes #42218
</pre>
</div>
</content>
</entry>
<entry>
<title>feat(lua): in script mode -l, use raw output for print()</title>
<updated>2026-10-02T09:43:56+00:00</updated>
<author>
<name>bfredl</name>
<email>bjorn.linse@gmail.com</email>
</author>
<published>2026-09-24T12:31:40+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=58ce7218ec9aa85cc090cee4654e4573f6dd8570'/>
<id>58ce7218ec9aa85cc090cee4654e4573f6dd8570</id>
<content type='text'>
consider the following test_script.lua :

    print 'hello\n' -- TWO new lines
    print 'this is \027[31mRED FOR AN AMAZING REASON\027[0m'
    print 'foo'
    print '' -- newline despite empty!
    print 'bar'

    -- a bit later:
    os.execute 'sleep 2' -- CPU goes BRR, cursor in column zero
    print 'more bar'

before this PR, `nvim -l test_script.lua` had some weird behaviors
compared to `lua test_script.lua` or the now removed `nvim -ll
test_script.lua`.

- one extra '\n' at the end of a print is ignored, one would need
  TWO '\n' for a single extra '\n'

- an empty print'' is supposed to print an empty line

- print'\027[31mRED' is being escaped so it does not work

- the cursor gets stuck at the end of a message, instead of after
  emitting the new line, this looks like the CPU lag has something
  to do with the _last_ printed message which is likely not the case.

I consider these behaviors to be unintentional (a consequence of
stragglig through the message.c meta-machine, which is optimized
for message handling in _an interative text editor_) and getting
closer to plain lua behavior would be better.

An alternative would be to restore the builtin print(), but our
implemenation still has some benefits, like try
`print(setmetatable({}, {__tostring=error})` in plain lua..
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
consider the following test_script.lua :

    print 'hello\n' -- TWO new lines
    print 'this is \027[31mRED FOR AN AMAZING REASON\027[0m'
    print 'foo'
    print '' -- newline despite empty!
    print 'bar'

    -- a bit later:
    os.execute 'sleep 2' -- CPU goes BRR, cursor in column zero
    print 'more bar'

before this PR, `nvim -l test_script.lua` had some weird behaviors
compared to `lua test_script.lua` or the now removed `nvim -ll
test_script.lua`.

- one extra '\n' at the end of a print is ignored, one would need
  TWO '\n' for a single extra '\n'

- an empty print'' is supposed to print an empty line

- print'\027[31mRED' is being escaped so it does not work

- the cursor gets stuck at the end of a message, instead of after
  emitting the new line, this looks like the CPU lag has something
  to do with the _last_ printed message which is likely not the case.

I consider these behaviors to be unintentional (a consequence of
stragglig through the message.c meta-machine, which is optimized
for message handling in _an interative text editor_) and getting
closer to plain lua behavior would be better.

An alternative would be to restore the builtin print(), but our
implemenation still has some benefits, like try
`print(setmetatable({}, {__tostring=error})` in plain lua..
</pre>
</div>
</content>
</entry>
<entry>
<title>fix(api): correct Lua command and completion types</title>
<updated>2026-09-28T13:43:14+00:00</updated>
<author>
<name>Lewis Russell</name>
<email>lewis6991@gmail.com</email>
</author>
<published>2026-09-28T13:19:42+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=b597af006fbb7c94c03ea9e7fa13cab7394b0501'/>
<id>b597af006fbb7c94c03ea9e7fa13cab7394b0501</id>
<content type='text'>
Problem: Command inputs and parsed modifiers have different optional
fields, and completion window IDs are annotated as floating-point
values.

Solution: Separate modifier input and return types, correct integer IDs,
and update the metadata generators and their output.

AI-assisted
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem: Command inputs and parsed modifiers have different optional
fields, and completion window IDs are annotated as floating-point
values.

Solution: Separate modifier input and return types, correct integer IDs,
and update the metadata generators and their output.

AI-assisted
</pre>
</div>
</content>
</entry>
<entry>
<title>fix(strings): non fatal errors for [NULL] safety in vim_snprintf</title>
<updated>2026-09-08T10:46:24+00:00</updated>
<author>
<name>bfredl</name>
<email>bjorn.linse@gmail.com</email>
</author>
<published>2026-09-07T11:39:56+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=97660307f5ac10d01febd7ffba63dfeb24d10351'/>
<id>97660307f5ac10d01febd7ffba63dfeb24d10351</id>
<content type='text'>
context: vim_snprintf provides a "portable" replacement for a system
vsnprintf(). However we rely on system vsnprintf() in places. This
is quite arbitrary. I want to use system vsnprintf() only, and
reduce the machinery in string.c for typval printf only, which will
delet a lot of duplicated code.

The biggest hurdle here is not "portably" (we only support sane c
runtimes) but the following discrepancy: standard libc printf()
considers NULL args to %s to be undefined behavior strictly
while vim_snprintf() _defacto_ allows this by replacement to "[NULL]"

IMO, this should be seen as "graceful" error handling (nicer than crashing
on the user), not a valid means to have the string "[NULL]" intentionally
be shoved in the users face. more robust code should explicitly
check for NULL and replace it with a _appropriate_ fallback for
the situation, depending on what a NULL string actually means in the
context (unnamed buffer? anonymous namespace? global augroup?)

soo, this PR provides the most _gently_ incremental nudge towards
considering this case again as an error one could possible imagine.
If sanitizers are complied in, this minor incursion gets printed
into the sanitizers' log as a "report-and-continue" error with a
traceback. This doesn't annoy the end user or "stop the world"
in the test suite, but the CI will see the reported error and
fail the build, just like other non-fatal CI errors.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
context: vim_snprintf provides a "portable" replacement for a system
vsnprintf(). However we rely on system vsnprintf() in places. This
is quite arbitrary. I want to use system vsnprintf() only, and
reduce the machinery in string.c for typval printf only, which will
delet a lot of duplicated code.

The biggest hurdle here is not "portably" (we only support sane c
runtimes) but the following discrepancy: standard libc printf()
considers NULL args to %s to be undefined behavior strictly
while vim_snprintf() _defacto_ allows this by replacement to "[NULL]"

IMO, this should be seen as "graceful" error handling (nicer than crashing
on the user), not a valid means to have the string "[NULL]" intentionally
be shoved in the users face. more robust code should explicitly
check for NULL and replace it with a _appropriate_ fallback for
the situation, depending on what a NULL string actually means in the
context (unnamed buffer? anonymous namespace? global augroup?)

soo, this PR provides the most _gently_ incremental nudge towards
considering this case again as an error one could possible imagine.
If sanitizers are complied in, this minor incursion gets printed
into the sanitizers' log as a "report-and-continue" error with a
traceback. This doesn't annoy the end user or "stop the world"
in the test suite, but the CI will see the reported error and
fail the build, just like other non-fatal CI errors.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix(lua): blast radius of broken `_G.debug` #41507</title>
<updated>2026-08-27T10:14:24+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-08-27T10:14:24+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=02b0c80422bf8b0ae7a3e839d162bb5e28b81e65'/>
<id>02b0c80422bf8b0ae7a3e839d162bb5e28b81e65</id>
<content type='text'>
Problem:
`nlua_pcall()` references `_G.debug.traceback`. If user code deletes it
or breaks it some other way, various Lua features are broken.

    _G.debug = nil
    vim.schedule(function() end)
    vim.wait(100)

    E5113: Lua chunk: attempt to index a nil value
    stack traceback:
            [C]: in function 'loop_poll'
            [string "vim/_core/editor"]:176: in function 'wait'
            crash.lua:3: in main chunk
    PANIC: unprotected error in call to Lua API (attempt to index a nil value)

Solution:
Check `_G.debug.traceback` before using it as errfunc. If it's broken,
omit the traceback and say so in the error message.

Note: We could cache `_G.debug` in LUA_REGISTRYINDEX on startup, but
that would prevent plugins from providing custom functionality there
(and we happen to do so in `tui_spec.lua` for example).</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
`nlua_pcall()` references `_G.debug.traceback`. If user code deletes it
or breaks it some other way, various Lua features are broken.

    _G.debug = nil
    vim.schedule(function() end)
    vim.wait(100)

    E5113: Lua chunk: attempt to index a nil value
    stack traceback:
            [C]: in function 'loop_poll'
            [string "vim/_core/editor"]:176: in function 'wait'
            crash.lua:3: in main chunk
    PANIC: unprotected error in call to Lua API (attempt to index a nil value)

Solution:
Check `_G.debug.traceback` before using it as errfunc. If it's broken,
omit the traceback and say so in the error message.

Note: We could cache `_G.debug` in LUA_REGISTRYINDEX on startup, but
that would prevent plugins from providing custom functionality there
(and we happen to do so in `tui_spec.lua` for example).</pre>
</div>
</content>
</entry>
<entry>
<title>fix(lifecycle): Lua state not freed if free_all_mem() is re-entered #41366</title>
<updated>2026-08-18T12:30:42+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-08-18T12:30:42+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=1eae512285e7131f4bf48416f9d4b8b1124e223a'/>
<id>1eae512285e7131f4bf48416f9d4b8b1124e223a</id>
<content type='text'>
Problem:
Leak reported by ASAN CI, always at Lua state init.

      ERROR: LeakSanitizer: detected memory leaks
          strbuf_init src/cjson/strbuf.c:62:22
          json_create_config src/cjson/lua_cjson.c:635:5
          lua_cjson_new src/cjson/lua_cjson.c:2060:5
          nlua_state_add_stdlib src/nvim/lua/stdlib.c:840:3
          nlua_state_init src/nvim/lua/executor.c:973:3
      ...
      SUMMARY: AddressSanitizer: 1055 byte(s) leaked in 2 allocation(s).

Analysis:
`getout()` may run during `free_all_mem()` (that's why it checks
`!entered_free_all_mem`). If that happens, the second `os_exit()`
returns early from `free_all_mem()` then `exit()` is called and Lua
state is never closed.

Solution:
Always call `nlua_free_all_mem()` in the early-return case.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
Leak reported by ASAN CI, always at Lua state init.

      ERROR: LeakSanitizer: detected memory leaks
          strbuf_init src/cjson/strbuf.c:62:22
          json_create_config src/cjson/lua_cjson.c:635:5
          lua_cjson_new src/cjson/lua_cjson.c:2060:5
          nlua_state_add_stdlib src/nvim/lua/stdlib.c:840:3
          nlua_state_init src/nvim/lua/executor.c:973:3
      ...
      SUMMARY: AddressSanitizer: 1055 byte(s) leaked in 2 allocation(s).

Analysis:
`getout()` may run during `free_all_mem()` (that's why it checks
`!entered_free_all_mem`). If that happens, the second `os_exit()`
returns early from `free_all_mem()` then `exit()` is called and Lua
state is never closed.

Solution:
Always call `nlua_free_all_mem()` in the early-return case.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(options): ":set foo?" for Lua callbacks #41100</title>
<updated>2026-08-01T14:07:26+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-08-01T14:07:26+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=e02755cd9ff29277d14421c9df627e5dc48e4f67'/>
<id>e02755cd9ff29277d14421c9df627e5dc48e4f67</id>
<content type='text'>
Problem:
`:set foo=&lt;tab&gt;` and `:set foo?` for func/expr options set to a Lua
function, always displays "v:lua".

The existing "&lt;Lua N: file:line&gt;" form was avoided because the ref id
N changes on every read of the same option.

Solution:
- Don't attempt to tab-complete Lua functions.
- Show "&lt;Lua file:line&gt;" (or "&lt;Lua&gt;" if source file is unknown).

Example:

    :set operatorfunc?
      operatorfunc=&lt;Lua ~/.config/nvim/init.lua:42&gt;</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
`:set foo=&lt;tab&gt;` and `:set foo?` for func/expr options set to a Lua
function, always displays "v:lua".

The existing "&lt;Lua N: file:line&gt;" form was avoided because the ref id
N changes on every read of the same option.

Solution:
- Don't attempt to tab-complete Lua functions.
- Show "&lt;Lua file:line&gt;" (or "&lt;Lua&gt;" if source file is unknown).

Example:

    :set operatorfunc?
      operatorfunc=&lt;Lua ~/.config/nvim/init.lua:42&gt;</pre>
</div>
</content>
</entry>
<entry>
<title>refactor(exmode): Ex-mode as cmdwin + Lua #40991</title>
<updated>2026-07-27T10:25:21+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-27T10:25:21+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=359459dec6e1929c0afb56a3111dee7b5a924eea'/>
<id>359459dec6e1929c0afb56a3111dee7b5a924eea</id>
<content type='text'>
Problem:
POSIX-compatible Ex-mode requires special-cases all over the codebase to
match various quirks that don't actually matter to users.
- The main utility of *interactive* Ex-mode is its REPL behavior, and
  that can be achieved with `cmdwin`, which also gains extra UX
  benefits.
- The main utility of *non-interactive* `nvim -es` is for shell
  scripting, where Ex-mode quirks are mostly unhelpful (e.g. the
  "Entering Ex mode" message).

Solution:
- Reimplement *interactive* Ex-mode as a "persistent, insert-mode
  cmdwin" in Lua.
  - "nvim -e/-E" is simply an alias to "gQ".
- Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode".
  - Drop POSIX Ex-mode quirks.

Improvements:
- "nvim -V1 -es" output ends with a final newline!
- "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was
  pointless noise, unwanted for scripting purposes.)
- stdin is no longer typeahead. Scripts (":lua io.read()") can read
  stdin as data.
- Empty line is a no-op: a stray blank line no longer moves the cursor
  (deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501).

Preserved behavior:
- cursor starts at "$"
- mode()=="cv" (for non-interactive)
- multiline commands (:append/:function/heredoc pull continuation lines)
- bare-range print
- :print=&gt;stdout
- -V1=&gt;stderr
- CRLF input
- continue-after-error and exit codes

Dropped (regressed) POSIX behavior (non-interactive):
- Event loop only ticks while/between commands, not while blocked
  waiting for a stdin line.
- ":g/pat/visual...Q"
- input()/getchar()/":s/x/y/c" no longer consume stdin lines as
  answers: Nvim stops at end-of-input, skipping the rest of the script,
  exit 0. Use ":lua io.read()" instead.
  - If users care about this they should use interactive Ex-mode (`gQ`).
- ":@r" stops at end of the register instead of continuing to read
  cmdline input from stdin.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
POSIX-compatible Ex-mode requires special-cases all over the codebase to
match various quirks that don't actually matter to users.
- The main utility of *interactive* Ex-mode is its REPL behavior, and
  that can be achieved with `cmdwin`, which also gains extra UX
  benefits.
- The main utility of *non-interactive* `nvim -es` is for shell
  scripting, where Ex-mode quirks are mostly unhelpful (e.g. the
  "Entering Ex mode" message).

Solution:
- Reimplement *interactive* Ex-mode as a "persistent, insert-mode
  cmdwin" in Lua.
  - "nvim -e/-E" is simply an alias to "gQ".
- Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode".
  - Drop POSIX Ex-mode quirks.

Improvements:
- "nvim -V1 -es" output ends with a final newline!
- "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was
  pointless noise, unwanted for scripting purposes.)
- stdin is no longer typeahead. Scripts (":lua io.read()") can read
  stdin as data.
- Empty line is a no-op: a stray blank line no longer moves the cursor
  (deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501).

Preserved behavior:
- cursor starts at "$"
- mode()=="cv" (for non-interactive)
- multiline commands (:append/:function/heredoc pull continuation lines)
- bare-range print
- :print=&gt;stdout
- -V1=&gt;stderr
- CRLF input
- continue-after-error and exit codes

Dropped (regressed) POSIX behavior (non-interactive):
- Event loop only ticks while/between commands, not while blocked
  waiting for a stdin line.
- ":g/pat/visual...Q"
- input()/getchar()/":s/x/y/c" no longer consume stdin lines as
  answers: Nvim stops at end-of-input, skipping the rest of the script,
  exit 0. Use ":lua io.read()" instead.
  - If users care about this they should use interactive Ex-mode (`gQ`).
- ":@r" stops at end of the register instead of continuing to read
  cmdline input from stdin.</pre>
</div>
</content>
</entry>
<entry>
<title>feat(eval): declare more "fast" functions #40834</title>
<updated>2026-07-19T14:03:53+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-19T14:03:53+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=239125b8c8ae699beaf0753fd4042fdeb2da0ff5'/>
<id>239125b8c8ae699beaf0753fd4042fdeb2da0ff5</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor(input): rename getchar.c =&gt; input.c #40698</title>
<updated>2026-07-12T12:34:13+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-07-12T12:34:13+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=d25ae8b8c20cc19bc579946ea36117c0a1b378d0'/>
<id>d25ae8b8c20cc19bc579946ea36117c0a1b378d0</id>
<content type='text'>
Problem:
`getchar.c` is a quirky name and doesn't align with our existing
`os/input.c` and `tui/input.c` modules, which encompass the same topic
at different layers.

Solution:
Rename `getchar.c` =&gt; `input.c` for discoverability.

Introduce `dialog.c` for functionality related to showing confirm
prompts, dialogs, etc.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
`getchar.c` is a quirky name and doesn't align with our existing
`os/input.c` and `tui/input.c` modules, which encompass the same topic
at different layers.

Solution:
Rename `getchar.c` =&gt; `input.c` for discoverability.

Introduce `dialog.c` for functionality related to showing confirm
prompts, dialogs, etc.</pre>
</div>
</content>
</entry>
</feed>
