Problem:
The "restart" event has some problems:
- all UI clients must implement a somewhat complex set of setups
- UI must be on the same machine as the server
- only works for the "current" UI
- race/edge case: If the user config has errors / waiting for input, are
all UIs able to attach while Nvim is waiting for input?
Solution:
- Perform the restart on the server, not the client.
- Pass listen address (instead of CLI args) in the UI event.
- Simplifies UI logic: they only need to attach to new address.
- Opens the door for more enhancements in the future, such as allowing
all UIs to reattach instead of only the "current" UI.
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem:
- Progress-events are filtered by "source". But "source" is not required by nvim_echo.
- Without "++nested" (force=false), nvim_echo in an event-handler does not trigger Progress events.
- vim.health does not declare a "source".
Solution:
- Make source mandatory for progress-messages
- Enable ++nested (force=true) by default when firing Progress event.
- Set "source" in vim.health module.
Problem:
Currently, there's no way to distinguish progress messages coming from
different sources. Nor can Progress event be easily filtered based on
source.
Solution:
- Add "source" field to nvim_echo-opts.
- The Progress event pattern is now defined by the "source" field.
- Include the "title" as ev.data.
- Unrelated change: set force=false to disable nesting.
Problem: nvim_set_hl always replaces all attributes.
Solution: Add update field. When true, merge with existing
attributes instead of replacing. Unspecified attributes are preserved.
If highlight group doesn't exist, falls back to reset mode.
Problem:
`vim.keymap.*.Opts.buf` allows `boolean` aliases for more widely
used `integer?` values, `true` -> `0` and `false` -> `nil`. This
conversion is unnecessary and can be handled at call sites.
Solution:
As a follow-up to deprecating the `buffer` option, drop support for
boolean values for the new `buf` option. The deprecated `buffer`
continues to support booleans for backward compatibility.
The `buffer` option remains functional but is now undocumented.
Providing both will raise an error. Since providing `buf` was disallowed
before, there is no code that will break due to using `buffer` alongside
`buf`.
Problem:
If buffer update callbacks poll for uv events during terminal scrollback
refresh, new output from PTY process may lead to incorrect scrollback.
Solution:
Don't poll for output to the same terminal as the one being refreshed.
Problem:
`nvim_echo(…, {id=…})` accepts user-defined id as a string or integer.
Generated ids are always higher than last highest msg-id used. Thus
plugins may accidentally advance the integer id "address space", which,
at minimum, could lead to confusion when troubleshooting, or in the
worst case, could overflow or "exhaust" the id address space.
There's no use-case for it, and it could be the mildly confusing, so we
should just disallow it.
Solution:
Disallow *integer* user-defined message-id.
Only allow *string* user-defined message-id.
Problem:
nvim_get_option_value with "filetype" set silently returns incorrect
defaults if autocommands are blocked, like when they're already running.
Solution:
Allow its FileType autocommands to nest: `do_filetype_autocmd(force=true)`.
Also error if executing them fails, rather than silently return wrong defaults.
Endless nesting from misbehaving scripts should be prevented by the recursion
limit in apply_autocmds_group, which is 10.
Problem: nvim_open_tabpage's "enter" argument is optional, which is inconsistent
with nvim_open_win.
Solution: make it a (non-optional) positional argument, like nvim_open_win.
Also change "enter"'s description to be more like nvim_open_win's doc.
Problem: "after" in nvim_open_tabpage is inconsistent with how a count works
with :tab, :tabnew, etc. Plus, the name "after" implies it's inserted after that
number.
Solution: internally offset by 1. Allow negative numbers to mean after current.
Hmm, should we even reserve sentinels for after current? Callers can probably
just use nil...
- Cleanup, remove redundant comments, add more tests.
- Enhance win_new_tabpage rather than create a new function for !enter, and use
a different approach that minimizes side-effects. Return the tabpage_T * and
first win_T * it allocated.
- Disallow during textlock, like other APIs that open windows.
- Remove existing win_alloc_firstwin error handling from win_new_tabpage; it's
not needed, and looks incorrect. (enter_tabpage is called for curtab, which is
not the old tabpage! Plus newtp is not freed)
- Fix checks after creating the tabpage:
- Don't fail if buf wasn't set successfully; the tab page may still be valid
regardless. Set buffer like nvim_open_win, possibly blocking Enter/Leave
events. (except BufWinEnter)
- tp_curwin may not be the initial window opened by win_new_tabpage. Use the
win_T * it returns instead, which is the real first window it allocated,
regardless of autocmd shenanigans.
- Properly check whether tab page was freed; it may have also been freed
before win_set_buf. Plus, it may not be safe to read its handle!
Problem: "win" is allowed in external window configs in some cases. External
window converted to normal float can't move tabpages in one nvim_win_set_config
call. External window can't be turned into a normal split.
Solution: disallow setting "win" for external windows. Allow external window to
move tabpages, which turns it non-external. Allow external window to be turned
into a (non-external) split.
parse_win_config has more validation issues from not considering the window's
existing config enough (not from this PR). For example, zindex can be set for an
existing split if "split"/"vertical" isn't given, despite intending for that to
be an error. Plus the logic is confusing.
It could do with a refactor at some point...
Problem: more cases where it may not be safe to move a window between tabpages.
Solution: check them.
Rather speculative... I haven't spend much time looking, but I didn't find
existing code that sets these locks to skip checking win_valid. (what I did find
called it anyway, like in win_close) Still, I think it's a good precaution for
what future code might do.
If the fact that nvim_win_set_config *actually* moves windows between tabpages
causes unforeseen issues, "faking" it like ":wincmd T" may be an alternative:
split a new window, close the old one, but instead also block autocmds, copy the
old window's config, and give it its handle?
Problem: only possible to move floats between tabpages if relative=win, which
has the restrictive effect of also anchoring it to the target window.
Solution: allow "win" without "relative" or "split"/"vertical". Only assume
missing "win" is 0 if relative=win is given to maintain that behaviour. (or when
configuring a new window)
Also add an error when attempting to change a split into a float that's in
another tabpage, as this isn't actually supported yet. (until the next commit)
Maybe this could do with some bikeshedding. Unclear if "win" should require
"relative" to be given, like with "row"/"col"; this can be annoying though as
specifying "relative" requires other fields to be given too.
Problem: possible to configure a split as a floatwin with relative=win that is
relative to itself.
Solution: fix the check.
Not caused by this PR; just something I noticed when about to fix the validation
logic.
Problem: when nvim_win_set_config moves a floatwin between tabpages, its grid
may remain if temporarily inside another tabpage. Also, things like tablines
aren't redrawn.
Solution: always remove its grid. Set must_redraw so things are redrawn even if
w_redr_type was already set for the old tabpage.
I don't think it's necessary to do anything extra here when removing the grid:
- win_ui_flush calls ui_call_win_hide anyway, and calling it manually ends up
sending two win_hide events.
- ui_comp_remove_grid safely does nothing if the grid doesn't exist.
- w_pos_changed is set by win_config_float later, if that's needed. I think the
pending_comp_index_update set by ui_comp_remove_grid is enough anyway, at
least for making sure win_ui_flush sends win_hide.
Added test fails with the prior approach of checking `parent_tp != curtab`, but
also `win_tp == curtab`. (which is a better, but still flawed alternative)
The added redrawing here also supersedes setting w_hl_needs_update, and also
redraws stuff like the tabline to pass the new test.
- Factor out logic to keep nvim_win_set_config clean.
- Clean up a few things, remove redundant logic, reflow some lines.
- Add some more comments where appropriate.
- Don't consider negative "win", as that's only relevant for splits.
- Add more test coverage.
- Add news.txt entry.
Problem: nvim_win_set_config can't move floating windows to different tab pages.
Solution: allow it.
Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Problem: nvim_parse_cmd rejects valid commands like `:1` (range-only)
or `aboveleft` (modifier-only).
Solution: allow empty command when range or modifiers exist, and handle
execution using existing range command logic.
Problem:
When a terminal process exits, "[Process Exited]" text is added
to the buffer contents.
Solution:
- Return `exitcode` field from `nvim_get_chan_info`.
- Show it in the default 'statusline'.
- Show exitcode as virtual text in the terminal buffer.
Problem:
There is an inconsistency between extmarks/highlights regarding the
`end_col` param.
Solution:
Allow end_col=-1 to mean "end of line" (if strict=false).
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
Problem: nvim_win_set_config may raise unnecessary errors when not moving a
split.
Solution: skip checks related to moving when only maybe resizing a split.
Problem: No explicit redraw after setting style=minimal in nvim_open_win or
nvim_win_set_config, which may cause it to appear like it's not set.
Solution: call changed_window_setting after applying the style, which should be
enough for these options.
Problem: nvim_win_set_config may merge configs despite failing to configure a
split, and without applying necessary side-effects (like setting style=minimal
options). Plus, autocommands may apply a different config after the merge,
causing side-effects to apply for an outdated config.
Solution: merge configs last, only on success. Include fields only relevant to
splits. Properly set _cmdline_offset for splits.
Maybe better to disallow _cmdline_offset for splits instead, as the pum is
relative to cmdline_row anyway? (I didn't want to change behaviour too much)
Also use expect_unchanged in an unrelated test to quash a warning.
Problem: nvim_win_set_config with style="minimal" does not take immediate effect
when a split is not moved.
Solution: don't skip nvim_win_set_config's epilogue when only a resize may be
needed. De-duplicate resize logic and remove unnecessary redraw. (win_set*_win
already handles that)
Problem: Calling nvim_set_hl() with url= crashes because it tries to
free arena-owned string memory.
Solution: Remove the bad free and return a validation error instead.
using the GNU compiler we just get a bunch of const warnings we can fix.
clang, however, gets really upset that the standard library suddenly
starts using a lot of c11 features, despite us being in -std=gnu99 mode.
Basically, _GNU_SOURCE which we set is taken as a _carte blanche_ by the
glibc headers to do whatever they please, and thus we must inform clang
that everything is still OK.
Problem: Unable to tell whether a msg_show event is emitted as a result
a command typed on the cmdline (UI may want to represent these
differently from other messages).
Solution: Add trigger parameter that is set to "typed_cmd" for
a message emitted due to an interactively typed command.
Possible extensions are mapping/timer/event but it's hard to
imagine a UI distinguishing those so not added here.
Problem: nvim_win_get_config() does not return a window's "style".
Solution: always include it, and document `style=""`.
Always included so it can be used reciprocally with nvim_open_win() or
nvim_win_set_config(). (otherwise the config of a window with kWinStyleUnused
will not unset the kWinStyleMinimal style of another window if passed to
nvim_win_set_config, for example)