Commit Graph

1028 Commits

Author SHA1 Message Date
Ellison
9734f33bc7 feat(vim.net): request() accepts more http methods #39406 2026-05-01 06:54:44 -04:00
Justin M. Keyes
7c4845ff46 fix(ui): z=, tselect with async vim.ui.select
Problem:
After 55ceb31,  z= and tselect don't work if `vim.ui.select` is an async
provider (especially terminal buffers).

Solution:
Drop the `vim.wait()` approach, use an async approach.

fix #39506
2026-04-30 19:19:42 +02:00
Justin M. Keyes
18d7dd485b feat(ui): use vim.ui.select for :oldfiles, :recover
Problem:
followup to 55ceb314ca #39478
`:oldfiles` and swapfile `:recover` do not delegate to `vim.ui.select`.

Solution:
- Delegate to `vim.ui.select`.
- Fix a long-standing `recover_names` bug where `concat_fnames(dir_name,
  files[i], true)` produced malformed `<dir>//<dir>/<file>` paths (also
  fixes `swapfilelist()`).
2026-04-30 17:44:31 +02:00
bfredl
77a27076e8 Merge pull request #39469 from bfredl/systempipa
fix(vim.system): use REAL PIPES for vim.system, similar to jobs
2026-04-30 13:31:45 +02:00
bfredl
46fa9354b6 fix(vim.system): use REAL PIPES for vim.system, similar to jobs
This is essentially the #35991 fix for the #35984 issue,
but applied to vim.system().
2026-04-30 12:22:57 +02:00
Justin M. Keyes
55ceb314ca feat(ui): use vim.ui.select for :tselect, z= #39478
Problem:
`:tselect` and `z=` (spell suggest) have their own bespoke select menus.

Solution:
- Delegate to `vim.ui.select` instead.
- Bonus:
  - `:tselect` gains mouse support. `print_tag_list` didn't suport mouseclick.

This causes some minor regressions, which are not blockers:

- `z=` no longer draws the list right-left if 'rightleft' is set.
  - TODO: can/should `vim.ui.select` / `vim.fn.inputlist()` handle that?
- `:tselect`
  - No "column" headings (`# pri kind tag file`).
  - No highlighting: (HLF_T: tag name, HLF_D: file, HLF_CM: extra fields).
  - TODO: can `vim.ui.select()` support highlighted chunks (`[[text, hl_id], ...]`) ?

fix https://github.com/neovim/neovim/issues/25814
fix https://github.com/neovim/neovim/issues/31987
2026-04-28 18:29:17 -04:00
Lewis Russell
c822a2657c refactor(lua): move vim.wait into runtime Lua
Move vim.wait into runtime/lua/vim/_core/editor.lua and replace
the C entrypoint with narrow vim._core helpers for polling, UI
flushing, and interrupt checks.

Keep the existing interval semantics by retaining the dummy timer that
wakes the loop while it is otherwise idle.

Update the docs to describe the success return values correctly, and
adjust the test expectation for the new vim.validate() callback error.

AI-assisted: Codex
2026-04-27 11:33:47 +01:00
Luis Calle
0b7a291238 feat(vim.pos): accept buf=0 for current buf #39414 2026-04-26 06:34:18 -04:00
Justin M. Keyes
5c88492a13 fix(trust): always use "/" slashes in filepaths #39355
Problem:
We should not use "\" (backslashes) except where absolutely required.
See references in https://github.com/neovim/neovim/pull/37729

Solution:
There is no reason to use "\" slashes in the trust db, so don't.
2026-04-24 07:37:21 -04:00
Olivia Kinnear
645a588aa6 feat(excmd): add :uptime command #39331
Problem
Nvim marks its v:starttime, but there is no user-friendly way to get Nvim's uptime.

Solution
Add :uptime (based loosely on uptime(1)).
2026-04-23 17:11:59 -04:00
Justin M. Keyes
c42aea3d37 refactor(test): deduplicate trust tests #39354 2026-04-23 16:44:21 -04:00
Barrett Ruth
0a8218a2b4 fix(trust): hash unchanged empty buffers as empty files #39027
Problem:
`vim.secure.trust()` hashes an unchanged empty buffer as
a newline, so trusting an empty file by buffer never works.

Solution:
Hash unchanged empty-buffers `''` so buffer-based
trust matches the on-disk empty file.
2026-04-23 15:01:37 -04:00
Justin M. Keyes
4ceca862fc refactor(test): drop deprecated exc_exec #39242 2026-04-20 14:16:41 -04:00
Evgeni Chasnovski
3a4cc5db0b fix(lua): make vim._with() work with buf=0 and win=0 context #39151
Problem: Using `buf=0`/`win=0` context in `vim._with` should be
  equivalent to using explicit buffer/window identifier respectively.

Solution: Explicitly adjust context in case of `buf=0` or `win=0`.
2026-04-18 12:04:28 -04:00
Evgeni Chasnovski
6b9b4a1377 fix(vim.filetype): match() fails if g:ft_ignore_pat is not defined #39158
Problem: Calling `vim.filetype.match({ filename = '...', buf = ... })`
  during startup results in an error due to not yet defined
  `g:ft_ignore_pat`.

Solution: Add a guard to check `g:ft_ignore_pat` related properties only
  if the variable is defined. This also allows to simplify other tests
  which did not depend on `g:ft_ignore_pat` but required it explicitly
  set to work.
2026-04-18 06:50:28 -04:00
Justin M. Keyes
0d4d285bd2 perf(vim.fn): call Lua-implemented vim.fn.xx() directly #39166
Problem:
- Builtin "Vimscript" functions (f_xx) are mostly implemented in C.
  Partly that's because there is some boilerplate required to call out
  to Lua.
- Calls to `vim.fn.foo()` always marshall over the Lua <=> Vimscript
  ("typval") bridge, even if `fn.foo()` is implemented entirely in Lua:
  ```
  Lua => typval => Object => Lua => Object => typval => Lua.
  ```

Solution:
Functions declared in eval.lua with `func_lua` are implemented in
entirely in Lua (`_core/vimfn.lua`).

- `gen_eval.lua` wires `func_lua` entries to `lua_wrapper`, which handles
  the typval conversion for Vimscript callers (slow path).
- `nlua_call()` detects `func_lua` functions and calls the Lua
  implementation directly. This eliminates all conversion overhead for
  Lua callers (fast path).
- Validate at build-time that `func`, `func_float`, and `func_lua` are
  mutually exclusive.
- Migrate `hostname()` as a toy example, to show the idea.
2026-04-17 19:10:20 -04:00
Justin M. Keyes
646ce85aa5 refactor: update usages of deprecated "buffer" param #39089 2026-04-15 18:45:26 +00:00
Justin M. Keyes
71ac4db335 refactor(api): rename "window" to "win" (positional parameters) #39083
continues d0af4cd909.

This commit renames positional parameters. This is only "cosmetic", but
is intended to make it extra clear which name is preferred, since people
often copy existing code despite the guidelines in `:help dev-naming`.
2026-04-15 13:31:17 -04:00
Lewis Russell
1f53abf54b refactor(diagnostic): split diagnostic module
Extract the diagnostic implementation from
runtime/lua/vim/diagnostic.lua into focused internal modules covering
config, display, float rendering, jump/list helpers, namespace and
storage management, severity/shared utilities, and statusline support.

Move the builtin handlers into runtime/lua/vim/diagnostic/handlers/ and
keep runtime/lua/vim/diagnostic.lua as the public facade that lazily
dispatches to the split modules. This preserves the external
vim.diagnostic API while making the implementation easier to navigate
and reason about.

AI-assisted: Codex
2026-04-15 14:44:13 +01:00
Lewis Russell
55f9c2136e test: replace busted with local harness
Replace the busted-based Lua test runner with a repo-local harness.

The new harness runs spec files directly under `nvim -ll`, ships its own
reporter and lightweight `luassert` shim, and keeps the helper/preload
flow used by the functional and unit test suites.

Keep the file boundary model shallow and busted-like by restoring `_G`,
`package.loaded`, `package.preload`, `arg`, and the process environment
between files, without carrying extra reset APIs or custom assertion
machinery.

Update the build and test entrypoints to use the new runner, add
black-box coverage for the harness itself, and drop the bundled
busted/luacheck dependency path.

AI-assisted: Codex
2026-04-15 12:09:25 +01:00
Lewis Russell
e289f9579c fix(lua): make vim.deep_equal cycle-safe
AI-assisted: Codex
2026-04-15 09:26:45 +01:00
Maria Solano
c1c2648284 feat(snippet): support multiple sessions #29340 2026-04-10 10:08:10 -04:00
Ellison
45f50d238a feat(vim.net): custom request() headers #38837
Problem
Cannot specify headers in vim.net.request() call.

Solution
Support opts.headers in vim.net.request opts.
2026-04-10 09:55:57 -04:00
zeertzjq
9c5fba5df0 fix(messages): truncate warning messages only in display (#38901)
For now, add a private "_truncate" flag to nvim_echo, using a truncation
method similar to showmode().
2026-04-09 04:11:32 +00:00
ngicks
a165eee64f feat(vim.version): add __eq to vim.VersionRange #38881
Problem: vim.VersionRange had no __eq metamethod, so comparing 2 distinct
but same value instances always returned false. In vim.pack.add this caused
redundant lockfile rewrites, even when the resulting lockfile content was
unchanged.

Solution: Add __eq metamethod on vim.VersionRange
2026-04-08 13:33:00 -04:00
glepnir
af707dd242 fix(diagnostic): virtual_lines should anchor at end_lnum, not lnum #38701
Problem: Multi-line diagnostics always render virtual lines below lnum.

Solution: Use end_lnum when placing the virt_lines extmark.
2026-04-06 13:22:39 -04:00
Luis Calle
01be30f638 feat(vim.pos)!: require buf param on vim.pos, vim.range #38665
Problem: `buf` is optional even though its needed to perform conversions
and the ordering of `(buf, row, col)` is not consistent.

Solution: make `buf` mandatory on `vim.range` and `vim.pos` and enforce
the `buf, row, col` ordering
2026-04-06 11:51:36 -04:00
Tom Ampuero
6d420feaef fix(net): handle remote archive URLs via tar/zip browse #38744
Problem:
Opening .tar.gz or .zip URLs shows raw binary instead of using the archive plugins.

Solution:
Similar to the original netrw implementation, the autocmd should detect
archive URLs, download them to a temp file and the open them with
tar/zip handlers already bundled as vim plugins.
2026-04-05 15:22:26 -04:00
zeertzjq
a89d7dcb91 docs: misc (#38578) 2026-04-01 07:59:51 +08:00
Justin M. Keyes
44d1f82fbf test: failing "treesitter.get_parser() returns nil for >= 0.12" 2026-03-29 18:50:37 +02:00
Luis Calle
f3c2eb49ba feat: extend vim.Pos, vim.Range #36397
Problem:
Using nested `vim.Pos` objects to represent each `vim.Range` object
requires 3 tables for each `vim.Range`, which may be undesirable in
performance critical code. Using key-value tables performs worse than
using array-like tables (lists).

Solution:
Use array-like indices for the internal fields of both `vim.Pos` and
`vim.Range` objects. Use a metatable to allow users to access them like
if they were key-value tables.

---

Problem:
The `vim.Pos` conversion interface for `extmark` indexing does not take
into account the difference in how a position on top of a newline is
represented in `vim.Pos` and `extmark`.
- `vim.Pos`: for a newline at the end of row `n`, `row` takes the value
  `n + 1` and `col` takes the value `0`.
- `extmark`: for a newline at the end of for `n`, `row` takes the value
  `n` and `col` takes the value `#row_text`.

Solution:
Handle this in the `extmark` interface.

---

Problem:
Not all `to_xxx` interfaces have wrapping objects like `to_lsp`.

Solution:
Return unwrapped values in `to_xxx` interfaces where it makes sense.
Accept unwrapped values in "from" interfaces where it makes sense.

---

Problem:
`start` and `end` positions have different semantics, so they can't be
compared. `vim.Range` relies on comparing the `end` and `start` of two
ranges to decide which one is greater, which doesn't work as expected
because this of the different semantics.

For example, for the ranges:

    local a = {
      start = { row = 0, col = 22, },
      end_ = { row = 0, col = 24, },
    }
    local b = {
      start = { row = 0, col = 17, },
      end_ = { row = 0, col = 22, },
    }

in this code:

    local foo, bar = "foo",  "bar"
    --               |---||-|
    --                 b  a

The range `b` is smaller than the range `a`, but the current
implementation compares `b._end` (`col = 22`) and `a.start` (`col = 22`)
and concludes that, since `b.col` is not smaller than `a.col`, `b`
should be greater than `a`.

Solution:
- Use a `to_inclusive_pos` to normalize end positions inside of
  `vim.Range` whenever a comparison between a start and an end position
  is necessary.
2026-03-29 11:22:40 -04:00
Justin M. Keyes
0ac321a1d6 test: fix s390x failures
Problem:
failures in s390x CI.

Solution:
- runtime/lua/man.lua: parse_path() can return nil but 3 callers didn't handle it.
- skip some tests on s390x.

TODO:

- TODO: why "build/bin/xxd is not executable" on s390x?
- TODO: other failures, not addressed (see below).

OTHER FAILURES:

    FAILED   test/functional/treesitter/fold_spec.lua @ 87: treesitter foldexpr recomputes fold levels after lines are added/removed
    test/functional/treesitter/fold_spec.lua:95: Expected objects to be the same.
    Passed in:
    (table: 0x4013c18940) {
      [1] = '0'
      [2] = '0'
      [3] = '0'
     *[4] = '0'
      [5] = '0'
      ...
    Expected:
    (table: 0x4005acf900) {
      [1] = '0'
      [2] = '0'
      [3] = '>1'
     *[4] = '1'
      [5] = '1'
      ...

    stack traceback:
            (tail call): ?
            test/functional/treesitter/fold_spec.lua:95: in function <test/functional/treesitter/fold_spec.lua:87>

    FAILED   test/functional/treesitter/select_spec.lua @ 52: treesitter incremental-selection works
    test/functional/treesitter/select_spec.lua:63: Expected objects to be the same.
    Passed in:
    (string) 'bar(2)'
    Expected:
    (string) 'foo(1)'

    stack traceback:
            (tail call): ?
            test/functional/treesitter/select_spec.lua:63: in function <test/functional/treesitter/select_spec.lua:52>

    FAILED   test/functional/treesitter/select_spec.lua @ 69: treesitter incremental-selection repeat
    test/functional/treesitter/select_spec.lua:82: Expected objects to be the same.
    Passed in:
    (string) '2'
    Expected:
    (string) '4'

    stack traceback:
            (tail call): ?
            test/functional/treesitter/select_spec.lua:82: in function <test/functional/treesitter/select_spec.lua:69>

    FAILED   test/functional/treesitter/select_spec.lua @ 98: treesitter incremental-selection history
    test/functional/treesitter/select_spec.lua:111: Expected objects to be the same.
    Passed in:
    (string) 'bar(2)'
    Expected:
    (string) 'foo(1)'

    stack traceback:
            (tail call): ?
            test/functional/treesitter/select_spec.lua:111: in function <test/functional/treesitter/select_spec.lua:98>

    FAILED   test/functional/treesitter/select_spec.lua @ 186: treesitter incremental-selection with injections works
    test/functional/treesitter/select_spec.lua:201: Expected objects to be the same.
    Passed in:
    (string) 'lua'
    Expected:
    (string) 'foo'

    stack traceback:
            (tail call): ?
            test/functional/treesitter/select_spec.lua:201: in function <test/functional/treesitter/select_spec.lua:186>

    FAILED   test/functional/treesitter/select_spec.lua @ 216: treesitter incremental-selection with injections ignores overlapping nodes
    test/functional/treesitter/select_spec.lua:231: Expected objects to be the same.
    Passed in:
    (string) ' )'
    Expected:
    (string) ' foo('

    stack traceback:
            (tail call): ?
            test/functional/treesitter/select_spec.lua:231: in function <test/functional/treesitter/select_spec.lua:216>

    FAILED   test/functional/treesitter/select_spec.lua @ 307: treesitter incremental-selection with injections handles disjointed trees
    test/functional/treesitter/select_spec.lua:337: Expected objects to be the same.
    Passed in:
    (string) 'int'
    Expected:
    (string) '1}'

    stack traceback:
            (tail call): ?
            test/functional/treesitter/select_spec.lua:337: in function <test/functional/treesitter/select_spec.lua:307>

    ERROR    test/functional/treesitter/parser_spec.lua @ 562: treesitter parser API can run async parses with string parsers
    test/functional/treesitter/parser_spec.lua:565: attempt to index a nil value

    stack traceback:
            test/functional/testnvim/exec_lua.lua:124: in function <test/functional/testnvim/exec_lua.lua:105>
            (tail call): ?
            (tail call): ?
            test/functional/treesitter/parser_spec.lua:563: in function <test/functional/treesitter/parser_spec.lua:562>

    FAILED   test/functional/core/job_spec.lua @ 1157: jobs jobstop() kills entire process tree #6530
    test/functional/core/job_spec.lua:1244: retry() attempts: 94
    test/functional/core/job_spec.lua:1246: Expected objects to be the same.
    Passed in:
    (table: 0x401dd74b30) {
      [name] = 'sleep <defunct>'
      [pid] = 33579
      [ppid] = 1 }
    Expected:
    (userdata) 'vim.NIL'

    stack traceback:
            test/testutil.lua:89: in function 'retry'
            test/functional/core/job_spec.lua:1244: in function <test/functional/core/job_spec.lua:1157>
2026-03-29 13:36:56 +02:00
Yochem van Rosmalen
f29b3b5d45 feat(net): vim.net.request(outbuf) writes response to buffer #36164
Problem:
Non-trivial to write output of vim.net.request to buffer. Requires extra
code in plugin/net.lua which can't be reused by other plugin authors.

```
vim.net.request('https://neovim.io', {}, function(err, res)
  if not err then
    local buf = vim.api.nvim_create_buf(true, false)
    if res then
      local lines = vim.split(res.body, '\n', { plain = true })
      vim.api.nvim_buf_set_lines(buf, 0, -1, true, lines)
    end
  end
end)
```

Solution:
Accept an optional `outbuf` argument to indicate the buffer to write output
to, similar to `outpath`.

    vim.net.request('https://neovim.io', { outbuf = buf })

Other fixes / followups:
- Make plugin/net.lua smaller
- Return objection with close() method
- vim.net.request.Opts class
- vim.validate single calls
- Use (''):format(...) instead of `..`
2026-03-23 18:48:03 -04:00
skewb1k
9a5641b4b5 fix(lua): drop support for boolean buf in vim.keymap #38432
Problem:
`vim.keymap.*.Opts.buf` allows `boolean` aliases for more widely
used `integer?` values, `true` -> `0` and `false` -> `nil`. This
conversion is unnecessary and can be handled at call sites.

Solution:
As a follow-up to deprecating the `buffer` option, drop support for
boolean values for the new `buf` option. The deprecated `buffer`
continues to support booleans for backward compatibility.
2026-03-23 08:00:53 -04:00
benarcher2691
2069be281c fix(mpack): boundary values for negative integer encoding #37255
Problem:
libmpack encodes boundary values -129 and -32769 with wrong integer
sizes:
- -129 as int8 instead of int16
- -32769 as int16 instead of int32
because the boundary checks compare against the wrong values (e.g., lo
< 0xffffff7f instead of lo < 0xffffff80). This caused data corruption:
-129 would decode as 127.

Solution:
Fix off-by-one errors in the two's complement boundary constants:
0xffffff80 (-128, min int8) and 0xffff8000 (-32768, min int16).

Fixes #37202

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-21 17:07:33 -04:00
skewb1k
4d3a67cd62 feat(lua): replace buffer with buf in vim.keymap.set/del #38360
The `buffer` option remains functional but is now undocumented.
Providing both will raise an error. Since providing `buf` was disallowed
before, there is no code that will break due to using `buffer` alongside
`buf`.
2026-03-21 12:00:06 -04:00
Yochem van Rosmalen
72a63346d8 feat(stdlib): vim.fs.ext() returns file extension #36997
Problem:
Checking the extension of a file is done often, e.g. in Nvim's codebase
for differentiating Lua and Vimscript files in the runtime. The current
way to do this in Lua is (1) a Lua pattern match, which has pitfalls
such as not considering filenames starting with a dot, or (2)
fnamemodify() which is both hard to discover and hard to use / read if
not very familiar with the possible modifiers.

vim.fs.ext() returns the file extension including the leading dot of
the extension. Similar to the "file extension" implementation of many
other stdlibs (including fnamemodify(file, ":e")), a leading dot
doesn't indicate the start of the extension. E.g.: the .git folder in a
repository doesn't have the extension .git, but it simply has no
extension, similar to a folder named git or any other filename without
dot(s).
2026-03-20 05:08:00 -04:00
Juan Pablo Briones
f4f1149292 fix(options): vim.opt fails for 'fillchars' #37141
Problem:
When `to_vim_value[info.metatype](info, value)` is called, a list value
such as `{'eob:a'}` is treated like a map, which generates `1:eob:a`.

Note: commands like `:lua vim.opt.wildmode={'longest:full'}` are not an
issue because only cases harcoded in `key_value_options` have metatype `map`.

Solution:
Check for array type and use the same logic as in array metatypes.
2026-03-18 19:19:47 -04:00
Justin M. Keyes
680d25e5b3 fix(api): use standard error messages 2026-03-16 14:52:04 +01:00
glepnir
88a72efb46 fix(diagnostic): open_float() handles config.float function #31577
Problem:
The `float` field of vim.diagnostic.config can be a function,
but diagnostic.open_float() does not handle it correctly.

Solution:
Add handling for it in open_float().
2026-03-16 09:50:13 -04:00
luukvbaal
911337eb3c fix(normal): crash using :norm from vim.ui_attach shell message event #38283
Problem:  'showcmd' buffer is being populated for :norm commands, which
          can result in a recursive uv_run() when called from a msg_show
          vim.ui_attach callback for a shell message.

Solution: The 'showcmd' buffer is never displayed while executing a
          :normal command so prevent unnecessary work, avoiding the crash.
2026-03-13 09:36:44 -04:00
Oleh Volynets
caf7808591 feat(diagnostic): custom status format function #36696
Problem:  Statusline component of diagnostics allows only the default
          format "sign:count".

Solution: Extend vim.diagnostic.Opts.Status to allow a custom signs
          or formatting function that provides the status presentation.
2026-03-13 07:21:45 -04:00
Justin M. Keyes
7ea148a1dc docs: use "ev" convention in event-handlers
Problem:
In autocmd examples, using "args" as the event-object name is vague and
may be confused with a user-command.

Solution:
Use "ev" as the conventional event-object name.
2026-03-12 11:12:56 +01:00
Willaaaaaaa
c5146362d8 test: fs_spec fails if home is a symlink #38258 2026-03-12 05:46:18 -04:00
Justin M. Keyes
b8a976afda docs: api, messages, lsp, trust
gen_vimdoc.lua: In prepare for the upcoming release, comment-out the
"Experimental" warning for prerelease features.
2026-03-11 18:00:18 +01:00
Sean Dewar
137d5ab01d fix(api): merge split window config only on success
Problem: nvim_win_set_config may merge configs despite failing to configure a
split, and without applying necessary side-effects (like setting style=minimal
options). Plus, autocommands may apply a different config after the merge,
causing side-effects to apply for an outdated config.

Solution: merge configs last, only on success. Include fields only relevant to
splits. Properly set _cmdline_offset for splits.

Maybe better to disallow _cmdline_offset for splits instead, as the pum is
relative to cmdline_row anyway? (I didn't want to change behaviour too much)

Also use expect_unchanged in an unrelated test to quash a warning.
2026-03-08 19:41:33 +00:00
Yochem van Rosmalen
dc5d313d66 fix(vim.fs): joinpath() should ignore empty items #38077
Problem:
vim.fs.joinpath treats empty string as a path segment
(it adds a path separator for each empty item):

    print(vim.fs.joinpath('', 'after/lsp', '')) -- '/after/lsp/'
    print(vim.fs.joinpath('', '')) -- '/'

Especially problematic if the empty segment is the first segment, as
that converts the path to an absolute path.

Solution:
Ignore empty (length of 0) path segments.

Benchmark:

    local function test(func)
      local t = vim.uv.hrtime()
      for _ = 1, 100000, 1 do
        func('', 'this/is', 'a/very/long/path', '', 'it', 'really', 'is')
      end
      print(math.floor((vim.uv.hrtime() - t) / 1e6), 'ms')
    end

- with Iter():filter() --> 370 ms
- building new segments table --> 208 ms
- with vim.tbl_filter --> 232 ms
- Instead of gsub split on `/` in all parts --> 1870 ms
2026-02-27 17:45:07 -05:00
anondeveg
6ba32713ad feat(secure): allow 'path' parameter for trust action 'allow' (#38001) 2026-02-25 20:55:05 -06:00
luukvbaal
39c4e0f336 fix(messages): unwanted ext_messages newlines for confirm() #38045
Problem:  Newlines emitted with ext_messages intended to position
          the message/prompt on the message grid.
Solution: Don't emit these newlines with ext_messages, followup to 4260f73e.
2026-02-24 13:01:31 -05:00
wjyoung65
9aa936d892 test(ui): failure in lua/ui_spec.lua in headless OS (no GUI) #37975 2026-02-21 15:00:06 -05:00