neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 31c814a0ed0eca1822ecb0409b06bab24d1c4792
parent 4daa8eb5abcad2e3cf4501f0e4fcaae90ec85b72
Author: glepnir <glephunter@gmail.com>
Date:   Fri, 28 Nov 2025 02:23:46 +0800

fix(float): respect statusline=3, don't inherit local 'statusline' #36716

Problem: When creating floating window from existing window, the
window-local 'statusline' option is inherited, causing unwanted
statusline display. Additionally, with laststatus=3 (global statusline),
the early return skipped clearing wp->w_redr_status flag.

Solution: Clear inherited window-local 'statusline' in win_new_float
for style="minimal". Restructure win_redr_status to always clear the
flag before any early returns, and only render floating window statusline
when window-local 'statusline' is explicitly set. And respect 'laststatus'
option.
Diffstat:
Msrc/nvim/option.c | 1+
Msrc/nvim/statusline.c | 15+++++----------
Msrc/nvim/winfloat.c | 14+++++++++-----
Mtest/functional/ui/statusline_spec.lua | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 86 insertions(+), 16 deletions(-)

diff --git a/src/nvim/option.c b/src/nvim/option.c @@ -2117,6 +2117,7 @@ static const char *did_set_laststatus(optset_T *args) status_redraw_curbuf(); last_status(false); // (re)set last window status line. + win_float_update_statusline(); return NULL; } diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c @@ -76,14 +76,8 @@ void win_redr_status(win_T *wp) || (wild_menu_showing != 0 && !ui_has(kUIWildmenu))) { return; } - wp->w_redr_status = false; - - if (wp->w_floating && is_stl_global) { - return; - } - busy = true; - + wp->w_redr_status = false; if (wp->w_status_height == 0 && !(is_stl_global && wp == curwin)) { // no status line, either global statusline is enabled or the window is a last window redraw_cmdline = true; @@ -91,7 +85,8 @@ void win_redr_status(win_T *wp) // Don't redraw right now, do it later. Don't update status line when // popup menu is visible and may be drawn over it wp->w_redr_status = true; - } else if (*p_stl != NUL || *wp->w_p_stl != NUL) { + } else if (*wp->w_p_stl != NUL + || (*p_stl != NUL && (!wp->w_floating || (is_stl_global && wp == curwin)))) { // redraw custom status line redraw_custom_statusline(wp); } @@ -234,7 +229,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler, bool u StlClickRecord *tabtab; bool is_stl_global = global_stl_height() > 0; - ScreenGrid *grid = wp && wp->w_floating ? &wp->w_grid_alloc : &default_grid; + ScreenGrid *grid = wp && wp->w_floating && !is_stl_global ? &wp->w_grid_alloc : &default_grid; // There is a tiny chance that this gets called recursively: When // redrawing a status line triggers redrawing the ruler or tabline. @@ -275,7 +270,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler, bool u &wp->w_winbar_click_defs_size); } else { const bool in_status_line = wp->w_status_height != 0 || is_stl_global; - if (wp->w_floating && !draw_ruler) { + if (wp->w_floating && !is_stl_global && !draw_ruler) { row = wp->w_winrow_off + wp->w_view_height; col = wp->w_wincol_off; maxwidth = wp->w_view_width; diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c @@ -70,6 +70,10 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) } wp->w_p_wbr = empty_string_option; } + if (wp->w_p_stl && wp->w_p_stl != empty_string_option) { + free_string_option(wp->w_p_stl); + wp->w_p_stl = empty_string_option; + } } else { assert(!last); assert(!wp->w_floating); @@ -104,7 +108,7 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) win_append(lastwin_nofloating(), wp, NULL); } wp->w_floating = true; - wp->w_status_height = *wp->w_p_stl != NUL ? STATUS_HEIGHT : 0; + wp->w_status_height = *wp->w_p_stl != NUL && (p_ls == 1 || p_ls == 2) ? STATUS_HEIGHT : 0; wp->w_winbar_height = 0; wp->w_hsep_height = 0; wp->w_vsep_width = 0; @@ -164,13 +168,13 @@ void win_set_minimal_style(win_T *wp) // statuscolumn: cleared if (wp->w_p_stc != NULL && *wp->w_p_stc != NUL) { free_string_option(wp->w_p_stc); - wp->w_p_stc = xstrdup(""); + wp->w_p_stc = empty_string_option; } // statusline: cleared (for floating windows) if (wp->w_floating && wp->w_p_stl != NULL && *wp->w_p_stl != NUL) { free_string_option(wp->w_p_stl); - wp->w_p_stl = xstrdup(""); + wp->w_p_stl = empty_string_option; if (wp->w_status_height > 0) { win_config_float(wp, wp->w_config); } @@ -190,7 +194,7 @@ int win_border_width(win_T *wp) void win_config_float(win_T *wp, WinConfig fconfig) { // Process statusline changes before applying new height from config - bool show_stl = *wp->w_p_stl != NUL; + bool show_stl = *wp->w_p_stl != NUL && (p_ls == 1 || p_ls == 2); if (wp->w_status_height && !show_stl) { win_remove_status_line(wp, false); } else if (wp->w_status_height == 0 && show_stl) { @@ -329,7 +333,7 @@ void win_float_update_statusline(void) { for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) { bool has_status = wp->w_status_height > 0; - bool should_show = *wp->w_p_stl != NUL; + bool should_show = *wp->w_p_stl != NUL && (p_ls == 1 || p_ls == 2); if (should_show != has_status) { win_config_float(wp, wp->w_config); } diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua @@ -909,7 +909,7 @@ describe("'statusline' in floatwin", function() }) end) - it('controlled by ":setlocal statusline" and "style"', function() + it('controlled by ":setlocal statusline" and "style" and "laststatus"', function() local buf = api.nvim_create_buf(false, false) api.nvim_buf_set_lines(buf, 0, -1, false, { '1', '2', '3', '4' }) local cfg = { @@ -996,5 +996,75 @@ describe("'statusline' in floatwin", function() {3:[No Name] }| | ]]) + -- clear statusline when laststatus is 3 + command('tabclose | set laststatus=2') + screen:expect([[ + | + {1:~}┌──────────┐{1: }| + {1:~}│{4:^1 }│{1: }| + {1:~}│{4:2 }│{1: }| + {1:~}│{4:3 }│{1: }| + {1:~}│{4:4 }│{1: }| + {1:~}│{3:<Name] [+]}│{1: }| + {1:~}└──────────┘{1: }| + {1:~ }|*10 + {2:[No Name] }| + | + ]]) + command('set laststatus=0') + screen:expect([[ + | + {1:~}┌──────────┐{1: }| + {1:~}│{4:^1 }│{1: }| + {1:~}│{4:2 }│{1: }| + {1:~}│{4:3 }│{1: }| + {1:~}│{4:4 }│{1: }| + {1:~}└──────────┘{1: }| + {1:~ }|*12 + | + ]]) + + command('set laststatus=3') + screen:expect([[ + | + {1:~}┌──────────┐{1: }| + {1:~}│{4:^1 }│{1: }| + {1:~}│{4:2 }│{1: }| + {1:~}│{4:3 }│{1: }| + {1:~}│{4:4 }│{1: }| + {1:~}└──────────┘{1: }| + {1:~ }|*11 + {3:[No Name] [+] }| + | + ]]) + api.nvim_buf_set_name(buf, 'stl_test') + screen:expect([[ + | + {1:~}┌──────────┐{1: }| + {1:~}│{4:^1 }│{1: }| + {1:~}│{4:2 }│{1: }| + {1:~}│{4:3 }│{1: }| + {1:~}│{4:4 }│{1: }| + {1:~}└──────────┘{1: }| + {1:~ }|*11 + {3:stl_test [+] }| + | + ]]) + end) + + it("clears inherited window-local 'statusline' on creation", function() + command('set laststatus=2') + api.nvim_set_option_value('statusline', 'global', {}) + local curwin = api.nvim_get_current_win() + api.nvim_set_option_value('statusline', 'split-local', { win = curwin }) + api.nvim_open_win(0, true, { relative = 'editor', row = 1, col = 1, height = 2, width = 4 }) + screen:expect([[ + | + {1:~}{4:^ }{1: }| + {1:~}{11:~ }{1: }| + {1:~ }|*15 + {2:split-local }| + | + ]]) end) end)