## Flicker cause
ui2's `check_targets()` function creates the hidden ui2 windows with this call chain:
```
nvim_open_win()
win_set_buf()
do_buffer()
set_curbuf()
enter_buffer()
```
and `enter_buffer()` sets `need_fileinfo`:
fdc09be03c/src/nvim/buffer.c (L1837-L1839)
This is then picked up by `normal_redraw`:
fdc09be03c/src/nvim/normal.c (L1381-L1385)
The fileinfo message then causes a ui2 window to appear to display it:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L325-L330)
... which ends up calling `set_pos`, which registers an `on_key` handler:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L726-L728)
This handler closes the ui2 window when the user presses, for example, `l` (because the user's not focusing said window).
The handler eventually calls `check_targets()`:
fdc09be03c/runtime/lua/vim/_core/ui2/messages.lua (L594-L595)
and `check_targets()` takes us back to the beginning, causing the ui2 window flicker
## Repro
```vim
=require("vim._core.ui2").enable()
set ch=0 shm-=F ve=all
e /tmp/x
```
Then hit `Ctrl-G` to show fileinfo (if not already shown) and hold `l`
## Fix
Effectively surround the ui2 window creating with `:silent`
Problem:
`nvim_create_autocmd` is too verbose and its `callback` requires extra
"nesting".
Solution:
Introduce `nvim_on`. Start using it internally. Then we can get a feel
for how it should look before making it public.
Problem:
- Configuring the height of one of the message targets to 1 is
recognized as 100% of 'lines'.
- Cmdline is expanded for message exceeding 'cmdheight' even if the
configured height is smaller than or equal to 'cmdheight'.
Solution:
- Recognize a height of 1 as absolute; a decimal number smaller than 1
is taken as a fraction of 'lines' (replace 1 with 0.999 for the old
behavior).
- Don't expand the cmdline if the configured height doesn't allow it.
Problem: - "bufwrite" message identifier is encoded in the message ID
of a "progress" kind message (since ff68fd6b); UI2 does not
allow routing by message ID.
- No documented way to set a default message target for all
but a few kinds (without copying all of |ui-messages| kinds
to cfg.msg.targets).
- A user adding a message route for the documented empty ""
kind can result in unexpected behavior.
- Showing duplicate message (x) indicator in msg and cmd
targets simultaneously is unsupported.
- Manually triggering CursorMoved autocommand to add matchparen
highlighting in the cmdline.
Solution: - Match cfg.msg.targets keys as Lua pattern to a message ID.
- Recognize "default" as key in cfg.msg.targets, drop the
undocumented cfg.msg.target field.
- Don't try to get configured target for "" message kind/trigger.
- Maintain msg indicator virtual text for the cmd and msg target.
- Add matchparen highlighting by directly calling the Lua module
(possible since b813c7e0).
Problem: Invalid check for non-typed key to dismiss expanded cmdline.
Unable to delay the timer that removes a message from the msg
window.
Solution: Check for empty string instead of nil to determine whether a
key is typed.
Restart the timer if it expires while the user is in the msg
window. Allow entering the msg window with a mouse click.
Problem: After closing a tabpage while the msg window is showing a
message, it is hidden while the msg window still contains a
message.
Solution: Unhide the msg window after entering a tabpage and it still
contains a message.
Co-authored-by: Linykq <yukunlin590@gmail.com>
Problem:
- Unable to "pin" a window to prevent closing without specifically
being targeted.
- :fclose closes hidden windows (even before visible windows).
Solution:
- Add 'winpinned' window-local option. When set, window is skipped by
:fclose and :only. Pin the ui2 cmdline window (which should always be
visible), so that it is not closed by :only/fclose.
- Skip over hidden (and pinned) windows with :fclose.
Co-authored-by: glepnir <glephunter@gmail.com>
Problem: `vim._core.ui2.enable` requires passing an empty table for
default options, unlike other (native) Lua API.
Solution: Initialize `opts` with empty table if `nil` is passed.
fix(ui2): prevent <CR> from focusing pager in insert/terminal mode
Problem: <CR> in insert/terminal mode can focus pager unexpectedly.
Solution: Don't enter the pager when <CR> is pressed during expanded
cmdline in insert/terminal mode.
Problem:
- Window height is set dynamically to match the text height,
making it difficult for the user to use a different height.
- Cmdwin is closed to enter the pager but still taken into
account for the pager position, and not restored when
the pager is closed.
- Dialog pager handler may unnecessarily consume <Esc>.
Solution:
- Add maximum height config fields for each of the UI2 windows,
where a number smaller than one is a fraction of 'lines',
absolute height otherwise (i.e. `cfg.msg.pager.height = 0.5`).
- If the cmdwin will be closed to enter the pager, don't try
to position the pager above it. Re-enter the cmdwin when the
pager is closed.
- Only add vim.on_key() handler for the dialog paging is actually
possible.
Problem: Windows are closed and re-opened after changing tabpage (and
might be removed from the current tabpage after 094b297a).
Solution: Ensure windows are on the current tabpage by moving them.
Problem: Previous tests for this relied on other events opening the
targets, which are not guaranteed to happen.
Solution: Open target windows when entering a new tabpage.
Problem: Unable to immediately open a typed command in the pager.
Solution: Support mapping msg_show "typed_cmd" trigger in
cfg.msg.targets (e.g. `targets = { typed_cmd = 'pager' }`).
Problem: Unable to configure message targets based on message kind.
Solution: Add cfg.msg.targets mapping message kinds to "cmd/msg/pager".
Check the configured target when writing the message.
cfg.msg = { target = 'cmd', targets = { progress = 'msg', list_cmd = 'pager' } }
will for example use the 'msg' target for progress messages,
immediately open the pager for 'list_cmd' and use the cmdline
for all other message kinds.
Problem: - Unintentionally inserting lines for a replaced multiline
message that also has multiple highlights.
- Scheduled check to see if the expanded cmdline window was
entered makes it difficult to keep track of what happens when
the key pressed to dismiss it results in a message.
- Reading the first line of an error message should be enough
notice for something going wrong.
- "search_cmd" messages should not be shown with 0 'cmdheight'.
- Unable to configure dynamically changed pager height.
- Enabling UI2 doesn't make sense with no UIs attached.
Solution: - Only insert a line for the first chunk after a newline.
- Use getmousepos() to check if the expanded cmdline was
clicked to enter the pager.
entering the pager to serve as a configuration interface.
- Don't expand the cmdline for error messages; user can press g<.
- Don't show "search_cmd" messages with 'cmdheight' set to 0.
- Change 'eventignorewin' to ensure WinEnter is fired when
- Have enable() return early when no UIs are attached.
Problem: Implicitly setting message target when 'cmdheight' changes.
Solution: Just use the user configured target. Support "cmd" target
with 'cmdheight' set to 0.
Problem: vim.on_key() called for each message while cmdline is open.
Cursor is on a seemingly random column when pager is entered.
Entering the pager while the cmdline is expanded can be more
convenient than pressing "g<".
Pager window is unnecessarily clamped to half the shell height.
Setting 'laststatus' while pager is open does not adjust its
dimensions.
Solution: Only call vim.on_key() once when dialog window is opened.
Ensure cursor is at the start of the first message when
entering the pager.
Enter the pager window when "<CR>" is pressed while the
cmdline is expanded.
Don't clamp the pager window height.
Set message windows dimensions when 'laststatus' changes.