This is the first installment of a multi-PR series significantly
refactoring how highlights are being specified.
The end goal is to have a base set of 20 ish most common highlights,
and then specific files only need to add more groups to that as needed.
As a complicating factor, we also want to migrate to the new default
color scheme eventually. But by sharing a base set, that future PR
will hopefully be a lot smaller since a lot of tests will be migrated
just simply by updating the base set in place.
As a first step, fix the anti-pattern than Screen defaults to ignoring
highlights. Highlights are integral part of the screen state, not
something "extra" which we only test "sometimes". For now, we still
allow opt-out via the intentionally ugly
screen._default_attr_ids = nil
The end goal is to get rid of all of these eventually (which will be
easier as part of the color scheme migration)
Problem: Text is not redrawn with 'relativenumber' when only the 'statuscolumn' is redrawn after inserted lines.
Solution: Force a full redraw if statuscolumn width changed.
Problem: The 'statuscolumn' is not redrawn on the wrapped part of a
line when moving the cursor with 'relativenumber' set.
Solution: Redraw the 'statuscolumn' for the entire line height in the
"col_rows" win_line() code path.
Problem: Some edge cases to the old (pre-#26406) and current "b_signcols"
structure result in an incorrectly sized "auto" 'signcolumn'.
Solution: * Implement a simpler 'signcolumn' validation strategy by immediately
counting the number of signs in a range upon sign insertion and
deletion. Decrease in performance here but there is a clear path
forward to decreasing this performance hit by moving signs to a
dedicated marktree, or by adding meta-data to the existing
marktree which may be queried more efficiently?
* Also replace "max_count" and keep track of the number of lines with
a certain number of signs. This makes it so that it is no longer
necessary to scan the entire buffer when the maximum number of signs
decreases. This likely makes the commit a net increase in performance.
* To ensure correctness we also have re-initialize the count for an
edited region that spans multiple lines. Such an edit may move the
signs within it. Thus we count and decrement before splicing the
marktree and count and increment after.
Problem: Default number column has incorrect width after 'statuscolumn'
is unset due to an error, but was also truncated.
Solution: Reverse 'statuscolumn' error and truncate return branches.
This is the command invoked repeatedly to make the changes:
:%s/^\(.*\)|\%(\*\(\d\+\)\)\?$\n\1|\%(\*\(\d\+\)\)\?$/\=submatch(1)..'|*'..(max([str2nr(submatch(2)),1])+max([str2nr(submatch(3)),1]))/g
Problem: The legacy signlist data structures and associated functions are
redundant since the introduction of extmark signs.
Solution: Store signs defined through the legacy commands in a hashmap, placed
signs in the extmark tree. Replace signlist associated functions.
Usage of the legacy sign commands should yield no change in behavior with the
exception of:
- "orphaned signs" are now always removed when the line it is placed on is
deleted. This used to depend on the value of 'signcolumn'.
- It is no longer possible to place multiple signs with the same identifier
in a single group on multiple lines. This will now move the sign instead.
Moreover, both signs placed through the legacy sign commands and through
|nvim_buf_set_extmark()|:
- Will show up in both |sign-place| and |nvim_buf_get_extmarks()|.
- Are displayed by increasing sign identifier, left to right.
Extmark signs used to be ordered decreasingly as opposed to legacy signs.
Problem: Multibyte characters may be wrapped at the end of a line
when 'statuscolumn' and 'spell' are set.
Solution: Update line pointerdiff "v" before fetching the line pointer
after evaluating 'statuscolumn'.
Problem: The 'statusline'-format ui elements do not receive right
click events when "mousemodel" is "popup*"
Solution: Do not draw popupmenu and handle click event instead.
Problem: Estimated 'statuscolumn' width estimated is not properly used,
executing the `w_redr_statuscol` path unnecessarily.
Solution: Adjust `w_nrwidth` and 'statuscolumn' width before anything
is actually drawn in a `win_update()`.
Problem: The 'statuscolumn' is not drawn and the line itself is drawn
at an offset to the rest of the buffer after virt_lines if
'cpoptions' includes "n".
Solution: Make sure 'statuscolumn' is drawn.
* fix(column): rebuild status column when sign column is invalidated
Problem: When implementing a custom sign column through
`'statuscolumn'`, the status column is not properly rebuilt
when the sign column width changes.
Solution: Force a rebuild of the status column when the sign column
width is invalidated.
* test(column): 'statuscolumn' has correct width when (un)placing signs
Problem: 'statuscolumn' width can be incorrect when toggling 'number'
or setting 'statuscolumn'.
Solution: Make sure the width is reset and re-estimated when
'statuscolumn' and 'number' are set. (When 'relativenumber'
is set this already happens because it always changes
"nrwidth_line_count".)
Problem: The fold and sign column is built and stored regardless of
whether the corresponding item is present in 'statuscolumn'.
Solution: Since the 'statuscolumn' parses itself, we can defer
building the columns until the corresponding item is
actually encountered.
Problem: The 'statuscolumn' width is being estimated without the
proper context. In particular, this resulted in the fact
that a custom fold column could be included in the estimated
`number_width()`, and doubly added when actually drawing the
statuscolumn due to `win_col_off()` also adding the
`'foldcolumn'` width. Resulting in a status column that is
`'foldcolumn'` cells wider than necessary.
Solution: Estimate 'statuscolumn' width in `get_statuscol_str()` when
a buffer's line count has changed.
Problem: 'statuscolumn' click definitions are cleared, evaluated,
allocated and filled each redraw for every row in a window.
This despite the fact that we only store a single click
definition array for the entire column as opposed to one
for each row.
Solution: Only fill the 'statuscolumn' click definition array once per
window per redraw.
Resolve https://github.com/neovim/neovim/issues/21767.
Click definitions are always filled for tabline, statusline and winbar,
so they should also be always filled for statuscolumn, otherwise it will
leak memory.
Note: this doesn't actually change the existing code much, because of a
typo in the existing code.
Problem: The default fold column, as well as the 'statuscolumn', were
drawn unnecessarily/unexpectedly for virtual lines placed
with `virt_lines_leftcol` set.
Solution: Skip the column states if a virtual line with
`virt_lines_leftcol` set will be drawn.
Problem: The `'statuscolumn'` was not re-evaluated for wrapped lines,
when preceded by virtual/filler lines. There was also no way
to distinguish virtual and wrapped lines in the status column.
Solution: Make sure to rebuild the statuscolumn, and replace variable
`v:wrap` with `v:virtnum`. `v:virtnum` is negative when drawing
virtual lines, zero when drawing the actual buffer line, and
positive when drawing the wrapped part of a buffer line.
fix(statuscolumn): statusline click registered as statuscolumn
Problem: Status line click is registered as status status column click.
Solution: Check that mouse is not on the status line.
Resolve https://github.com/luukvbaal/statuscol.nvim/issues/4.