| Commit message (Collapse) | Author | Age |
| |
|
|
|
|
|
|
| |
Problem:
By default, 'termpastefilter' removes TAB chars when pasting to a :terminal.
Very annoying, and does not improve "security".
Solution:
Drop "HT" from the 'termpastefilter' default.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem:
A number in 'iskeyword', 'isfname' or 'isident' that overflows (e.g. via
a modeline) hits abort() or an assert in getdigits_int().
Solution:
Parse the numbers non-strictly so an out-of-range value gives E474.
Fixes #42409
AI-assisted
|
| |
|
|
|
|
|
|
|
|
| |
Problem:
TM_DIRECTORY expands to the directory's basename, losing its parent path.
Solution:
Remove the tail modifier when expanding the current file's directory.
Extend the existing known-variable test to check the full directory path.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem: watchdirs() keeps its state in large nested callbacks in
_watch.lua, which makes its directory tracking logic harder to change.
Solution: Move the backend into its own module and store its state in a
WatchDirs instance. Split setup, event handling and cleanup into
methods. Extend the existing test to cover cancellation while a
directory stat is pending.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
After edits move diagnostic ranges, counted jumps resume searching from
their original positions. This can revisit the same diagnostic and hang
the default first/last diagnostic mappings.
Solution:
Advance the search origin using the diagnostic's current logical position.
Test forward and backward counted jumps after inserting or deleting a
line, including jumps to the last or first diagnostic without wrapping.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem:
Accepting an item from another completion source raises an error when its
user_data.nvim table does not contain LSP metadata.
Solution:
Retrieve and guard the nested LSP metadata before accessing its fields.
Cover acceptance of a foreign completion item without LSP metadata.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem:
An empty snippet insertText falls back to the label during selection, but
acceptance clears that label and expands an empty string.
Solution:
Require nonempty insertText before expanding a snippet without textEdit.
Extend the omnifunc acceptance fixture with an empty snippet insertion.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem:
A completion list default edit range can replace the explicit range of an
InsertReplaceEdit, filtering out valid items or changing their replacement.
Solution:
Only synthesize a default text edit when the completion item has none.
Extend the existing itemDefaults test for explicit edits with both range variants.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem:
Snippet completion words and previews prefer insertText even when textEdit
is present, although the actual expansion uses textEdit.newText.
Solution:
Use the text edit before the fallback insertion text in both selectors.
Extend the existing precedence test to check the snippet word and preview.
AI-assisted
|
| |
|
|
|
|
|
|
| |
Problem: Custom ui2 window tracks 'fillchars' option to adjust to the
change of `msgsep` flag. However, 'fillchars' is `:h global-local`
window option. If it is set locally to the window, ui2 reacts to its
`msgsep` value and keeps using it afterwards even in other windows.
Solution: Use and react to only global value of 'fillchars'.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: Highlight inspection is limited to a single position, and its
result types do not document the fields shared by different highlight
sources.
Solution: Accept end_row/end_col in vim.inspect_pos to inspect a range.
Keep range ends exclusive and retain the existing single-position
behavior.
Support Ex line ranges in :Inspect, including Visual selections.
Document named result types, expose shared highlight fields, and keep
the existing extmark details and buffer field for compatibility.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
When starting Nvim with both `--clean` and `--noplugin` (in either
order), `--noplugin` is silently ignored and built-in runtime plugins
are loaded anyway. `command_line_scan()` sets `p_lpl = false` for
`--noplugin`, and `--clean` sets `params.use_vimrc = "NONE"` and
`params.clean = true`, which later overwrites `p_lpl` back to `true` via
`p_lpl = vimrc_none ? params.clean : p_lpl`.
Solution:
Only reset `p_lpl = false` when `vimrc_none && !params.clean`,
preserving `p_lpl = false` if `--noplugin` was passed.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
Provider checks start and wait for a job, then execute the same command
again to obtain its output. The returned output can disagree with the
first process's exit status, and the second execution has no timeout.
Solution:
Return the first job's captured output. Bind the output callbacks to
their state and preserve line breaks between callback data entries.
Cover invocation count, multiline stdout, and merged stderr.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: nvim_set_option_value() dry runs skip checks in did_set_*
callbacks. This logic also prepares values needed to apply the option,
such as tab widths or a compiled regexp. Moving the checks into
validation callbacks needs a way to save that work for did_set_*.
Solution: Store prepared values in optset_T so did_set_* can consume
them after the option is stored. Dry runs perform the same validation,
then free the prepared values without changing live state.
This extends dry-run validation for:
- 'cedit': reject invalid command-line window keys.
- 'completeitemalign': require each completion column exactly once.
- 'cursorlineopt': reject empty values and conflicting line modes.
- 'encoding': accept only UTF-8 and its aliases.
- 'fileencoding': reject lists and local changes with 'nomodifiable'.
- 'messagesopt': require mandatory fields and enforce numeric limits.
- 'spellcapcheck': return regexp errors, including under :silent!.
- 'spellsuggest': reject conflicting suggestion modes.
- 'varsofttabstop' and 'vartabstop': reject invalid tab widths.
- 'wildmode': reject more than four completion stages.
'makeencoding' also uses the shared encoding preparation.
Separating value preparation exposed a bug in 'vartabstop' and
'varsofttabstop': failed assignments could discard local tab widths, and
global assignments could overwrite them. Fix this by preparing new
widths separately and applying them only after a valid local assignment.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
| |
vim.diagnostic.Opts.VirtualText has a `source` option to prefix
diagnostic messages with their source (`'if_many'` or always), but the
newer virtual_lines handler never got the same option, even though the
shared helpers it needs (diagnostic_shared.prefix_source/count_sources)
are already render-target-agnostic and used by virtual_text as-is.
Add the same `source` field to vim.diagnostic.Opts.VirtualLines and
apply it in the virtual_lines handler right after message formatting,
mirroring virtual_text's own ordering (format first, then prefix the
source onto the already-formatted message).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
vim-patch:9.2.1191: crash with "//e" when only a substitute pattern exists
Problem: Crash when using "//e" or "//" while there is a substitute
pattern but no previous search pattern (after v9.2.0374).
Solution: Use the previous pattern selected for an empty pattern
(Jonas Ornfelt).
related: vim/vim#19998
closes: vim/vim#21533
AI-assisted
https://github.com/vim/vim/commit/c58607c9a0579de0da909fc46f68144a01378af1
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
#42352
Problem:
- nvim_buf_call() aborts (assert) when called from an expression evaluated
for a window in another tabpage ('foldexpr', 'statusline'), because
`curwin` is not in `curtab`.
- After it returns, `curwin` is wrong if it switched windows.
- `vim._with{win=…, keepcwd=true}` does not undo `:lcd` if `win` is in
another tabpage.
Solution:
- Allow `curwin` outside `curtab`, and restore if it was outside
`curtab` at `ctx_switch()`.
- Find the target window in any tabpage when restoring its dirs.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
`nvim_set_option_value('fo', {'c','r','o'}, {operation='remove'})` does
nothing on "jcqrol": the items are joined into one `:set-=` value, which
only matches a contiguous substring. Removing map keys, e.g. {'eol','space'}
from 'listchars', never matches. `vim.opt:remove{…}` inherits this.
(Regression from f34ee3da80e8; 429338e74bf4 fixed the case where the
flags are adjacent and in order.)
Solution:
Remove each item separately.
|
| |
|
|
|
|
|
|
|
| |
Problem:
If a job exits with cursor at last row, the `[Process exited]` message
covers the text of that row.
Solution:
Start a new line before showing the message, like the old
`\r\n[Process exited]` did.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Problem:
After clearing cursors, "]C" "[C" do nothing, although the previous
cursor positions ("gQ") may still be useful as marks.
Solution:
If multicursor is not active, "]C" "[C" iterate the
"nvim.multicursor.last" extmarks. They also work as an operator motion
("d]C"), since there is no cascade.
AI-assisted
|
| |
|
|
|
|
|
|
|
| |
Problem: :detach! changes the channel's detach property without emitting
ChanInfo, so plugins watching channel updates cannot react to changes.
Solution: Schedule ChanInfo after setting detach=true. Add a test
covering emit on :detach!.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
`g@<C-v>j` and `y<C-v>j` set '] one char short of the block corner, so
'operatorfunc' cannot get the block. With 'virtualedit' "block", "y"
also yanks a short last line one column narrow.
Solution:
- Decide `inclusive` from the motion's own type, before get_op_vcol()
makes it blockwise (like Vim).
- Never exclude the end of a block from '] (`g@<C-v>l`): a block
includes its corner.
Co-authored-by: IcyJerry <263879414+Icyjerry@users.noreply.github.com>
Co-authored-by: Nagato Yuzuru <nagato@yuzuru.me>
|
| | |
|
| |
|
|
|
|
|
|
| |
Problem:
nvim_parse_cmd("'btab", {}) and typing ":'btab" crash, parse_cmdline()
continues with a NULL eap->cmd after an invalid :tab address.
Solution:
Fail if parse_command_modifiers() set an error.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
With 'ruler' in the cmdline ('laststatus=0') and ext_messages (ui2), a
'rulerformat' "%m" does not update the "[+]" indicator after ":write",
until a cursor-move.
Analysis:
`redraw_buf_status_later()` only marks windows with a statusline or
winbar. The symptom is hidden by the legacy message grid because the
write message overwrites the cmdline, which redraws the ruler.
Solution:
Also mark the cmdline 'ruler', like `status_redraw_buf()`.
|
| |
|
|
|
|
|
|
|
|
| |
Problem:
A Visual-mode mapping that reads input (`getchar()`) does not include
that input when cascading to other cursors (they only see ESC). OTOH,
Normal-mode mappings do replay the input.
Solution:
Append the payload to the Visual session's Lua-mapping subatom, and to the
session-ending command (`:<C-u>…` mapping).
|
| |
|
|
|
|
|
|
|
|
|
| |
Problem:
- `v:cascading` is false during the Insert-mode live-preview.
- `vim.on_key()` sees the internal keys of the Visual-selection preview
and "zq" steps.
Solution:
- Set `v:cascading` during the Insert-mode preview.
- Don't send internal keys to `on_key` callbacks.
- Use `v:cascading` as the source of truth for `mc_replaying()`.
|
| |
|
|
|
|
|
|
| |
Problem:
After `/\%Vfoo<CR>`, `zqn` places no cursors. `mc_zq_target()` clears
`'< '>` before `gn` (to detect a failed match), so `\%V` never matches.
Solution:
Keep the user's `'< '>` during `gn`; detect failure by its beep.
|
| |
|
|
|
| |
Problem: No way to check if cascade is in action.
Solution: Add `v:cascading` variable.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
With multicursors, an Insert-mode edit by a Lua/`<Cmd>` mapping or API
(nvim_put(), …) is live-previewed at the other cursors, but dropped at
ESC: the cascade replays _redo_, which does not contain such edits.
Solution:
When `<Cmd>`/Lua/RPC changes the buffer during Insert-mode, sync the
previews and restart the capture (like a non-captured cursor-move). The
edit stays as text.
- The mapping runs only at the primary. Its text is mirrored as-is
(similar to insert-completion). Re-running it per cursor would require
a "partial-remap" span replay, and breaks single-session plugins
(vim.snippet).
- Not during completion; redo already captures the pre-inserted
candidate on accept.
- Text typed before the edit is kept as mirrored, not replayed, so
per-cursor effects ('textwidth' wrapping, …) don't apply to it.
Known issues:
- "o"/"O"/"cc" with 'autoindent' followed by the mapping: the per-cursor
insert-entry replay is still pending, so the edit is lost.
|
| |
|
|
|
|
|
|
|
|
|
| |
Problem:
Handlers defer `show()` on unloaded buffers with a buffer-local BufRead
autocmd whose id is stored per-namespace:
- `noautocmd bwipeout` deletes the autocmd, so the next show/hide fails.
- Showing another buffer in the same namespace cancels the pending show.
Solution:
Handlers skip unloaded buffers. The existing global BufRead autocmd
shows cached diagnostics when the buffer loads.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
vim-patch:9.2.1175: setreg() block width wrong for unprintable chars
When yanking, the width of a <c-v>{motion}y register
is determined by the virtual colums of the text. However
in setreg() in 'b' mode use an idosyncratic width measurement
where C0 control chars (ASCII 0x00 - 0x19) and invalid UTF-8 bytes
have width 1 instead of their display width (2 or 4 cells).
Consider the following test case:
let strings = ['"reference', '"Übel', "\"aa\x07bb", "\"qq\x82", "\"x\nbabbel"]
for string in strings
call append('$', string)
exec "normal G0\<c-v>$\"ay"
let one = getregtype('a')
if string != strings[-1]
call setreg("b", string, 'b')
let two = getregtype('b')
else
let two = "na"
endif
call setreg("c", [string], 'b')
let three = getregtype('c')
call append('$', '"yank: '.one.", string: ".two.", list: ".three)
endfor
AFter this fix, all the three ways of measuring the width gives
equal values (or two, in the case of not being able to use setreg()
with a plain string in the first case)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
`nvim --embed --listen addr` always treats stdin as an RPC channel. If
stdin is /dev/null (e.g. backgrounded over ssh), the channel closes
before a UI can attach, so Nvim exits (detach=false behavior). If stdin
is a tty, keystrokes are read as RPC.
Solution:
With `--embed --listen`, open the stdio RPC channel only if stdin is
a pipe or socket. Else wait for a UI at the `--listen` address.
$ nvim --embed --listen ./nvim.sock
Nvim server (pid: 71984) waiting for UI, listening on: "./nvim.sock"
Note:
- No change when stdin is a pipe. So the test harness, TUI, and :restart
all behave exactly as before.
- The #29634 use-case of configuring a UI that attaches *after* startup
(a second UI, or reattach) still requires #25377 (reliable UIEnter).
Not affected by this change.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
Only the stdio channel can "own" a server (self-exit on close). After
:restart the TUI reconnects over a socket, so the restarted server does
not have "self-exit" behavior when the channel closes (e.g. by UI
disconnect, host-terminal close, etc.), which leaves a dangling server.
Solution:
- Introduce `nvim_chan_set`. (`nvim_set_client_info` doesn't fit:
exposing it to Lua would require a `channel` param, which is not
backwards-compatible, plus it's awkward because it doesn't merge info.)
- Broadcast per-channel properties in the "restart" UI event as an
opaque dict (a potentially useful pattern for other UI-events in the
future).
- UIs are expected to restore the channel properties on restart.
- `nvim_get_chan_info()` reports "detach".
- Remove `nvim__chan_set_detach()`.
|
| |\
| |
| | |
fix(lua): regression with `print()` in headless mode when redirecting
|
| | |
| |
| |
| |
| |
| |
| |
| |
| | |
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
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Problem:
nvim_open_term() sizes the terminal from the current window, which may
have 0 rows (bordered float, 'cmdheight' taking all rows). libvterm
aborts when resizing from 0 rows.
Solution:
In `terminal_alloc()`, treat zero width/height as the pty default
(80x24), like jobstart(term=true).
Open question:
nvim_win_get_height() on such a float returns -1 (winheight() returns 0).
|
| |\ \
| | |
| | | |
perf(watch): skip directories outside include glob prefixes
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Problem: watchdirs() scans and watches every directory that is not
excluded, even when a glob only matches files in one subtree. Some
language servers register absolute dependency filenames separately.
Neovim uses the workspace root for these string globs, so each extra
registration can scan and allocate libuv handles across the whole tree.
Solution: Keep each glob's literal directory prefix with its compiled
matcher. A directory must be allowed by both the include filter and at
least one watch rule. Skip unrelated subtrees, including new directories
created later. Keep ancestors watched so matching directories can still
be found. Report events only when they match the full patterns.
For example, watching /project for /project/src/**/*.lua only needs the
src tree and /project itself:
/project/ watched
|-- src/ watched
| `-- lib/ watched
|-- tests/ skipped
| `-- fixtures/ skipped
`-- vendor/ skipped
`-- pkg/ skipped
With no exclusions, this uses three watches instead of seven.
The gain can be large, but depends on the server's patterns and the
workspace layout. Separate watches for absolute dependency filenames can
skip most directories.
For example, a test workspace has 213 directories, including 201 under
build/. The two dependency files in this example are under packages/ and
styles/, so their watches can skip build/. Before this change, each
watch starts at the workspace root, scans all 213 directories and
creates 213 libuv handles.
With this change:
- Haskell Language Server: a separate watch for
/project/packages/demo/demo.cabal watches four directories: the
project root, packages/, demo/ and its src/ child. This cuts that
watch's scans and handles by 98%. With one broad source watch and this
dependency watch, the total falls by 49%.
- Tailwind CSS v4: a separate watch for the imported
/project/styles/themes/colors.css watches three directories: the
project root, styles/ and themes/. This cuts that watch's scans and
handles by 99%. With two broad watches and this dependency watch, the
total falls by 33%.
The broad watches still cover all 213 directories. The saving comes from
avoiding repeated scans and extra handles for each dependency watch.
Most servers with watch registrations in the survey do not benefit.
Their patterns match throughout the watch root, or their watches already
start at the relevant directory. In both cases, the glob prefix cannot
exclude more directories.
AI-assisted
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Problem: Globs such as '#generated/*.lua' fail to match their literal
paths. The parser consumes a leading '#' as its internal in-segment
flag.
Solution: Pass the flag as an LPeg match argument instead of inserting
it into the glob text. Cover literal and braced patterns with leading
hashes.
AI-assisted
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |