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: #19040
Signed-off-by: McAuley Penney <jacobmpenney@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: cannot style non-current window separator
Solution: Add the VertSplitNC highlighting group
(Hirohito Higashi).
Add VertSplitNC highlight group for vertical separators of non-current
windows, similar to StatusLine/StatusLineNC distinction. The separator
adjacent to the current window uses VertSplit, others use VertSplitNC.
Default: linked to VertSplit.
At the current window's status line rows, the separator cell is drawn as
a space with the StatusLine highlight so it blends into the status line
without a stray fillchar glyph.
Also:
- :redrawstatus[!] now also redraws vertical separators.
- statusline height changes trigger vsep redraw.
closes: #19951
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Cannot handle mouseclicks in the statusline
Solution: Add the %[FuncName] statusline item to define clickable
regions with a callback function. (Yasuhiro Matsumoto)
closes: #19841
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
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: #19728
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: close_buffer() callers incorrectly handle b_nwindows,
especially after nasty autocmds, allowing it to go
out-of-sync. May lead to buffers that can't be unloaded, or
buffers that are prematurely freed whilst displayed.
Solution: Modify close_buffer() and review its callers; let them
decrement b_nwindows if it didn't unload the buffer. Remove
some now unneeded workarounds like 8.2.2354, 9.1.0143,
9.1.0764, which didn't always work (Sean Dewar)
close_buffer() now doesn't decrement b_nwindows when not unloading buf, or when
buf isn't w_buffer after autocmds (they would've already decremented it).
Callers are now expected to decrement b_nwindows if w_buffer is not NULL after
close_buffer(), and when still intending to switch buffers or close win, for two
reasons:
- close_buffer() autocmds may have switched buffers. The new w_buffer's
b_nwindows would also need decrementing.
- After close_buffer(), callers may opt to not switch w_buffer or close win.
b_nwindows would need to be incremented again. (unless w_buffer is NULL from
being unloaded; callers are already forced to find a new buffer then)
These were the main causes of b_nwindows bugs, as these cases could not be
reliably detected, and went largely unhandled.
NOTE: if close_buffer() autocmds switch buffers, close_buffer() is not called
for that new buffer before decrementing b_nwindows. This may skip side-effects
like from 'bufhidden', but I think it's mostly harmless, and was already
happening in other places.
Let's see how this goes... Other details: (I have lots to say!)
It's OK to pass a win to close_buffer() that isn't showing buf (used by
set_curbuf()). In that case, we skip some side-effects and don't decrement
b_nwindows, but may still unload buf if hidden.
buf_freeall() now returns whether it freed anything. Removes some repeated
checks in close_buffer().
Preserve close_buffer()'s behaviour when called by win_free_popup() after its
popup was already removed from the window list. This made win_valid_any_tab()
return FALSE, so we skip things that originally checked it in that case.
Add "set_context" to close_buffer() to preserve do_ecmd()'s behaviour of only
setting b_last_cursor and/or calling buflist_setfpos() when not splitting
(see 7.2.041: https://groups.google.com/g/vim_dev/c/ZGgNvaylNzI/m/WHxjhnuxqB0J)
Without this, Test_marks_cmd() fails from its ' mark differing. Don't use
oldwin though; it's not always the window with the closed buf, especially
after BufLeave autocmds in do_ecmd(). Also, only set context if win is really
displaying buf.
Don't bail in do_ecmd() if buf was deleted but curwin->w_buffer is NULL; that
leaves curwin open to a NULL buffer! Use lastbuf instead, like set_curbuf().
I don't think it's possible for buf to be deleted by close_buffer() anyway, as
b_locked was set (which I can't see a way to bypass, unlike b_locked_split).
Maybe such checks can be removed, but I'd rather not risk that here.
Don't set curwin to previouswin in set_curbuf(); shouldn't be needed, otherwise
may lead to curbuf != curwin->w_buffer if autocmds switch to a window showing
buf, as that skips enter_buffer()? Was introduced back in 7.3.557 to avoid
cases where autocmds switch windows, possibly leaving previouswin with a NULL
buffer. Since 7.4.2312 and 7.4.2328, close_buffer() and buf_freeall() already
handles this. I've added an assert() as a sanity check anyway.
In free_all_mem(), set b_nwindows to 0 before close_buffer() so buffers can be
wiped if still in a window before win_free_all(). Needed as close_buffer() now
skips unloading buffers that aren't hidden if win is NULL. If it's possible for
free_all_mem()'s :tabonly! and :only! to not close all windows before freeing,
then this issue was also previously possible if b_nwindows > 1.
related: #19728
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: When 'showtabpanel' is set before any window exists (e.g. via
--cmd) and multiple tab pages are opened with -p, the tabpanel
appears when the second tab page is created. At that point
shell_new_columns() only updates the current (new) tab page's
frame width; existing tab pages retain the wrong width.
Solution: After calling shell_new_columns() in win_new_tabpage(), iterate
all other tab pages and update their frame widths with
frame_new_width() (Hirohito Higashi).
related: #19730
closes: #19734
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: When 'laststatus' changes, the status line can become
misaligned.
Solution: Update last_status_rec() to calculate the maximum status line
height required across all windows in a vertical row.
closes: #19688
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: possible crash with winminheight=0
(Emilien Breton)
Solution: Use <= instead of < when checking reserved room in
frame_setheight() to correctly handle the zero-height
boundary case (Hirohito Higashi).
In frame_setheight(), when shrinking the current window and the only
other window has 'winfixheight' with 'winminheight'=0, room_reserved
was not cleared because the condition used '<' instead of '<='.
The freed rows were discarded, leaving fr_height sum less than
topframe fr_height. Subsequent resize operations then computed a
wrong room_cmdline that expanded topframe beyond the screen, causing
a crash.
fixes: #19706closes: #19712
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Compile error when FEAT_DIFF is not defined (after v9.2.0144)
Solution: Add ifdefs around those lines (John Marriott).
related: #19622
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: 'statuslineopt' is a global only option and configuring the
line height is limited.
Solution: Make 'statuslineopt' global-local to a window and allow to
configure a fixed-height height statusline per window
(Hirohito Higashi).
closes: #19622
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: When initializing a window in win_init(), w_hl is reset to
NULL without ensuring existing highlight overrides are
cleared (after v9.2.0113)
Solution: Clear highlight overrides and reset w_hl in win_init(). Remove
the redundant VIM_CLEAR() from win_init_empty() (Foxe Chen).
closes: #19609
Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: When a popup info window is reused, win_init_empty() resets
w_hl to NULL without freeing the previously allocated value,
causing a memory leak (after v9.2.0113)
Solution: Free w_hl before resetting it to NULL in win_init_empty()
using the VIM_CLEAR() macro.
closes: #19607
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: winhighlight pointer may be used uninitialized causing a crash
Solution: Initialize pointer in win_init() and win_init_empty()
(Foxe Chen).
closes: #19601
Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Coverity: error handling issues in win_init() (after
v9.2.0093)
Solution: Only call pop_highlight_overrides() when
push_highlight_overrides() was successful.
CID: 1683100
related: #19561
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Not possible to have window-local highlighting groups
(Hima)
Solution: Port Neovims 'winhighlight' option to Vim (Foxe Chen).
fixes: #3576closes: #19493
Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Cannot have a mutli-line statusline.
Solution: Add support for multi-line statusline
(Hirohito Higashi).
closes: #19123
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
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: #19211
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: heap-use-after-free when wiping buffer in TabClosedPre.
Solution: Check window_layout_locked() when closing window(s) in another
tabpage (zeertzjq).
closes: #19196
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Crash when using :tabonly in BufUnload.
Solution: Set curbuf when setting curwin->w_buffer. Don't wipe out a
buffer if there are no other buffers. Don't decrement
b_nwindows if it was 0 before buf_freeall() (zeertzjq).
fixes: #19088#issuecomment-3710172769
closes: #19186
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Use-after-free in winframe_remove() (henices)
Solution: Set window_layout_locked() inside winframe_remove()
and check that writing diff files is disallowed when the
window layout is locked.
It can happen with a custom diff expression when removing a window:
1. Buffer was removed, so win_frame_remove() is called to remove the
window.
2. win_frame_remove() → frame_new_height() → scroll_to_fraction()
→ diff_check_fill() (checks for filler lines)
3. diff_check_fill() ends up causing a diff_try_update, and because we
are not using internal diff, it has to first write the file to a
buffer using buf_write()
4. buf_write() is called for a buffer that is not contained within a
window, so it first calls aucmd_prepbuf() to create a new temporary
window before writing the buffer and then later calls
aucmd_restbuf(), which restores the previous window layout, calling
winframe_remove() again, which will free the window/frame structure,
eventually freeing stuff that will still be accessed at step 2.
closes: #19064
Signed-off-by: Christian Brabandt <cb@256bit.org>
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: #18961
Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: WinEnter autocommand may confuse Vim when closing tabpage
(hokorobi)
Solution: Verify that curwin did not change in close_others()
fixes: #18722closes: #18733
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tabpanel: inconsistent use of cmdline and message area with
tabpanel
Solution: Reduce the cmdline and message area by the horizontal size of
the tabpanel (Hirohito Higashi)
closes: #18678
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Generating prototype files does not work on all platforms
Solution: Rework prototypes generation using python instead of cproto,
enable it in CI to test it for each PR (Hirohito Higashi).
closes: #18045
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Window may have wrong height if resized from another tabpage.
Solution: Improve check for whether a tabline has been added (zeertzjq).
fixes: #18518closes: #18519
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: 'cursorlineopt' "screenline" isn't redrawn when moving cursor
and then using line("w0") and :retab that does nothing.
Solution: Call redraw_for_cursorcolumn() when setting a valid w_virtcol
(zeertzjq).
closes: #18506
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: vertical separator of 'winfixwidth' windows may remain if they
become right-most windows from closing windows to the right.
Solution: Don't implicitly rely on frame_new_width to fix vseps, as the
call may be skipped for 'winfixwidth' windows to preserve
their width; do it explicitly in winframe_remove (Sean Dewar).
Note that I prefer win_new_width here over setting w_width directly, which
would've previously been done by win_split_ins after frame_add_vsep, as this
wasn't true for winframe_remove.
Though the equivalent issue of bottom 'winfixheight' windows leaving stray
statuslines with &ls=0 doesn't seem to exist, test it anyway.
closes: #18481
Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Crash in BufLeave/WinLeave/TabLeave when closing window after
BufUnload closes all other windows in the tab page.
Solution: Avoid duplicate BufLeave/WinLeave events. Trigger TabLeave
before removing the buffer (zeertzjq).
related: #14166
related: neovim/neovim#33603closes: #18330
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Issues with proto files: missing or inconsistent prototypes.
Solution: Update ifdefs, move typedefs, fix prototype declaration
(Hirohito Higashi)
This change focuses on fixes and tweaks found while working on #18045 for
the proto/*.pro files.
The following fixes and tweaks have been made:
- Fixed a prototype declaration where the variable name differed from
the function definition.
- Removed a prototype declaration without a function body.
- Fixed a problem where a prototype declaration was not created for a
function definition enclosed in a #if directive because it lacked ||
defined(PROTO).
- Moved typedef struct soundcb_S soundcb_T; from proto/sound.pro to
vim.h.
- Other small tweaks.
The make proto mechanism remains unchanged.
closes: #18058
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Autocompletion slow with include- and tag-completion
Solution: Refactor ins_compl_interrupted() to also check for timeout,
further refactor code to skip outputting message when
performing autocompletion (Girish Palya).
Running `vim *` in `vim/src` was slower than expected when
'autocomplete' was enabled. Include-file and tag-file completion
sources were not subject to the timeout check, causing unnecessary
delays.
So apply the timeout check to these sources as well, improving
autocompletion responsiveness, refactor find_pattern_in_path() to take
an additional "silent" argument, to suppress any messages.
closes: #17966
Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: missing change from patch v9.1.1461
Solution: change wrong TPL_LCOL macro in a few more places
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tabpanel: tabpanel vanishes with popup menu
Solution: remove pum-related test in tabpanel_leftcol(), refactor a few
related functions (Hirohito Higashi)
This commit does the following:
- Delete unnecessary pum-related checks in the tabpanel_leftcol()
function
- remove pum-related check in tabpanel_leftcol()
- The argument of the TPL_LCOL() macro has been deleted.
- The argument of the tabpanel_leftcol() function has been changed
to void
- The return type of the `win_comp_pos()` function has been changed to
void
closes: #17549
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: GUI control code is displayed on the console on startup
Solution: check if Vim is starting up (Hirohito Higashi)
closes: #17456
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tabpanel may flicker in the GUI
Solution: call scroll_start() and scroll_region_reset()
(Hirohito Higashi)
fixes: #17440closes: #17442
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tabpanel: there are still some problems with the tabpanel with
column handling
Solution: fix the problems and refactor Tabpanel feature (Hirohito
Higashi).
fixes: #17423fixes: #17332closes: #17336
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: tabpanel not correctly redrawn on tabonly
(Maxim Kim, after v9.1.1391)
Solution: force redraw of the tabpanel, tweak style
(Hirohito Higashi)
fixes: #17322closes: #17330
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Vim does not have a tabpanel
Solution: include the tabpanel feature
(Naruhiko Nishino, thinca)
closes: #17263
Co-authored-by: thinca <thinca@gmail.com>
Signed-off-by: Naruhiko Nishino <naru123456789@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: b:undo_ftplugin not executed when re-using buffer
(archy3)
Solution: explicitly execute b:undo_ftplugin in buflist_new() when
re-using the current buffer
fixes: #17113closes: #17133
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: With ':set splitkeep=screen', cursor did't restore column
correctly when splitting a window on a line longer than the
last line on the screen (after v9.1.0707)
Solution: Restore cursor column in `win_fix_scroll()` since it may be
changed in `getvcol()` after 396fd1ec29 (phanium).
Example:
```
echo longlonglongling\nshort | vim - -u NONE --cmd 'set
splitkeep=screen' +'norm $' +new +q
```
fixes: #16968closes: #16971
Signed-off-by: phanium <91544758+phanen@users.noreply.github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: Coverity warns about NULL pointer when triggering WinResized
Solution: Add OOM checks for windows_list like for scroll_dict. Remove
void casts that are unnecessary after 9.1.1084 (zeertzjq).
closes: #16959
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
Problem: TabClosedPre is triggered just before the tab is being freed,
which limited its functionality.
Solution: Trigger it a bit earlier and also on :tabclose and :tabonly
(Jim Zhou)
closes: #16890
Signed-off-by: Jim Zhou <jimzhouzzy@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>