Problem: The zip autoload script aborts loading when the "zip"
command is not available, so even read-only browsing of an
archive fails with E117 (zip#Browse undefined) on systems
that have "unzip" but not "zip" (e.g. the Windows CI
runner). Regressed in b0e0b22.
Solution: Drop the load-time executable gate and check each command
per operation instead, so a missing "zip" only affects
writing. Update the test to match the reworded message.
e241ac0a62
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem:
The bundled `zip` plugin is implemented in Vimscript, making it harder to
maintain and build on with Nvim's Lua runtime infrastructure.
Solution:
Add an opt-out `zip.lua` browser backed by `nvim.dir`, and disable the legacy
Vimscript implementation by moving it to `pack/dist/opt/zip/`. Load it with
`:packadd zip`.
Problem:
Cmdline area shows stale ":" after backspacing out of the command line.
Solution:
Clear the command line for empty commands. Note that `:<CR>` will now
clear the command line too.
Problem: Installing plugins during lockfile synchronization always
writes the lockfile, even though its content is used during install.
This might be a problem if the lockfile (itself or its parent
directory) is not writeable (can only be read).
Solution: Do not write the lockfile when installing directly from it.
This is okay since the `src` and `rev` are used directly from the
lockfile and don't change at this step. While potential change in
`version` (that must be written to the lockfile) is handled in other
code path.
Problem:
commit_chars_str() reads a 0x80-0xBF byte as a 2-byte lead, so
"\xA9x" makes "x" a commit character. nvim_get_hl() returns
a dict, so `#` on it is 0 whether or not the group exists
Solution:
use vim.str_utf_end() and drop entries that are not one whole
character. use next check dict length.
Problem:
Tree-sitter uses UINT32_MAX for full-document ranges, which becomes -1 on 32-bit platforms and reaches _foldupdate as an invalid end row.
Solution:
Treat negative changed-range end rows as unbounded and clamp them to the buffer line count. Add a regression test that simulates the 32-bit sentinel.
AI-assisted: Codex
Problem:
Want `gQ` for _le multicursor_.
Solution:
- Don't use `gQ` for exmode.
- Introduce `:exmode`.
- Introduce `[count]q:` as an alias to `:exmode`.
Problem:
On NetBSD, `man -w open` can return the exact manpage path, but `:Man`
may still fail when man directories cannot be discovered from `manpath
-q`, bare `man -w`, or `$MANPATH`.
Solution:
Fall back to the direct manpage lookup when directory discovery fails.
Add a test for resolving `open(2)` through `goto_tag()` without manpath
data.
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=>stdout
- -V1=>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.
Lazy imports (PEP 810, to be released in Python 3.15) introduces a
`lazy` soft keyword that's recognized when it precedes a `from` or
`import` keyword.
closes: vim/vim#20342916809ae1e
Co-authored-by: Jon Parise <jon@indelible.org>
Problem: s:SearchBracket()'s skip-expression matches syntax group
names ending in "Comment", "Todo", or "String" to decide
whether a candidate bracket is inside a string/comment
and should be skipped for indentation purposes. Byte and
raw-byte string literals (b"...", rb"...") are highlighted
via the pythonBytes/pythonRawBytes syntax groups, which
don't end in "String", so brackets inside them (e.g.
b"[") were never skipped and were counted as real,
unmatched brackets, producing incorrect indentation.
Solution: Add "Bytes" to the indent script's existing suffix match,
so pythonBytes/pythonRawBytes are recognized directly, the
same way pythonString/pythonFString/pythonRawString
already are.
This supersedes an earlier version of this fix that
renamed pythonBytes/pythonRawBytes to
pythonBytesString/pythonRawBytesString in
runtime/syntax/python.vim.
fixes: vim/vim#20812closes: vim/vim#20827f88e7191da
Co-authored-by: qwavies <qwavsbusiness@gmail.com>
## Flicker cause
ui2's `check_targets()` function creates the hidden ui2 windows with this call chain:
```
nvim_open_win()
win_set_buf()
do_buffer()
set_curbuf()
enter_buffer()
```
and `enter_buffer()` sets `need_fileinfo`:
fdc09be03c/src/nvim/buffer.c (L1837-L1839)
This is then picked up by `normal_redraw`:
fdc09be03c/src/nvim/normal.c (L1381-L1385)
The fileinfo message then causes a ui2 window to appear to display it:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L325-L330)
... which ends up calling `set_pos`, which registers an `on_key` handler:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L726-L728)
This handler closes the ui2 window when the user presses, for example, `l` (because the user's not focusing said window).
The handler eventually calls `check_targets()`:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L594-L595)
and `check_targets()` takes us back to the beginning, causing the ui2 window flicker
## Repro
```vim
=require("vim._core.ui2").enable()
set ch=0 shm-=F ve=all
e /tmp/x
```
Then hit `Ctrl-G` to show fileinfo (if not already shown) and hold `l`
## Fix
Effectively surround the ui2 window creating with `:silent`
Problem:
The code block query relied on a bug fixed in commit
7ed5609439, where a trailing newline was
not included in a node's text.
Solution:
Fix the query to expect the newline.
Problem:
After expanding tabs with the `expandtab` option, if the old indent
matches the requested one, `vim.text.indent()` returns the input
unchanged.
The optimization path assumes that if old_indent == size, the input
wouldn't be changed, which is not correct when old_indent is formed by
expanded tabs.
Solution:
Apply the optimization only when `expandtab` is not set.
'spellcapcheck' checks the first word in the file for a capital like any
sentence start: capcol is seeded to 0 for line 1 in spell_check_sblock().
This has been the case since the feature was added in v7.0100, so the note
that it "doesn't work for the first word in the file" is incorrect.
related: f9184a1d3151b5b727fec86c2ac0946c9c68df4d (code change)
related: 0d9c26dd8333aae4b20015f13fe2e8e1f07037bd (initial doc patch,
just a few minutes later)
related: vim/vim#20715e2d3e7818b
Co-authored-by: Christian Brabandt <cb@256bit.org>
Problem: `:browse edit` (and variants) without an argument fails instead
of opening a browser.
Solution: Dispatch to dir.lua using the cwd as the implied directory.
Replace the inherited GUI-only documentation with the supported
behavior. Support vsplit, split, tabedit variants.
Problem: When a tagfunc returns a "cmd" that is neither a line number nor
a search pattern, the tag entry is corrupted: the "kind" field is
lost and taglist() returns a mangled "cmd".
Solution: Accept any Ex command in "cmd" as in a tags file, terminate a
generic command with a bar so the trailing fields are preserved,
and reject a value that cannot be stored in a tag line with E987
(Hirohito Higashi).
fixes: vim/vim#20781
related: vim/vim#20790
closes: vim/vim#2082886adef19fc
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Mao-Yining <mao.yining@outlook.com>
Update the Go syntax file with some recent changes made to vim-go to
correctly highlight the second and later lines of concatenated strings
in var or const blocks.
closes: vim/vim#20835e9234b9b4a
Co-authored-by: Billie Cleek <bhcleek@gmail.com>
Problem: [security]: arbitrary Ex command execution during C
omni-completion (Threonine)
Solution: Match tags typeref literally to block Ex command injection
(Yasuhiro Matsumoto).
Escaping only "/" and "\" left the typeref able to break out of the
:vimgrep pattern without a "/": an unclosed "[" makes vimgrep's pattern
skipping fail, and the parser then treats a following "|" as a command
separator, so the tag value runs as Ex commands during C omni-completion.
Match the field literally with \V so no regex metacharacter can affect
pattern parsing.
Github Security Advisory:
https://github.com/vim/vim/security/advisories/GHSA-cx73-phcg-3j5g2f628d8104
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Changes:
- Removed the blank line before the first healthcheck header.
- Fixed a bug where the entire "Terminal" section of `vim.health` would
not appear if the `infocmp` executable was not found.
- Fixed a typo in `vim.lsp` when displaying the LSP log level.
Problem:
Options parsing is still painful for dict-style options.
Solution:
schema-maxxing => 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' => `fcs_tab`, 'listchars' => `lcs_tab`.
- `nvim_set_option_value`:
- Return the improved structures. Also from `vim.opt.x:get()`.
- Eliminate api <=> 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.