I submitted PR #18871 two months ago.
However, because I set out an ideal final specification, I had to resolve several major issues and it nearly stalled.
So I closed that PR and switched to a more realistic approach, gradually merging the specifications one by one.
This way, I thought it would be feasible to implement without having to worry about things like uniform window heights.
@chrisbra and All,
Is there a chance this will be merged into mainstream?
https://github.com/vim/vim/pull/19123
(20 files)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Thanks, I think this is a nice addition.
Is there a chance this will be merged into mainstream?
Yes after the 9.2 release. We can then work out the remaining issues.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Under the specification of this PR, the code is almost complete and works as intended.
(I'll add a few tests to test_statuslineopt)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
How about using "\n" as a line break?
'tabpanel' does this.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
The tabpanel specification is odd.
I plan to change it to “%@”. Neither the statusline nor the tabpanel should be split using actual newline characters.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@chrisbra and All,
I don't think it's a good Vim specification for tabpanels to break lines with \n. I think the tabpanel specification change should be made by the 9.2 release, and it will be difficult to do so after that.
So in this PR I've reduced the multi-line statusline to a simpler specification and introduced a line break mechanism with %@ to 'statusline'. Then, to match this, I'm planning to change the specification of 'tabpanel' (abolishing line breaks with \n and introducing line breaks with %@) and refactor tabpanel.c, which is difficult to maintain.
Is the above plan acceptable?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
%@ may cause some confusion:
Copilot.png (view on web)
Note that GitHub Copilot's answer is incorrect here, as clickable statusline areas is a Neovim-only feature.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
I don't follow. I'd argue using \n would be a reasonable choice as linebreak character, since it is widely known even outside of the Vim community.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Thank you for your feedback. I understand that \n is widely recognized, but I have concerns about using it for line breaks in 'statusline', 'tabpanel' and 'tabline':
The 'statusline' family options are fundamentally built around a %-based item syntax (e.g., %f, %=, %%). Introducing \n as a line break mechanism would break this consistent design pattern. For uniformity, line breaks should also use a %-based syntax like %@.
In Vim script, \n behaves differently depending on the quote type:
"\n" (double quotes) → interpreted as actual newline character (0x0A)
'\n' (single quotes) → interpreted as literal two-character string \n
This creates confusion when users set 'statusline':
set statusline=Line1\nLine2 " May not work as expected let &statusline="Line1\nLine2" " Becomes actual newline at assignment let &statusline='Line1\nLine2' " Remains literal \n
When \n is converted to an actual newline character (0x0A) before the parser processes it, the parser cannot distinguish between:
Intentional line breaks (user’s desired formatting)
Unintentional newlines (from external data, user input, or file contents)
For example:
let &stl="abc\ndef"
At this point, \n has already been converted to byte 0x0A. The 'statusline' parser receives: "abc" + <0x0A> + "def" as a byte sequence, with no way to know whether this newline was intentional.
This is a fundamental design flaw—mixing control characters (formatting) with data (display content) at the same byte-level makes the parser fragile and potentially vulnerable.
With a %-based syntax, the parser can explicitly recognize line breaks as formatting directives, separate from data content.
I believe 'tabpanel' should also use %-based line breaks for consistency. Since 'tabpanel' is still relatively new (merged in patch 9.1.1391 on 2025 May), this is the right time to establish a consistent specification before 9.2 release.
For these technical reasons, I believe a %-based line break mechanism is more appropriate for both 'statusline' and 'tabpanel'.
Would you be open to reconsidering the use of %-based syntax for line breaks?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Okay fair. But changing tabpanel spec after the release is a bit late. Perhaps we should mark it experimental still, so that we can change the designating new-line atom. Also there is the neovim conflict for %@ as pointed out by @zeertzjq Is there a different mark we could use here?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Perhaps %;? A semicolon naturally has the "separator" meaning.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Thank you for reconsidering.
Why not document the "\n" line break in 'tabpanel' as "deprecated" and remove it in the next release (9.3 or 10.0)?
Also there is the neovim conflict for %@ as pointed out by @zeertzjq Is there a different mark we could use here?
Well, honestly, even now, When you use Neovim's %@FunaName@ ...%@, it should be judged by if has('nvim'). In other words, it should be fine even if Vim uses "%@" for something else in 'statusline'.
Here's my personal opinion...
Maybe the Neovim guys are planning to port this feature too?
If they do, it would be a bit disappointing, but that's a separate discussion.
In any case, I believe Vim should make its own design decisions without being constrained by Neovim's choices.
--
Best regards,
Hirohito Higashi (h_east)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@zeertzjq commented on this pull request.
In src/option.h:
> @@ -1383,6 +1385,7 @@ enum
#endif
#ifdef FEAT_STL_OPT
, WV_STL
+ , WV_STLO
This is no longer needed as 'statuslineopt' is now a global option.
In src/testdir/test_options.vim:
> + elseif opt == 'statuslineopt' + exe 'setl ' .. opt .. '=maxheight:4' + exe 'setg ' .. opt .. '=maxheight:5,fixedheight'
This code is never executed as 'statuslineopt' is not a window global-local option anymore, and isn't included in the result of GetGlobalLocalWindowOptions().
In src/testdir/test_options.vim:
> + elseif opt == 'statuslineopt'
+ call assert_equal('maxheight:5,fixedheight', eval('&g:' .. opt), 'option:' .. opt)
same here
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@chrisbra
I refactor tabpanel.c to Change line break "\n" to "%@".
Add support "\n" for 'tabpanel' for temporarily backward compatibility.
And the documentation now states that "\n" will no longer be supported in future versions.
I have confirmed that the latest commit (3405e7d) of this PR works with g:anypanel_sep = "%@" and "\n" in vim-anypanel (https://github.com/h-east/vim-anypanel).
Let's merge this PR before the 9.2 release!
If you agree, we will make the necessary corrections.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Sorry, that is a bit late now and I am only merging clear bug fixes. I'll just mark using "\n" as experimental and likely to be changed.
I can merge this after 9.2 and I feel like the correct % atom needs a bit more discussion, especially with regard to Neovim. I guess they will likely also merge this? @clason @zeertzjq ?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
It seems that this was also discussed in neovim/neovim#12925
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Sorry, that is a bit late now and I am only merging clear bug fixes. I'll just mark using "\n" as experimental and likely to be changed.
I'm sorry too. I was aware of the situation and made a strong offer. Your judgment is absolutely correct. Thank you.
I can merge this after 9.2
Thanks.
Please wait until I fix the following known issues and add tests:
... and I feel like the correct
%atom needs a bit more discussion, especially with regard to Neovim. I guess they will likely also merge this? @clason @zeertzjq ?
As I have already stated, Neovim is "something that used to be Vim," so I don't think there's any need for us to worry about compatibility.
Furthermore, since the Neovim guys don't seem interested in incorporating the features in this PR, I think the current specification of "%@" is fine.
By the way, the reason why "@" is used comes from :h <Nul>.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Sometimes things may happen in the other direction, when a Neovim feature is merged into Vim. I thought about this as well, and couldn't find any request for adding clickable statusline area into Vim, so perhaps this isn't a problem.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
since the Neovim guys don't seem interested in incorporating the features in this PR, I think the current specification of "%@" is fine.
It's likely that Neovim will merge this feature, since the code is fairly compatible with the existing statusline impl.
Users, and AI, benefit if we don't diverge unnecessarily. If Vim ever adds "click regions" to statusline, choosing some other syntax for that will add 2x confusion for users.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Please stop talking about "something that was Vim" here.
You're just adding your own features and incorporating Vim's features without permission. Vim shouldn't have to take into consideration the features you've added.
Don't try to justify yourselves with weird theories.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
Neovim guys will be flexible and not hesitate to change the specifications, right?
When this feature is merged into Vim, all problems will be solved by changing the specifications of the feature on the Neovim side.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 6 commits.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 9 commits.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 9 commits.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 12 commits.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 2 commits.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 17 commits.
You are receiving this because you are subscribed to this thread.![]()
@Copilot commented on this pull request.
This PR incrementally introduces a simpler multi-line statusline specification for Vim by adding a new global 'statuslineopt' option (currently supporting maxheight:) and enabling a line-break token in statusline-like format strings.
Changes:
'statuslineopt' (maxheight:{n}) and wire it into window layout/statusline height calculations.%@) and update tabpanel rendering to use the multi-line statusline builder.Copilot reviewed 25 out of 33 changed files in this pull request and generated 1 comment.
Show a summary per file| File | Description |
|---|---|
| src/window.c | Introduces statusline height helpers and propagates multi-line status height through split/equalize/layout logic. |
| src/vim.h | Adds statusline rendering mode enum and temporary compatibility macro. |
| src/vim.h | Adds statusline rendering mode enum and temporary compatibility macro. |
| src/testdir/util/gen_opt_test.vim | Adds generated option validation cases for 'statuslineopt'. |
| src/testdir/test_tabpanel.vim | Updates tabpanel tests to prefer %@ line breaks and refactors some test names. |
| src/testdir/test_statuslineopt.vim | Adds new automated tests for multi-line statusline behavior and best-effort maxheight. |
| src/testdir/dumps/Test_tabpanel_with_tabline_0.dump | New/updated screendump baseline for renamed tabpanel test. |
| src/testdir/dumps/Test_tabpanel_noeval_0.dump | New screendump baseline for renamed tabpanel test. |
| src/testdir/dumps/Test_tabpanel_noeval_1.dump | New screendump baseline for renamed tabpanel test. |
| src/testdir/dumps/Test_tabpanel_eval_0.dump | New screendump baseline for renamed tabpanel test. |
| src/testdir/dumps/Test_tabpanel_eval_1.dump | New screendump baseline for renamed tabpanel test. |
| src/testdir/dumps/Test_tabpanel_eval_with_linebreaks_0.dump | Updated screendump reflecting %@-based line breaking. |
| src/testdir/dumps/Test_tabpanel_eval_with_linebreaks_1.dump | New/updated screendump for %@/alignment behavior. |
| src/testdir/dumps/Test_tabpanel_cmdline_compl_0.dump | Adds screendump baseline for cmdline completion with tabpanel. |
| src/testdir/dumps/Test_tabpanel_cmdline_compl_1.dump | Adds screendump baseline for cmdline completion with tabpanel + pum. |
| src/testdir/dumps/Test_multistatusline_highlight_01.dump | Adds screendump baseline for multi-line statusline highlight test. |
| src/testdir/dumps/Test_multistatusline_highlight_02.dump | Adds screendump baseline for multi-line statusline highlight test. |
| src/testdir/Make_all.mak | Registers the new test_statuslineopt in the test runner. |
| src/tabpanel.c | Refactors tabpanel drawing to use multi-line statusline builder and centralized highlight rendering. |
| src/structs.h | Updates w_status_height documentation to reflect multi-line heights and update timing. |
| src/screen.c | Updates custom statusline/ruler/tabline drawing to render multiple statusline rows. |
| src/proto/window.pro | Adds prototypes for new window/statuslineopt helpers. |
| src/proto/optionstr.pro | Adds prototypes for 'statuslineopt' option handlers/expansion. |
| src/proto/buffer.pro | Adds prototypes for multi-line statusline builders and rendered-height helper. |
| src/optionstr.c | Adds 'statuslineopt' handlers and updates statusline format validation for %@. |
| src/optiondefs.h | Defines the new 'statuslineopt' option. |
| src/option.h | Adds STL_LINEBREAK token and declares the new option variable p_stlo. |
| src/gui.c | Updates mouse hit-testing to account for multi-line statusline height. |
| src/feature.h | Updates feature documentation to include 'statuslineopt' under +statusline. |
| src/drawscreen.c | Updates status redraw filling to cover multiple statusline rows. |
| src/buffer.c | Implements multi-line statusline builder variants and line-break parsing. |
| runtime/doc/windows.txt | Mentions that statusline height can be changed via 'statuslineopt'. |
| runtime/doc/tags | Adds help tags for 'statuslineopt' and the new %@ item. |
| runtime/doc/options.txt | Documents %@ and the 'statuslineopt' option; updates tabpanel docs for %@ usage. |
| src/vim.h | Adds statusline rendering mode enum and temporary compatibility macro. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
In src/window.c:
> + stlh_effort = stlo_mh; + FOR_ALL_TAB_WINDOWS(tp, wp) + frame_change_statusline_height_rec(tp->tp_topframe, false); + + stlo_mh = stlh_effort; + FOR_ALL_TAB_WINDOWS(tp, wp) + frame_change_statusline_height_rec(tp->tp_topframe, true);
frame_change_statusline_height() iterates with FOR_ALL_TAB_WINDOWS(tp, wp) but then calls frame_change_statusline_height_rec(tp->tp_topframe, ...) for every window. This ends up walking the full frame tree multiple times per tabpage (O(windows^2)) and, in the actual_change pass, repeatedly calls win_new_height() for the same windows. Iterate tabpages once (e.g. FOR_ALL_TABPAGES(tp)) and call the recursive helper once per tp->tp_topframe for each pass.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 5 commits.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@h-east commented on this pull request.
In src/window.c:
> + stlh_effort = stlo_mh; + FOR_ALL_TAB_WINDOWS(tp, wp) + frame_change_statusline_height_rec(tp->tp_topframe, false); + + stlo_mh = stlh_effort; + FOR_ALL_TAB_WINDOWS(tp, wp) + frame_change_statusline_height_rec(tp->tp_topframe, true);
Thanks.
Changed the macro FOR_ALL_TAB_WINDOWS to FOR_ALL_TABPAGES in frame_change_statusline_height().
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
It's ready to be merged.
It would be quite difficult to make 'statuslineopt' window-local, so I think it's more realistic to merge it as a global value.
Below are my thoughts.
Calling this a 'compatibility issue' is a misinterpretation of the term.
Compatibility usually refers to maintaining backward compatibility with older
versions of Vim or adhering to established industry standards. Neovim's
independent addition of a feature does not constitute a standard for Vim.
Demanding that Vim's core specifications be restricted by the choices of a
fork project is not about compatibility—it is an attempt to treat Vim as a
sub-project of Neovim, which is fundamentally unacceptable.
Vim has its own evolutionary path and design philosophy. As a maintainer, my
priority is to implement the best possible solution for Vim's users and its
codebase. If %@ is the most intuitive choice for representing line breaks in a
multi-line status line, then that is the 'correct' specification for Vim. We
cannot allow the independent extensions of a fork to dictate or paralyze the
future development of the original project. Maintaining the independence of
Vim's specifications is essential for the health of the ecosystem.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
@h-east pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
Thanks 🙏
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()
My opinion was not requested, but: I think it is a mistake not to work with the Neovim project where doing so makes sense and is easy. They have generously contributed here and (AFAIK) take almost all changes, esp. on the runtime side, seriously for inclusion on their end.
Yes, there are differences. Minimizing differences in the syntax of an option (for example) helps magnify the differences of import to users on both sides.
It is perfectly OK to discuss multiple kinds of compatibility here, and shutting down attempts to collaborate dooms us more than it helps us. Let’s be good stewards of a shared ecosystem.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.![]()