aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ui/statusline_spec.lua
Commit message (Collapse)AuthorAge
* Merge #41944 from epithet/stl-hl-scopesJustin M. Keyes2026-09-30
|\
| * feat(statusline): highlight scopesSébastien Hoffmann2026-09-26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem 1: many status line sections are automatically hidden when they currently aren't relevant. When such a section contains highlights, the exact pre-section highlighting needs to be reset at the end, otherwise the highlighting of unrelated sections to the right depend on whether the section is hidden or not. And in case of auto-hiding item groups, it might even refuse to hide. Problem 2: when only a part in the middle of a section should deviate from the surrounding highlighting, the section needs knowledge of the highlighting outside in order to reset it, which makes it hard to create self-contained, reusable modules. Problem 3: with nested sections of progressively stacked highlighting changes, the last %$-modifications effectively have to be subtracted when ending a subsection. This can only be done by replaying all the pre-subsection changes from the last %#. Solution: Introduce highlight scopes %#(...%#) that automatically reset pre-scope highlighting at the end. ref #26037 ref #29976 ref #29980 ref #35806 ref #36685
* | vim-patch:9.2.1114: Visual selection is not highlighted at the cursor ↵Takumi Katase2026-09-27
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | position #42105 vim-patch:9.2.1114: Visual selection is not highlighted at the cursor position Problem: In a terminal the character under the cursor is normally not shown as part of the visual selection. Solution: Don't set "noinvcur" in win_line() (Shane Harper). The problem did not occur in the GUI, only in a terminal. The name "noinvcur" ("don't invert the cursor") was misleading: the variable did not affect the cursor, but whether the character under the cursor could be displayed as part of the visual selection. The "noinvcur" handling may have been meant to help during a visual selection when Visual is shown in reverse video and the terminal draws the cursor by inverting the character under it, as otherwise the character under the cursor would not look highlighted like the rest of the selection. But Vim cannot know in general how a terminal draws the cursor, and when either the cursor is not drawn by inverting the character under it or Visual is not shown in reverse video, the handling just left a character of the visual selection unhighlighted. closes: vim/vim#21317 https://github.com/vim/vim/commit/d10aab4ba6602f8f2f2576d2d62ceb63869db6fb Co-authored-by: Shane Harper <shane@shaneharper.net> AI-assisted
* fix(statusline): default 'statusline' improvements #41597Sébastien Hoffmann2026-09-03
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: there should be exactly one cell of padding between sections, and exactly one cell of minimum padding between the left and the right. - Spaces between sections waste space when a section is empty. According to a comment in #33036, this was the reason to avoid `%k` and implement the keymap section with a vim expression, but other sections still have this problem. - The diagnostics section wastes space because it is not entirely empty when there are diagnostics in another buffer. - The terminal exit code section can touch the right side, e.g. the ruler, even though it belongs to the left side. Solution: - Use auto-hiding item groups (`%(` without width fields) to get rid of unneeded spaces when a section shows no information. This simplifies the 'showcmd' and 'keymap' sections in particular. - As a slight simplification, `term_exitcode` is moved into the flags section since it is formatted with square brackets like a flag. - Count the diagnostics for the current buffer specifically. - Ensure at least one cell of padding between the left and the right side by adding a space next to the separator `%=`. Problem: some sections are implemented with `%{%`, even though reevaluation of the expression result is not needed. This leads to otherwise needless %-escaping in `progress_status`. Solution: use `%{` instead. Problem: `%{` and `%{%` (without items) replace spaces with fillchars. This looks out-of-place inside the terminal exit code section, and in contrast to all other sections, the 'busy' section is surrounded by fillchars, which looks inconsistent, and with some terminal-font combinations, ◐ overlaps the fillchar, e.g. Alacritty & JetBrains Mono. Solution: use non-breaking spaces U+202F to avoid fillchar substitution. Problem: sections that appear/disappear frequently can make otherwise more stable sections jump around a lot. Solution: sort the sections on the right roughly by volatility: 'showcmd' in first place, 'keymap' next to the ruler.
* fix(window): 'laststatus' change pushes win past last row #41189Barrett Ruth2026-08-06
| | | | | | | | | | | | | Problem: Giving a window a status line when `'laststatus'` starts requiring one takes the row from a resizable frame found by walking up the frame tree, but only the window's own leaf frame is grown back. Every frame between the leaf and the donor keeps its old height, so a later resize hands out a row that does not exist and a window's status line ends up on the command line. Solution: Grow the window's frame with `frame_setheight()`, which takes the row from a neighbouring frame and keeps every enclosing frame consistent.
* refactor(ruler)!: replace C implementation with 'rulerformat' expressionSébastien Hoffmann2026-08-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: The default 'ruler' is implemented in C instead of the 'statusline' DSL. Solution: Replace the C implementation with a default 'rulerformat' expression. This is a continuation of #1248 and #33036. Advantages: - configuration is more discoverable, the default being a useful example - users and plugins can augment the default - code reuse and less C code to maintain - ui2: due to the use of an item group with `minwid`, it can expand instead of truncating when the content gets too long, which is particularly useful for locales with long translations of Top/Bot/All Implementation details: As is the case for 'statusline', when trying to set 'rulerformat' to an empty string, the default expression is restored instead, mimicking how previously the default C implementation would have been activated. Just like before, `:set rulerformat=` and `:set rulerformat&` have the same effect, and the ruler is disabled with `:set noruler`. The default expression uses an item group with `%=`, unlike the fallback in the previous default statusline `%-14.(%l,%c%V%) %P`, because the total width and how it is configured is immediately clear without documentation, it is a more useful pattern in general that works when both sides have flexible width, and it also works for vim, which is useful for configuration sharing/reuse. A truncation marker `%<` is added at the end to mimic how at small screen widths, the scroll percentage would disappear first, so that the cursor position can remain fully visible. BREAKING CHANGES: - `&rulerformat` can no longer be set to an empty string - ui2: the default ruler is no longer of fixed width, but can expand - at very small screen widths (< 36 columns) - ui2: it will no longer try to shrink white-space before truncating - it truncates gradually from the right, whereas previously, the scroll percentage would disappear all at once - l10n can no longer add a space after the comma between line and column (this was only done for one language: Ukrainian)
* fix(ruler)!: consistent width in last line and statuslineSébastien Hoffmann2026-08-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Traditionally, the ruler in the last line is one cell shorter than in the statusline, leaving the last cell of the screen blank. According to code comments, this is in order to prevent unwanted scrolling on "some" (unspecified, but presumably ancient) terminals. Berkeley vi is more specific in its `vs_modeline` function: dumb terminals with hardware scroll, SunOS 4.1.1 and Ultrix 4.2 curses. (n)curses still has a similar limitation in `(w)addstr`, but apparently only for historical reasons. Maintaining the different widths leads to awkward inconsistencies when the ruler is configured with 'rulerformat', except for the special case where it contains a top-level `%=`. Shifting the ruler in the last line to the left would be a solution, but the empty cell at the end doesn't seem to be relevant anymore. Solution: extend the ruler in the last line all the way to the right edge of the screen, just like in the statusline. The exact same amount of place will be available to the rest of the UI as before. BREAKING CHANGE: - the default ruler width is now 18 cells - the last cell of the screen is no longer empty Closes #41076
* fix(ruler): no window-local highlights for last line 'rulerformat'Sébastien Hoffmann2026-08-04
| | | | | | | | | | | Fixes #38777 in case 'rulerformat' is set. See PR 38879. Original message: Problem: When the 'ruler' is in the last line of the screen, it takes local highlight definitions of the current window, tripping an assert (since c1648cf). Solution: Don't use window-local highlight definitions when the ruler is not part of a statusline.
* vim-patch:9.2.0855: 'showcmd' not redrawn with empty mapping triggered on ↵zeertzjq2026-07-26
| | | | | | | | | | | | | timeout Problem: 'showcmd' not redrawn with empty mapping triggered on timeout. Solution: Don't postpone redraw when inside vgetorpeek(). Also move test for tabline 'showcmd' to test_tabline.vim. fixes: vim/vim#20839 closes: vim/vim#20840 https://github.com/vim/vim/commit/2e9687647a2ab2aadee00f01e37c71a5cffbdfcc
* fix(ui): invalid ruler items in other windows #40891Ondrej Balaz2026-07-22
| | | | | | | | | | | | | Problem: When buffer is open in multiple windows and its line count changes, any 'statusline' or 'rulerformat' items depending on it (e.g. %P) will become invalid in non-current windows because w_redr_status is only set on first change. Solution: Set w_redr_status on all windows with the buffer when the line count changes. Signed-off-by: Ondrej Balaz <blami@blami.net>
* test(harness): migrate away from magic globalsJustin M. Keyes2026-07-21
| | | | | | | | | | | | | | | | | | | | | Problem: The magic globals `it`, `describe`, etc., are more trouble than they are worth. - Hooking into `after_each` requires `getfenv()` hacks. - They confuse luals/emmylua, because the top-level `.luarc.json` isn't merged with `test/.luarc.json` (apparently a luals limitation?) - They totally defeat discoverability because the user just has to "know" about the various magic symbols. So they harm DX, which means they serve no purpose at all. Solution: - Expose the test API from `testutil`, so tests can call `t.it()`, `t.describe()`, etc., in the conventional way. - Drop `getfenv()` hacks. - Drop the `setfenv()` injection in `load_chunk`. - Drop `test/_meta.lua`.
* fix(ui): combine float border with window background #40796Artem Krinitsyn2026-07-19
| | | | | | | | | | Problem: Float border highlight groups (FloatBorder, FloatTitle and FloatFooter) fall back to Normal background highlight if no background color set. Solution: Combine border colors with window-local Normal highlight. Fix #38330
* fix(showcmd): avoid stale %S contents #40747Barrett Ruth2026-07-15
| | | Co-authored-by: zeertzjq <zeertzjq@outlook.com>
* feat(statusline)!: allow %= in item groups, scope %< to item groups #40369Sébastien Hoffmann2026-06-27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Separation markers (%=) are ignored within item groups. This lead to a regression when the C implementation of the statusline was replaced with a default expression. When the user configured a custom ruler expression with a %= and used the overloaded item group syntax to set the ruler width, the separation marker worked in the ruler, but not when the ruler was incorporated into the statusline where the item group syntax was interpreted in the usual way. Solution: Analogously to top-level behaviour, expand separation markers evenly within item groups until `minwid` is reached (if set). ref https://github.com/neovim/neovim/pull/33036 fix https://github.com/neovim/neovim/issues/39984 ref https://github.com/neovim/neovim/issues/40247 Problem: The recursion offset into the static `stl_items` was not taken into account when adjusting the item count after truncation. Steps to reproduce: first prepare `stl_items`: set stl=%{%repeat('%#Error#',10)%} then watch how the Error highlight leaks into the recursive call: set stl=%l%l%l%{%nvim_eval_statusline('test%l%<',{'maxwidth':3,'highlights':1}).highlights%} ref https://github.com/neovim/neovim/issues/32259 * fix(statusline): consistent truncation at multicell character Problem 1: truncation of item groups at multicell character didn't take into account that minwid can be specified as a negative number. Problem 2: after truncation at top-level from the right at multicell character, the returned width was always `maxwidth`, even though the actual width was reduced. In vim, this can be observed as a statusline that is not fully drawn until the edge of the screen: vim --clean +"set ls=2 stl=%{%repeat('x',&columns-2)%}🙂x%<" Problem 3: after truncation at top-level from the left at multicell character, the resulting gap to reach `maxwidth` again was filled with fillchars, but then the final NUL was not set correctly. This can be seen in the following example, where the statuscolumn spills into the editing area starting from line 10: nvim --clean +"set number stc=%<x🙂%{repeat('x',43)}%l" +"norm yy10p" Solution: fix the small errors and, at top-level, consistently reduce the size instead of compensating with fillchars. In the case of the statusline and the winbar, the remaining place is filled with the configured fillchars in `win_redr_custom`, after `build_stl_str_hl` has returned. In all other cases (title, icon, statuscol, tabline, ruler), there seems to be no point in adding additional spaces at the end. * feat(statusline)!: scope %< to item groups Problem: Previously, item groups were only truncated at the beginning, which is often not desired. In the example %.15(path: %f%) the group's title/label is truncated away: <th/to/file.txt Truncation markers (%<) in item groups were processed at the top-level in the end, which can be confusing. Only the first %< is used for the whole string, and it is used even if the containing item group is hidden. Additionally, in the case of hidden item groups, the marker's position was not adapted. For example, %(hidden%<%)%f had the effect of truncating the path somewhere in the middle: /path/<file.txt Solution: Make truncation consistent with top-level behaviour, which has a better default of truncating at the first `Normal` item, i.e. path: <file.txt and allows for fine-grained control with truncation markers (%<). E.g. %.15(path: %f%<%) now yields path: /path/to> The original behaviour can be restored like so: %.15(%<path: %f%) BREAKING CHANGE: %< is no longer processed at top-level - the default truncation behaviour has changed: now at first item - truncation markers inside item groups don't affect truncation outside of the item group anymore - several truncation markers can now have an effect when separated with item groups, whereas previously only the first one globally had ref https://github.com/neovim/neovim/issues/39984
* fix(autocmd): never draw aucmd_prepbuf temp win #40379luukvbaal2026-06-23
| | | | | | | | | | | | Problem: An autocommand that redraws may do so while curwin is temporarily set for the autocommand scope. This can result in flickering or unexpected state with UI components (statusline, winbar, decor providers...) that depend on the current window. Current workaround for statusline and winbar specifically delays the redraw, which can itself be unexpected for the autocommand. Solution: If redrawing happens with a temporary autocmd current window, temporarily restore the current window while redrawing.
* fix(statusline): defer redraw in aucmd context #40309Barrett Ruth2026-06-23
| | | | | | | | Problem: `nvim_exec_autocmds({buf=...})` may temporarily switch curwin/curbuf through `aucmd_prepbuf()`. Requested statuslines/winbars before `aucmd_restbuf()` may erroneously see the target window as current. Solution: Track `aucmd_prepbuf()` window-switch depth and leave statusline/winbar redraws marked dirty until the original window is restored.
* fix(autocmd): redraw statusline after nvim_exec_autocmds() #40172Barrett Ruth2026-06-10
| | | | | | | | | | | | | Problem: Since 5181984d, `nvim_exec_autocmds({buf=…})` temporarily sets the `buf`-window as current-window, and its statusline renders as a "current-window statusline", regardless of the user's actual current-window. Solution: Mark the statusline for redraw in `aucmd_restbuf()`, so it is redrawn correctly after the event. Co-authored-by: Luuk van Baal <luukvbaal@gmail.com>
* fix(statusline): no cmdline ruler for autocommand windowLuuk van Baal2026-05-22
| | | | | | Problem: Cmdline ruler may be drawn for autocommand window. Solution: Check that the current window is not an autocommand window when deciding whether to draw the ruler.
* fix(statusline): no window-local highlights for last line 'ruler' #38879luukvbaal2026-04-08
| | | | | | | | | Problem: When the 'ruler' is in the last line of the screen, it takes local highlight definitions of the current window, tripping an assert (since c1648cf8). Solution: Don't use window-local highlight definitions when the ruler is not part of a statusline. Co-authored-by: glepnir <glephunter@gmail.com>
* fix(window): clear cmdline 'ruler' when window is closed #38631luukvbaal2026-03-31
| | | | | | Problem: When 'ruler' is in last line of the screen and the current floating window is closed, the ruler is not cleared. Solution: When closing the current floating window, redraw the cmdline if that contained, and will no longer contain the 'ruler'.
* fix(progress): require "source" for progress-message #38514Shadman2026-03-28
| | | | | | | | | | | Problem: - Progress-events are filtered by "source". But "source" is not required by nvim_echo. - Without "++nested" (force=false), nvim_echo in an event-handler does not trigger Progress events. - vim.health does not declare a "source". Solution: - Make source mandatory for progress-messages - Enable ++nested (force=true) by default when firing Progress event. - Set "source" in vim.health module.
* refactor(progress): simplify progress-status format #38491Shadman2026-03-26
| | | | | | | | | | | | Problem: Currently we are using if 1 item then {title}: {percent}% else Progress: {AVG}%({N}) dropping {title} and Progress text saves up space in statusline plus makes the format consistent, less jumping around. Solution: Use `{AVG}%({N})` for all cases.
* fix(progress): show progress-status only in curwin #38458Shadman2026-03-24
| | | | | | | | | | | | | | | | Problem: Currently same progress stat get's displayed on statusline of all windows. This is repeatitive and noisy. Solultion: Only display progress-status on the focused window Problem: Currently, when multiple progress are on going we show it as Progress: {N} items {percent}% format. It can be simplified sinnce items doesn't really add enough value for the valuable space it takes in statusline Solution: Change format to Progress: {percent}%({N})
* feat(progress): status api, 'statusline' integration #35428Shadman2026-03-20
| | | | | | | | | | | | | | Problem: Default statusline doesn't show progress status. Solution: - Provide `vim.ui.progress_status()`. - Include it in the default 'statusline'. How it works: Status text summarizes "running" progress messages. - If none: returns empty string - If one running item: "title: percent%" - If multiple running items: "Progress: N items avg-percent%"
* fix(statusline): missing info/hint diagnostics #38307phanium2026-03-15
| | | | | Problem: default stl treat vim.diagnostics.count() return as array Solution: next() tell if a dict is empty
* feat(terminal): surface exit code via virttext + nvim_get_chan_info #37987Ayaan2026-03-10
| | | | | | | | | | Problem: When a terminal process exits, "[Process Exited]" text is added to the buffer contents. Solution: - Return `exitcode` field from `nvim_get_chan_info`. - Show it in the default 'statusline'. - Show exitcode as virtual text in the terminal buffer.
* fix(statusline): broken statusline on error #38000Sean Dewar2026-02-23
| | | | | | | | | | Problem: after #33036, an error from evaluating 'statusline' clears it and doesn't draw the statusline. (causing glitchy redraws) Solution: use the default value instead. If 'stl' is somehow ever empty, still call redraw_custom_statusline to at least draw an empty statusline. Ideally our default 'stl' shouldn't itself error too! :-) Also adjust some prior screen:expect()s to avoid immediate success warnings.
* feat(statusline): option to specify stacking highlight groups #37153Riley Bruins2026-02-15
| | | | | | | | **Problem:** No easy way to stack highlight groups #35806. **Solution:** Add a way to specify a new statusline chunk with a highlight group that inherits from previous highlight attributes. Also applies to tabline, etc.
* fix(ui): repaint separator connectors after all window updates #37852Riccardo Mazzarini2026-02-13
| | | | | | | | | | | | | | | | | Problem: When a window is redrawn, `draw_vsep_win`/`draw_hsep_win` paint plain separator characters (`│`/`─`) along the window's entire edges, including cells that are connector corners belonging to other windows. Then `draw_sep_connectors_win` only fixes the corners of that same window, not connectors in the middle of its edges that belong to adjacent windows. If the window that "owns" the connector corner isn't part of the redraw, the connector is never repainted. Solution: Move connector drawing out of the per-window `win_update` and into a separate pass in `update_screen` that runs after all windows have been updated.
* fix(statusline): diagnostics spacing #36897Olivia Kinnear2025-12-20
|
* fix(float): respect statusline=3, don't inherit local 'statusline' #36716glepnir2025-11-27
| | | | | | | | | | | | 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.
* feat(float): 'statusline' in floating windows #36521glepnir2025-11-26
| | | | | | | Problem: Can't show 'statusline' in floating windows. Solution: Use window-local 'statusline' to control floating window statusline visibility.
* feat(diagnostic): highlights in diagnostic.status() #36685Riley Bruins2025-11-25
| | | | Applies the appropriate `DiagnosticSign*` highlight to each group, resetting the highlights at the end of the expression.
* fix(statusline): scope truncation bookkeepingLewis Russell2025-11-20
| | | | | | | | | | | | Limit the default truncation item to the current recursion range so nested `nvim_eval_statusline()` calls don't reuse stale `stl_items` pointers. Add a functional regression that evaluates a Lua statusline helper which forces truncation to ensure the nested scenario stays stable. AI-Assist: OpenAI ChatGPT Fixes #36616
* fix(statusline): redraw if Visual selection other end changes (#36281)zeertzjq2025-10-23
|
* fix(window): don't add a hsep when out of room if global stl is offSean Dewar2025-09-03
| | | | | | | | Problem: a horizontal separator may be added to a window that doesn't need one if there is no room when moving a different window. Solution: only restore a hsep in winframe_restore when the global statusline is enabled.
* fix(statusline): don't require'vim.diagnostic' unless already usedbfredl2025-08-02
| | | | | | | | | This workarounds a bug likely in nvim__get_runtime, and fixes #35124 Though I'd argue it is more correct anyway as the point of vim.SUBMODULE lazy loading is "only pay for what you use". If no one has require'vim.diagnostic' yet in LSP or otherwise, there cannot be any diagostics available and loading the lua module is wasteful.
* feat(statusline): vim.diagnostic.status() #33723Anton Kastritskii2025-07-29
| | | | | | | | Problem: Not easy to get a status string for diagnostics. Solution: - Add vim.diagnostic.status(). - Add it to the default 'statusline'.
* feat(options): per-buffer 'busy' status #34493Shadman2025-07-06
| | | | | | | | Problem: Plugins cannot mark a buffer as "busy". Solution: - Add a buffer-local 'busy' option. - Show a busy indicator in the default 'statusline'.
* feat(options): default statusline expression #33036Shadman2025-04-21
| | | | | | | | | | Problem: Default 'statusline' is implemented in C and not representable as a statusline expression. This makes it hard for user configs/plugins to extend it. Solution: - Change the default 'statusline' slightly to a statusline expression. - Remove the C implementation.
* fix(statusline): overwriting stl_items with nvim_eval_statusline() {-item #32265luukvbaal2025-02-02
| | | | | | | | | | Problem: When an evaluation {-item calls `nvim_eval_statusline()`, that nested call may overwrite the same memory used for `stl_items`. Solution: Make `curitem` static and use it to compute an offset to avoid overwriting `stl_items` in nested calls to `build_stl_str_hl()`. Move miscellaneous statusline tests into `describe()` block.
* fix(tests): needing two calls to setup a screen is cringebfredl2024-11-14
| | |