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)
This commit is contained in:
Sébastien Hoffmann
2026-07-20 21:35:16 +02:00
parent 9be130304d
commit ca07e505f9
12 changed files with 224 additions and 226 deletions

View File

@@ -154,6 +154,8 @@ OPTIONS
To restore the previous truncation from the left, add a `%<` to the start.
The same applies to 'rulerformat', 'statuscolumn', 'tabline', 'winbar',
'titlestring', and 'iconstring'.
• 'rulerformat' can no longer be set empty, the new default expression will be
restored instead.
PLUGINS
@@ -229,7 +231,8 @@ BUILD
DEFAULTS
todo
'rulerformat' default is exposed as a statusline expression (previously it
was implemented as an internal C routine).
DIAGNOSTICS

View File

@@ -5181,43 +5181,45 @@ A jump table for the options with a short description can be found at |Q_op|.
*'ruler'* *'ru'* *'noruler'* *'noru'*
'ruler' 'ru' boolean (default on)
global
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.
*'rulerformat'* *'ruf'*
'rulerformat' 'ruf' string (default "")
'rulerformat' 'ruf' string (default "%18(%l,%c%V%= %P%)%<")
global
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: >vim
set rulerformat=%15(%c%V\ %p%%%)
<
This looks like an item group, but there are some differences in this
When 'ruler' is on, the default 'statusline' includes 'rulerformat'.
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.
@@ -6429,8 +6431,11 @@ A jump table for the options with a short description can be found at |Q_op|.
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
@@ -6447,10 +6452,10 @@ A jump table for the options with a short description can be found at |Q_op|.
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
@@ -6504,6 +6509,8 @@ A jump table for the options with a short description can be found at |Q_op|.
endfunc
< `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.
@@ -6540,11 +6547,13 @@ A jump table for the options with a short description can be found at |Q_op|.
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
@@ -6607,12 +6616,12 @@ A jump table for the options with a short description can be found at |Q_op|.
edit your vimrc or whatever with "vim --clean" to get it right.
Examples:
Emulate standard status line with 'ruler' set >vim
set statusline=%<%f\ %h%w%m%r%=%-14.(%l,%c%V%)\ %P
A simple version of the standard status line with 'ruler' set >vim
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 >vim
set statusline=...%r%{VarExists('b:gzflag','\ [GZ]')}%h...
@@ -6625,6 +6634,17 @@ A jump table for the options with a short description can be found at |Q_op|.
if exists(a:var) | return a:val | else | return '' | endif
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%}%)
<
*'suffixes'* *'su'*
'suffixes' 'su' string (default ".bak,~,.o,.h,.info,.swp,.obj")

View File

@@ -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

View File

@@ -7272,28 +7272,31 @@ local options = {
abbreviation = 'ru',
defaults = true,
desc = [=[
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.
]=],
full_name = 'ruler',
redraw = { 'statuslines' },
@@ -7305,19 +7308,18 @@ local options = {
{
abbreviation = 'ruf',
cb = 'did_set_rulerformat',
defaults = '',
defaults = '%18(%l,%c%V%= %P%)%<',
desc = [=[
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: >vim
set rulerformat=%15(%c%V\ %p%%%)
<
This looks like an item group, but there are some differences in this
When 'ruler' is on, the default 'statusline' includes 'rulerformat'.
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.
@@ -9086,7 +9088,7 @@ local options = {
cb = 'did_set_statusline',
defaults = {
if_true = table.concat({
'%<',
'%<', -- guards the default truncation from the left against a %< injected via rulerformat
'%f %h%w%m%r ',
"%{% v:lua.require('vim._core.util').term_exitcode() %}",
'%=',
@@ -9095,7 +9097,7 @@ local options = {
"%{% 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 ) : '' %}",
"%{% &ruler ? &rulerformat : '' %}",
}),
doc = 'is very long',
},
@@ -9126,8 +9128,11 @@ local options = {
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
@@ -9144,10 +9149,10 @@ local options = {
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
@@ -9201,6 +9206,8 @@ local options = {
endfunc
< `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.
@@ -9237,11 +9244,13 @@ local options = {
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
@@ -9304,12 +9313,12 @@ local options = {
edit your vimrc or whatever with "vim --clean" to get it right.
Examples:
Emulate standard status line with 'ruler' set >vim
set statusline=%<%f\ %h%w%m%r%=%-14.(%l,%c%V%)\ %P
A simple version of the standard status line with 'ruler' set >vim
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 >vim
set statusline=...%r%{VarExists('b:gzflag','\ [GZ]')}%h...
@@ -9322,6 +9331,17 @@ local options = {
if exists(a:var) | return a:val | else | return '' | endif
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%}%)
<
]=],
full_name = 'statusline',
modelineexpr = true,

View File

@@ -1838,8 +1838,8 @@ static const char *did_set_statustabline_rulerformat(optset_T *args, bool rulerf
char *s = *varp;
bool is_stl = args->os_idx == kOptStatusline;
// reset statusline to default when setting global option and empty string is being set
if (is_stl
// reset global statusline/rulerformat option to default when it is being set to an empty string
if ((is_stl || rulerformat)
&& ((args->os_flags & OPT_GLOBAL) || !(args->os_flags & OPT_LOCAL))
&& s[0] == NUL) {
xfree(*varp);

View File

@@ -460,13 +460,6 @@ msgstr "Katakana"
msgid "Bopomofo"
msgstr "Bopomofo"
#. row number, column number is appended
#. l10n: leave as-is unless a space after the comma is preferred
#. l10n: do not add any row/column label, due to the limited space
#, c-format
msgid "%ld,"
msgstr "%ld,"
msgid ""
"\n"
"\tLast set from "

View File

@@ -5477,10 +5477,6 @@ msgstr "Замінити «%.*s» на:"
msgid " < \"%.*s\""
msgstr " < «%.*s»"
#, c-format
msgid "%<PRId64>,"
msgstr "%<PRId64>, "
msgid "[Help]"
msgstr "[Допомога]"

View File

@@ -480,7 +480,6 @@ void win_redr_winbar(win_T *wp)
void redraw_ruler(void)
{
static bool did_show_ruler = false;
static int did_ruler_col = -1;
win_T *wp = !curwin->w_config.hide
&& curwin->w_status_height == 0 ? curwin : lastwin_nofloating(NULL);
bool is_stl_global = global_stl_height() > 0;
@@ -491,15 +490,10 @@ void redraw_ruler(void)
if (did_show_ext_ruler && ui_has(kUIMessages)) {
ui_call_msg_ruler((Array)ARRAY_DICT_INIT);
did_show_ext_ruler = false;
} else if (did_ruler_col > 0) {
msg_col = did_ruler_col;
msg_row = Rows - 1;
}
if (did_show_ruler && !ui_has(kUIMessages)) {
} else if (did_show_ruler && !ui_has(kUIMessages)) {
msg_clr_eos();
}
did_show_ruler = false;
did_ruler_col = -1;
return;
}
@@ -515,99 +509,8 @@ void redraw_ruler(void)
return;
}
if (*p_ruf && (p_ch > 0 || ui_has(kUIMessages))) {
win_redr_stl_expr(wp, false, true, ui_has(kUIMessages));
did_show_ruler = !ui_has(kUIMessages);
return;
}
hlf_T group = HLF_MSG;
int off = wp->w_status_height ? wp->w_wincol : 0;
int width = wp->w_status_height ? wp->w_width : Columns;
schar_T fillchar = schar_from_ascii(' ');
int attr = HL_ATTR(group);
// In list mode virtcol needs to be recomputed
colnr_T virtcol = wp->w_virtcol;
if (wp->w_p_list && wp->w_p_lcs_chars.tab1 == NUL) {
wp->w_p_list = false;
getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL, 0);
wp->w_p_list = true;
}
// Check if not in Insert mode and the line is empty (will show "0-1").
int empty_line = (State & MODE_INSERT) == 0
&& *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum) == NUL;
#define RULER_BUF_LEN 70
char buffer[RULER_BUF_LEN];
// row number, column number is appended
// l10n: leave as-is unless a space after the comma is preferred
// l10n: do not add any row/column label, due to the limited space
int bufferlen = vim_snprintf(buffer, RULER_BUF_LEN, _("%" PRId64 ","),
(wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
? 0
: (int64_t)wp->w_cursor.lnum);
bufferlen += col_print(buffer + bufferlen, RULER_BUF_LEN - (size_t)bufferlen,
empty_line ? 0 : (int)wp->w_cursor.col + 1,
(int)virtcol + 1);
// Add a "50%" if there is room for it.
char rel_pos[RULER_BUF_LEN];
int rel_poslen = get_rel_pos(wp, rel_pos, RULER_BUF_LEN);
int n1 = bufferlen + vim_strsize(rel_pos);
int this_ru_col = ru_col - (Columns - width);
// Never use more than half the window/screen width, leave the other half
// for the filename.
int n2 = (width + 1) / 2;
this_ru_col = MAX(this_ru_col, n2);
if (this_ru_col + n1 < width) {
// need at least space for rel_pos + NUL
while (this_ru_col + n1 < width
&& RULER_BUF_LEN > bufferlen + rel_poslen + 1) { // +1 for NUL
bufferlen += (int)schar_get(buffer + bufferlen, fillchar);
n1++;
}
bufferlen += vim_snprintf(buffer + bufferlen, RULER_BUF_LEN - (size_t)bufferlen,
"%s", rel_pos);
}
(void)bufferlen;
if (ui_has(kUIMessages)) {
MAXSIZE_TEMP_ARRAY(content, 1);
MAXSIZE_TEMP_ARRAY(chunk, 3);
ADD_C(chunk, INTEGER_OBJ(attr));
ADD_C(chunk, CSTR_AS_OBJ(buffer));
ADD_C(chunk, INTEGER_OBJ(HLF_MSG));
assert(attr == HL_ATTR(HLF_MSG));
ADD_C(content, ARRAY_OBJ(chunk));
ui_call_msg_ruler(content);
did_show_ext_ruler = true;
did_ruler_col = 1;
} else {
if (did_show_ext_ruler) {
ui_call_msg_ruler((Array)ARRAY_DICT_INIT);
did_show_ext_ruler = false;
}
// Truncate at window boundary.
for (n1 = 0, n2 = 0; buffer[n1] != NUL; n1 += utfc_ptr2len(buffer + n1)) {
n2 += utf_ptr2cells(buffer + n1);
if (this_ru_col + n2 > width) {
bufferlen = n1;
buffer[bufferlen] = NUL;
break;
}
}
grid_line_start(&msg_grid_adj, Rows - 1);
did_show_ruler = true;
did_ruler_col = off + this_ru_col;
int w = grid_line_puts(did_ruler_col, buffer, -1, attr);
grid_line_fill(did_ruler_col + w, off + width, fillchar, attr);
grid_line_flush();
}
win_redr_stl_expr(wp, false, true, ui_has(kUIMessages));
did_show_ruler = !ui_has(kUIMessages);
}
/// Get the character to use in a status line. Get its attributes in "*attr".

View File

@@ -561,14 +561,14 @@ describe('API/win', function()
api.nvim_set_option_value('statusline', 'window-status', { win = 0 })
eq('window-status', api.nvim_get_option_value('statusline', { win = 0 }))
eq(
"%<%f %{%nvim_eval_statusline('%h%w%m%r', {'maxwidth': 30}).width > 0 ? '%h%w%m%r ' : ''%}%=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}",
"%<%f %{%nvim_eval_statusline('%h%w%m%r', {'maxwidth': 30}).width > 0 ? '%h%w%m%r ' : ''%}%=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? &rulerformat : '' %}",
api.nvim_get_option_value('statusline', { scope = 'global' })
)
command('set modified')
command('enew') -- global-local: not preserved in new buffer
-- confirm local value was not copied
eq(
"%<%f %{%nvim_eval_statusline('%h%w%m%r', {'maxwidth': 30}).width > 0 ? '%h%w%m%r ' : ''%}%=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? ( &rulerformat == '' ? '%-14.(%l,%c%V%) %P' : &rulerformat ) : '' %}",
"%<%f %{%nvim_eval_statusline('%h%w%m%r', {'maxwidth': 30}).width > 0 ? '%h%w%m%r ' : ''%}%=%{% &showcmdloc == 'statusline' ? '%-10.S ' : '' %}%{% exists('b:keymap_name') ? '<'..b:keymap_name..'> ' : '' %}%{% &ruler ? &rulerformat : '' %}",
api.nvim_get_option_value('statusline', { win = 0 })
)
eq('', eval('&l:statusline'))

View File

@@ -27,7 +27,8 @@ M.nvim_set = (
'set shortmess+=IS background=light noswapfile noautoindent startofline'
.. ' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
.. " belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h"
.. [[ statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}]]
.. [[ statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ &rulerformat\ :\ ''\ %}]]
.. ' rulerformat=%18(%l,%c%V%=%P%)'
)
M.nvim_argv = {
M.nvim_prog,

View File

@@ -936,7 +936,7 @@ describe('ui/ext_messages', function()
end)
it("supports 'showcmd' and 'ruler(format)'", function()
command('set showcmd ruler')
command('set showcmd ruler rulerformat=%12(%l,%c%V%=%P%)')
command('hi link MsgArea ErrorMsg')
screen:expect({
grid = [[

View File

@@ -818,9 +818,6 @@ describe('statusline', function()
{2:[No Name] 0,0-1 All}|
0,0-1 All|
]])
command('set rulerformat=%18(%l,%c%V%=%P%)')
screen:expect_unchanged()
command('set rulerformat&')
api.nvim_win_close(win, true)
screen:expect([[
^ |
@@ -1145,7 +1142,7 @@ describe('default statusline', function()
"%{% 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 ) : '' %}",
"%{% &ruler ? &rulerformat : '' %}",
})
exec_lua("vim.o.statusline = ''")
@@ -1298,6 +1295,48 @@ describe('default statusline', function()
end)
end)
describe('default rulerformat', function()
local screen
before_each(function()
clear()
screen = Screen.new(60, 16)
command('set ruler')
end)
it('setting rulerformat to empty string sets default rulerformat', function()
exec_lua("vim.o.rulerformat = 'hjkl'")
eq('hjkl', eval('&rulerformat'))
screen:expect([[
^ |
{1:~ }|*14
hjkl |
]])
local default_rulerformat = '%18(%l,%c%V%= %P%)%<'
exec_lua("vim.o.rulerformat = ''")
eq(default_rulerformat, eval('&rulerformat'))
screen:expect([[
^ |
{1:~ }|*14
0,0-1 All|
]])
-- Reset to default if there's an error.
command('set rulerformat=%{a%}')
eq(default_rulerformat, eval('&rulerformat'))
eq(default_rulerformat, eval('&g:rulerformat'))
eq(default_rulerformat, eval('&l:rulerformat'))
command('redrawstatus') -- like Vim, rulerformat isn't immediately redrawn after an error
screen:expect([[
^ |
{1:~ }|*14
{9:E121: Undefined variable: a} 0,0-1 All|
]])
end)
end)
describe("'statusline' in floatwin", function()
local screen
before_each(function()