From 259e6fa9ccb7354cb541cf77c64c0f8196cbe2ec Mon Sep 17 00:00:00 2001 From: Sébastien Hoffmann Date: Sat, 1 Aug 2026 18:01:00 +0200 Subject: fix(ruler)!: consistent width in last line and statusline 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 --- runtime/lua/vim/_meta/options.gen.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_meta/options.gen.lua b/runtime/lua/vim/_meta/options.gen.lua index 898d57edc2..25f2085916 100644 --- a/runtime/lua/vim/_meta/options.gen.lua +++ b/runtime/lua/vim/_meta/options.gen.lua @@ -5403,7 +5403,7 @@ vim.go.ru = vim.go.ruler --- The format of this option is like that of 'statusline'. --- This option cannot be set in a modeline when 'modelineexpr' is off. --- ---- The default ruler width is 17 characters. To make the ruler 15 +--- The default ruler width is 18 characters. To make the ruler 15 --- characters wide, put "%15(" at the start and "%)" at the end. --- Example: --- -- cgit From ca07e505f939e8ff6e70571ef130722bdc40b292 Mon Sep 17 00:00:00 2001 From: Sébastien Hoffmann Date: Mon, 20 Jul 2026 21:35:16 +0200 Subject: refactor(ruler)!: replace C implementation with 'rulerformat' expression 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) --- runtime/lua/vim/_meta/options.gen.lua | 95 ++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 36 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_meta/options.gen.lua b/runtime/lua/vim/_meta/options.gen.lua index 25f2085916..dd2d1a7468 100644 --- a/runtime/lua/vim/_meta/options.gen.lua +++ b/runtime/lua/vim/_meta/options.gen.lua @@ -5369,28 +5369,31 @@ vim.o.rlc = vim.o.rightleftcmd vim.wo.rightleftcmd = vim.o.rightleftcmd vim.wo.rlc = vim.wo.rightleftcmd ---- Show the line and column number of the cursor position, separated by a ---- comma. When there is room, the relative position of the displayed ---- text in the file is shown on the far right: ---- Top first line is visible ---- Bot last line is visible ---- All first and last line are visible ---- 45% relative position in the file ---- If 'rulerformat' is set, it will determine the contents of the ruler. ---- Each window has its own ruler. If a window has a status line, the ---- ruler is shown there. If a window doesn't have a status line and ---- 'cmdheight' is zero, the ruler is not shown. Otherwise it is shown in ---- the last line of the screen. If the statusline is given by ---- 'statusline' (i.e. not empty), this option takes precedence over ---- 'ruler' and 'rulerformat'. +--- When on, show some buffer information in the ruler. Each window has +--- its own ruler. The ruler of the active window is shown in the last +--- line of the screen, unless 'cmdheight' is zero, or the window has a +--- status line, which (by default) contains the window's ruler. +--- +--- 'rulerformat' determines the contents of the ruler. +--- By default, the line and column number of the current cursor position +--- are shown, separated by a comma. --- If the number of characters displayed is different from the number of --- bytes in the text (e.g., for a TAB or a multibyte character), both --- the text column (byte number) and the screen column are shown, --- separated with a dash. --- For an empty line "0-1" is shown. --- For an empty buffer the line number will also be zero: "0,0-1". +--- Finally, the relative position of the displayed text in the file is +--- shown on the far right: +--- Top first line is visible +--- Bot last line is visible +--- All first and last line are visible +--- 45% relative position in the file +--- --- If you don't want to see the ruler all the time but want to know where --- you are, use "g CTRL-G" `g_CTRL-G`. +--- When 'ruler' is on, the output of `CTRL-G` doen't contain the current +--- line number of the cursor position. --- --- @type boolean vim.o.ruler = true @@ -5398,20 +5401,16 @@ vim.o.ru = vim.o.ruler vim.go.ruler = vim.o.ruler vim.go.ru = vim.go.ruler ---- When this option is not empty, it determines the content of the ruler ---- string, as displayed for the 'ruler' option. +--- This option determines the content of the ruler string, as displayed +--- for the 'ruler' option. --- The format of this option is like that of 'statusline'. +--- Setting to empty (`:set rulerformat=`) sets the value to the default. --- This option cannot be set in a modeline when 'modelineexpr' is off. --- ---- The default ruler width is 18 characters. To make the ruler 15 ---- characters wide, put "%15(" at the start and "%)" at the end. ---- Example: +--- When 'ruler' is on, the default 'statusline' includes 'rulerformat'. --- ---- ```vim ---- set rulerformat=%15(%c%V\ %p%%%) ---- ``` ---- ---- This looks like an item group, but there are some differences in this +--- The default ruler width is 18 characters, which is configured with +--- what looks like an item group. But there are some differences in this --- particular case. Most notably, the width is fixed and not a minimum, --- and the ruler is left-aligned, whereas the alignment of item groups is --- configurable and right-aligned by default. @@ -5420,7 +5419,7 @@ vim.go.ru = vim.go.ruler --- item group syntax has no special meaning for 'rulerformat'. --- --- @type string -vim.o.rulerformat = "" +vim.o.rulerformat = "%18(%l,%c%V%= %P%)%<" vim.o.ruf = vim.o.rulerformat vim.go.rulerformat = vim.o.rulerformat vim.go.ruf = vim.go.rulerformat @@ -6808,8 +6807,11 @@ vim.wo.stc = vim.wo.statuscolumn --- would loop. When the result contains unprintable characters the --- result is unpredictable. --- ---- Note that the only effect of 'ruler' when this option is set (and ---- 'laststatus' is 2 or 3) is controlling the output of `CTRL-G`. +--- When 'ruler' is on, the default 'statusline' includes 'rulerformat'. +--- See note below. +--- Note that if 'statusline' is configured without including the ruler, +--- the only effect of 'ruler' when this option is set (and 'laststatus' +--- is 2 or 3) is controlling the output of `CTRL-G`. --- --- field meaning ~ --- - Left justify the item. The default is right justified @@ -6826,10 +6828,10 @@ vim.wo.stc = vim.wo.statuscolumn --- --- Following is a description of the possible statusline items. The --- second character in "item" is the type: ---- N for number ---- S for string ---- F for flags as described below ---- - not applicable +--- "N" for number +--- "S" for string +--- "F" for flags as described below +--- "-" not applicable --- --- item meaning ~ --- f S Path to the file in the buffer, as typed or relative to current @@ -6886,6 +6888,8 @@ vim.wo.stc = vim.wo.statuscolumn --- ``` --- `stl=%{Stl_filename()}` results in `"%t"` --- `stl=%{%Stl_filename()%}` results in `"Name of current file"` +--- The default status line uses this to include 'rulerformat', see +--- note below. --- %} - End of "{%" expression --- ( - Start of item group. Can be used for setting the width and --- alignment of a section. Must be followed by %) somewhere. @@ -6922,11 +6926,13 @@ vim.wo.stc = vim.wo.statuscolumn --- is a bug that denotes that new mouse button recognition was --- added without modifying code that reacts on mouse clicks on --- this label. +--- --- Use `getmousepos()`.winid in the specified function to get the --- corresponding `window-ID` of the clicked item. --- \< - Where to truncate line if too long. Default is at the first --- item. Truncation markers within item groups apply to the --- truncation of that group until its maxwid is reached. +--- In case of several competing truncation markers, the first wins. --- No width fields allowed. --- = - Separation point between alignment sections. Each section will --- be separated by an equal number of spaces. With one %= what @@ -6992,20 +6998,20 @@ vim.wo.stc = vim.wo.statuscolumn --- edit your vimrc or whatever with "vim --clean" to get it right. --- --- Examples: ---- Emulate standard status line with 'ruler' set +--- A simple version of the standard status line with 'ruler' set --- --- ```vim ---- set statusline=%<%f\ %h%w%m%r%=%-14.(%l,%c%V%)\ %P +--- set statusline=%f\ %h%w%m%r%=\ %-14.(%l,%c%V%)\ %P --- ``` --- Similar, but add ASCII value of char under the cursor (like "ga") --- --- ```vim ---- set statusline=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P +--- set statusline=%f%h%m%r%=\ %b\ 0x%B\ \ %l,%c%V\ %P --- ``` --- Display byte count and byte value, modified flag in red. --- --- ```vim ---- set statusline=%<%f%=\ [%1*%M%*%n%R%H]\ %-19(%3l,%02c%03V%)%O'%02b' +--- set statusline=%f%=\ [%1*%M%*%n%R%H]\ %-19(%3l,%02c%03V%)%O'%02b' --- hi User1 term=inverse,bold cterm=inverse,bold ctermfg=red --- ``` --- Display a ,GZ flag if a compressed file is loaded @@ -7031,9 +7037,26 @@ vim.wo.stc = vim.wo.statuscolumn --- endfunction --- ``` --- +--- Note: By default, the status line is truncated from the left, and the +--- ruler from the right. But the status line can include the ruler. +--- To ensure that a top-level (i.e. not inside an item group) `%<` in +--- 'rulerformat' doesn't change the truncation of the status line, +--- - 'statusline' can be prepended with an explicit `%<`, which otherwise +--- would not be necessary. Example: +--- +--- ```vim +--- set statusline=%<%f%=\ %{%&rulerformat%} +--- ``` +--- - Or the ruler can be wrapped in an item group, which also collapses +--- any top-level `%=` in 'rulerformat' unless minwid is specified: +--- +--- ```vim +--- set statusline=%f%=\ %(%{%&rulerformat%}%) +--- ``` +--- --- --- @type string -vim.o.statusline = "%<%f %h%w%m%r %{% v:lua.require('vim._core.util').term_exitcode() %}%=%{% luaeval('(package.loaded[''vim.ui''] and vim.api.nvim_get_current_win() == tonumber(vim.g.actual_curwin or -1) and vim.ui.progress_status()) or '''' ')%}%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &busy > 0 ? '◐ ' : '' %}%{% luaeval('(package.loaded[''vim.diagnostic''] and next(vim.diagnostic.count()) and vim.diagnostic.status() .. '' '') or '''' ') %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}" +vim.o.statusline = "%<%f %h%w%m%r %{% v:lua.require('vim._core.util').term_exitcode() %}%=%{% luaeval('(package.loaded[''vim.ui''] and vim.api.nvim_get_current_win() == tonumber(vim.g.actual_curwin or -1) and vim.ui.progress_status()) or '''' ')%}%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &busy > 0 ? '◐ ' : '' %}%{% luaeval('(package.loaded[''vim.diagnostic''] and next(vim.diagnostic.count()) and vim.diagnostic.status() .. '' '') or '''' ') %}%{% &ruler ? &rulerformat : '' %}" vim.o.stl = vim.o.statusline vim.wo.statusline = vim.o.statusline vim.wo.stl = vim.wo.statusline -- cgit