Problem:
BufModifiedSet autocmd only triggered for current buffer during
redraw, causing delayed events when :wa writes non-current buffers.
Solution:
- Use the aucmd_defer approach to implement `Optionset modified`.
- Drop BufModifiedSet.
Problem: A vim.ui_attach() callback that redraws to show a 'verbose'
regex message during 'incsearch' results in recusive redrawing.
Solution: Check that curwin was redrawn instead of just any window when
determining if 'incsearch' highlighting was cleared.
Problem: Cannot apply 'scrolloff' context lines at end of file
Solution: Add the 'scrolloffpad' option to keep 'scrolloff' context even
when at the end of the file (McAuley Penney).
closes: vim/vim#19040a414630393
Co-authored-by: McAuley Penney <jacobmpenney@gmail.com>
Problem: Several win_T fields are declared as "int" or "char" but are
used strictly as boolean flags with TRUE/FALSE values. The
integer types obscure the boolean intent and are wider than
needed.
Solution: Change the following win_T members to bool (stdbool.h) and
update their assignments from TRUE/FALSE to true/false
accordingly.
The following conversions have been done:
- int -> bool (10 members):
w_set_curswant, w_botfill, w_old_botfill, w_do_win_fix_cursor,
w_popup_fixed, w_border_highlight_isset, w_cline_folded,
w_redr_status, w_arg_idx_invalid, w_has_scrollbar
- char -> bool (4 members):
w_topline_was_set, w_ru_empty, w_fold_manual, w_foldinvalid
No existing code compares these members against TRUE/FALSE explicitly or
uses ++/-- / bitwise ops on them, so only plain assignments are
affected.
Excluded:
- w_locked (recursion counter with ++/--),
- w_want_scrollbar (may hold -1 from dict_get_bool),
- w_winbar_height (used in arithmetic and exposed as number via
getwininfo()).
related: vim/vim#20005
closes: vim/vim#20008146d5da0d1
Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Problem:
- Unable to "pin" a window to prevent closing without specifically
being targeted.
- :fclose closes hidden windows (even before visible windows).
Solution:
- Add 'winpinned' window-local option. When set, window is skipped by
:fclose and :only. Pin the ui2 cmdline window (which should always be
visible), so that it is not closed by :only/fclose.
- Skip over hidden (and pinned) windows with :fclose.
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: w_locked can be bypassed when recursively set if not restored
to its prior value.
Solution: Rather than save/restore everywhere, just make it a count,
like other locks (Sean Dewar)
Requires the previous commit, otherwise b_nwindows will be wrong in
tests, which causes a bunch of weird failures.
closes: vim/vim#197287cb43f286e
Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Problem:
Currently, we recommend always inserting text above prompt-line in
prompt-buffer. This can be done using the `:` mark. However, although
we recommend it this way it can sometimes get confusing how to do it
best.
Solution:
Provide an api to append text to prompt buffer. This is a common
use-case for things using prompt-buffer.
Problem: cannot display tabs for indentation
Solution: Add the "leadtab" value to the 'listchars' option to
distinguish between tabs used for indentation and tabs used
for alignment (HarshK97).
closes: vim/vim#190948526d32647
Co-authored-by: HarshK97 <harshkapse1234@gmail.com>
Problem: Setting 'winhighlight' doesn't after setting global namespace
using nvim_win_set_hl_ns().
Solution: Check if using another namespace when setting 'winhighlight'
instead of disabling 'winhighlight' in nvim_win_set_hl_ns().
Problem: TabClosedPre may be triggered twice for the same tab page when
closing another tab page in BufWinLeave (after 9.1.1211).
Solution: Store whether TabClosedPre was triggered in tabpage_T
(zeertzjq).
Also fix the inconsistency that :tabclose! triggers TabClosedPre after
a failed :tabclose, but :close! doesn't even if there is only one window
in the tab page.
closes: vim/vim#192119168a04e0c
Problem: 'fsync' option cannot be set per buffer
Solution: Make 'fsync' option global-local
(glepnir)
closes: vim/vim#190194d5b303726
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: After :botright copen and closing the quikfix window, the
cursor ends up in the wrong window. The problem is fr_child
always points to the first (leftmost for FR_ROW, topmost for
FR_COL) child frame. When do :vsplit, the new window is
created on the left, and frame_insert() updates the parent's
fr_child to point to this new left window.
Solution: Create a snapshot before open the quickfix window and restore
it when close it (glepnir).
closes: vim/vim#18961b43f9ded7e
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: completion: complete_match() Vim script function and
'isexpand' option are not that useful and confusing
(after v9.1.1341)
Solution: Remove function and option and clean up code and documentation
(Girish Palya).
complete_match() and 'isexpand' add no real functionality to Vim. They
duplicate what `strridx()` already does, yet pretend to be part of the
completion system. They have nothing to do with the completion mechanism.
* `f_complete_match()` in `insexpand.c` does not call any completion code.
It’s just a `STRNCMP()` wrapper with fluff logic.
* `'isexpand'` exists only as a proxy argument to that function.
It does nothing on its own and amounts to misuse of a new option.
The following Vim script function can be used to implement the same
functionality:
```vim
func CompleteMatch(triggers, sep=',')
let line = getline('.')->strpart(0, col('.') - 1)
let result = []
for trig in split(a:triggers, a:sep)
let idx = strridx(line, trig)
if l:idx >= 0
call add(result, [idx + 1, trig])
endif
endfor
return result
endfunc
```
related: vim/vim#16716fixes: vim/vim#18563closes: vim/vim#18790cbcbff8712
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: Cannot configure the inner foldlevel indicator for the
foldcolumn
Solution: Add "foldinner" suboption value to the 'fillchar' option
(Maria José Solano).
closes: vim/vim#183651a691afd27
Co-authored-by: Maria José Solano <majosolano99@gmail.com>
Problem: Option insecure flags not copied when splitting window.
Solution: Move window-local insecure flags to winopt_T and copy them
properly (zeertzjq).
closes: vim/vim#18434b3740f4b00
Problem: 'nowrap' in a modeline may hide malicious code.
Solution: Forcibly use '>' as 'listchars' "extends" if 'nowrap' was set
from a modeline (zeertzjq).
Manual `:setlocal nowrap` disables this behavior. There is a separate
problem with `:set nowrap` that also applies to some other options.
related: vim/vim#18214
related: vim/vim#18399closes: vim/vim#184259d5208a931
Cherry-pick some test_modeline.vim changes from patches 9.0.{0363,0626}.
Problem: completion: 'autocomplete' cannot be enabled per buffer
(Tomasz N)
Solution: Make 'autocomplete' global or local to buffer (Girish Palya)
fixes: vim/vim#18320closes: vim/vim#183330208b3e80a
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: TextChangedT fires depending on whether Nvim needs to update_screen
while in terminal mode. This makes little sense as redraws can be completely
unrelated to the terminal. Also, TextChanged could be fired from changes in
terminal mode after returning to normal mode.
Solution: trigger it when b:changedtick changes, like other such events. Happens
when invalid cells are refreshed, though is no longer affected by cursor
changes. Don't fire TextChanged from changes in terminal mode after leaving.
Unlike the other TextChanged* events, I've elected to not have it be influenced
by typeahead. Plus, unlike when leaving insert mode when no TextChangedI events
are defined, I don't trigger TextChanged when returning to normal mode from
changes in terminal mode (is that a Vim bug?)
Curiously, Vim's TextChangedT is different; it's tied to its terminal cursor
redraws, which triggers pretty eagerly (but is unaffected by unrelated redraws)
- usually *twice* when data is sent to the terminal (regardless of whether it
causes any visible changes, like incomplete escape codes; wasn't true for Nvim).
Not clear to me how this event was actually intended to work, but this seems to
make the most sense to me.
Problem: completion: cannot use autoloaded funcs in 'complete' F{func}
(Maxim Kim)
Solution: Make it work (Girish Palya)
fixes: vim/vim#17869closes: vim/vim#178851bfe86a7d3
Cherry-pick Test_omni_autoload() from patch 8.2.3223.
Co-authored-by: Girish Palya <girishji@gmail.com>
Problem: not possible to anchor specific lines in diff mode
Solution: Add support for the anchoring lines in diff mode using the
'diffanchor' option (Yee Cheng Chin).
Adds support for anchoring specific lines to each other while viewing a
diff. While lines are anchored, they are guaranteed to be aligned to
each other in a diff view, allowing the user to control and inform the
diff algorithm what the desired alignment is. Internally, this is done
by splitting up the buffer at each anchor and run the diff algorithm on
each split section separately, and then merge the results back for a
logically consistent diff result.
To do this, add a new "diffanchors" option that takes a list of
`{address}`, and a new "diffopt" option value "anchor". Each address
specified will be an anchor, and the user can choose to use any type of
address, including marks, line numbers, or pattern search. Anchors are
sorted by line number in each file, and it's possible to have multiple
anchors on the same line (this is useful when doing multi-buffer diff).
Update documentation to provide examples.
This is similar to Git diff's `--anchored` flag. Other diff tools like
Meld/Araxis Merge also have similar features (called "synchronization
points" or "synchronization links"). We are not using Git/Xdiff's
`--anchored` implementation here because it has a very limited API
(it requires usage of the Patience algorithm, and can only anchor
unique lines that are the same across both files).
Because the user could anchor anywhere, diff anchors could result in
adjacent diff blocks (one block is directly touching another without a
gap), if there is a change right above the anchor point. We don't want
to merge these diff blocks because we want to line up the change at the
anchor. Adjacent diff blocks were first allowed when linematch was
added, but the existing code had a lot of branched paths where
line-matched diff blocks were handled differently. As a part of this
change, refactor them to have a more unified code path that is
generalized enough to handle adjacent diff blocks correctly and without
needing to carve in exceptions all over the place.
closes: vim/vim#176150d9160e11c
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
Problem:
Cannot enter multiline prompts in a buftype=prompt buffer.
Solution:
- Support shift+enter (`<s-enter>`) to start a new line in the prompt.
- Pasting multiline text via OS paste, clipboard, "xp, etc.
- A/I in editable region works as usual.
- i/a/A/I outside of editable region moves cursor to end of current
prompt.
- Support undo/redo in prompt buffer.
- Support o/O in prompt buffer.
- Expose prompt location as `':` mark.
Problem: The 'grepformat' option is global option, but it would be
useful to have it buffer-local, similar to 'errorformat' and
other quickfix related options (Dani Dickstein)
Solution: Add the necessary code to support global-local 'grepformat',
allowing different buffers to parse different grep output
formats (glepnir)
fixes: vim/vim#17316closes: vim/vim#173157b9eb6389d
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: [security]: Possible to open more windows into a closing
buffer without splitting, bypassing existing "b_locked_split"
checks and triggering use-after-free
Solution: Disallow switching to a closing buffer. Editing a closing
buffer (via ":edit", etc.) was fixed in v9.1.0764, but add an
error message and check just "b_locked_split", as "b_locked"
is necessary only when the buffer shouldn't be wiped, and may
be set for buffers that are in-use but not actually closing.
(Sean Dewar)
closes: vim/vim#172466cb1c82840
Problem: UIs implementing ext_cmdline/message must also implement
ext_popupmenu in order to get cmdline completion with
wildoptions+=pum.
Solution: Allow marking a window as the ext_cmdline window through
nvim_open_win(), including prompt offset. Anchor the cmdline-
completion popupmenu to this window.
clarify complete_match() documentation to better explain its backward
search behavior, argument handling, and return value format and add an
example of isexpand
closes: https://github.com/vim/vim/pull/17212ffc89e47d0
Problem: Cannot define completion triggers and act upon it
Solution: add the new option 'isexpand' and add the complete_match()
function to return the completion matches according to the
'isexpand' setting (glepnir)
Currently, completion trigger position is determined solely by the
'iskeyword' pattern (\k\+$), which causes issues when users need
different completion behaviors - such as triggering after '/' for
comments or '.' for methods. Modifying 'iskeyword' to include these
characters has undesirable side effects on other Vim functionality that
relies on keyword definitions.
Introduce a new buffer-local option 'isexpand' that allows specifying
different completion triggers and add the complete_match() function that
finds the appropriate start column for completion based on these
triggers, scanning backwards from cursor position.
This separation of concerns allows customized completion behavior
without affecting iskeyword-dependent features. The option's
buffer-local nature enables per-filetype completion triggers.
closes: vim/vim#16716bcd5995b40
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: not possible to configure the completion menu truncation
character
Solution: add the "trunc" suboption to the 'fillchars' setting to
configure the truncation indicator (glepnir).
closes: vim/vim#17006b87620466c
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: Computed previous buffer line count may be beyond end of
buffer. This results in signs being removed from `b_signcols`
that were never included in it, tripping an assertion.
Solution: Store the previous line count as it was before appending or
deleting lines. Use it to clamp the edited region when
clearing signs before a splice, after which it is reset.
Problem: Typos in code and docs related to 'diffopt' "inline:".
(after v9.1.1243)
Solution: Fix typos and slightly improve the docs.
(zeertzjq)
closes: vim/vim#169975a307c361c
Problem: Diff mode's inline highlighting is lackluster. It only
performs a line-by-line comparison, and calculates a single
shortest range within a line that could encompass all the
changes. In lines with multiple changes, or those that span
multiple lines, this approach tends to end up highlighting
much more than necessary.
Solution: Implement new inline highlighting modes by doing per-character
or per-word diff within the diff block, and highlight only the
relevant parts, add "inline:simple" to the defaults (which is
the old behaviour)
This change introduces a new diffopt option "inline:<type>". Setting to
"none" will disable all inline highlighting, "simple" (the default) will
use the old behavior, "char" / "word" will perform a character/word-wise
diff of the texts within each diff block and only highlight the
differences.
The new char/word inline diff only use the internal xdiff, and will
respect diff options such as algorithm choice, icase, and misc iwhite
options. indent-heuristics is always on to perform better sliding.
For character highlight, a post-process of the diff results is first
applied before we show the highlight. This is because a naive diff will
create a result with a lot of small diff chunks and gaps, due to the
repetitive nature of individual characters. The post-process is a
heuristic-based refinement that attempts to merge adjacent diff blocks
if they are separated by a short gap (1-3 characters), and can be
further tuned in the future for better results. This process results in
more characters than necessary being highlighted but overall less visual
noise.
For word highlight, always use first buffer's iskeyword definition.
Otherwise if each buffer has different iskeyword settings we would not
be able to group words properly.
The char/word diffing is always per-diff block, not per line, meaning
that changes that span multiple lines will show up correctly.
Added/removed newlines are not shown by default, but if the user has
'list' set (with "eol" listchar defined), the eol character will be be
highlighted correctly for the specific newline characters.
Also, add a new "DiffTextAdd" highlight group linked to "DiffText" by
default. It allows color schemes to use different colors for texts that
have been added within a line versus modified.
This doesn't interact with linematch perfectly currently. The linematch
feature splits up diff blocks into multiple smaller blocks for better
visual matching, which makes inline highlight less useful especially for
multi-line change (e.g. a line is broken into two lines). This could be
addressed in the future.
As a side change, this also removes the bounds checking introduced to
diff_read() as they were added to mask existing logic bugs that were
properly fixed in vim/vim#16768.
closes: vim/vim#168819943d4790e
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
Problem: Since 3cb1e825, all windows with 'statuscolumn' set, and a
resized 'signcolumn' for a particular buffer are marked
to be fully redrawn when the first window is encountered.
The "resized" variable is only unset after all windows have
been drawn, so this results in windows that have just been
draw to be marked for redraw again, even though the
signcolumn did not change size again.
Solution: Replace the `resized` variable with a `last_max` variable that
is changed when the first window into buf is encountered.
Problem: _on_conceal_line callbacks are not invoked if callback has not
let Nvim know it wants to receive them. But this may change on
factors other than what is currently checked (changed buffer).
Solution: Forego this optimization, callback is still guarded behind
'conceallevel'.
TSHighlighter now places marks for conceal_lines metadata. A new
internal decor provider callback _on_conceal_line was added that
instructs the highlighter to place conceal_lines marks whenever the
editor needs to know whether a line is concealed. The bundled markdown
queries use conceal_lines metadata to conceal code block fence lines.
Problem: When calling an API from Vimscript to set an option, mapping,
etc., :verbose shows that it's set from an API client.
Solution: Don't override current_sctx.sc_sid when calling an API from
Vimscript. Also fix the inverse case where API channel id is
not set when calling an API from RPC. Move channel id into
sctx_T to make saving and restoring easier.
Related #8329
vim-patch:partial:9.1.1084: Unable to persistently ignore events in a window and its buffers
Problem: Unable to persistently ignore events in a window and its buffers.
Solution: Add 'eventignorewin' option to ignore events in a window and buffer
(Luuk van Baal)
Add the window-local 'eventignorewin' option that is analogous to
'eventignore', but applies to a certain window and its buffers. Identify
events that should be allowed in 'eventignorewin', adapt "auto_event"
and "event_tab" to encode this information. Window context is not passed
onto apply_autocmds_group(), and when to ignore an event is a bit
ambiguous when "buf" is not "curbuf", rather than a large refactor, only
ignore an event when all windows into "buf" are ignoring the event.
b7147f8236
vim-patch:9.1.1102: tests: Test_WinScrolled_Resized_eiw() uses wrong filename
Problem: tests: Test_WinScrolled_Resized_eiw() uses wrong filename
(Luuk van Baal, after v9.1.1084)
Solution: Rename the filename to something more unique
bfc7719e48
Problem: Anchoring a floating window to the tabline and laststatus is
cumbersome; requiring autocommands and looping over all
windows/tabpages.
Solution: Add new "tabline" and "laststatus" options to the `relative`
field of nvim_open_win() to place a window relative to.
"wininfo" is going to be my next victim. The main problem with wininfo
is that it is "all or nothing", i e either all state about a buffer in a
window is considered valid or none of it is. This needs to be fixed to
address some long running grievances.
For now this is just a warmup: refactor it from a linked list to a
vector.
Problem: Option metadata like list of valid values for an option and
option flags are not listed in the `options.lua` file and are instead
manually defined in C, which means option metadata is split between
several places.
Solution: Put metadata such as list of valid values for an option and
option flags in `options.lua`, and autogenerate the corresponding C
variables and enums.
Supersedes #28659
Co-authored-by: glepnir <glephunter@gmail.com>
Problem:
The way option scopes currently work is inflexible and does not allow for nested
option scopes or easily finding the value of an option at any arbitrary scope
without having to do long handwritten switch-case statements like in
`get_varp()`. `.indir` is also confusing and redundant since option indices for
each scope can be autogenerated.
Solution:
Expand option scopes in such a way that an option can support any amount of
scopes using a set of scope flags, similarly to how it's already done for option
types. Also make options contain information about its index at each scope it
supports. This allows for massively simplifying `get_varp()` and
`get_varp_scope()` in the future by just using a struct for options at each
scope. This would be done by creating a table that stores the offset of an
option's variable at a scope by using the option's index at that scope as a key.
This PR also autogenerates enums for option indices at each scope to remove the
need for `.indir` entirely, and also to allow easily iterating over options all
options that support any scope.
Ref: #29314
Problem: 'findexpr' can't be used for lambads
(Justin Keyes)
Solution: Replace the findexpr option with the findfunc option
(Yegappan Lakshmanan)
related: vim/vim#15905closes: vim/vim#15976a13f3a4f5d
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>