New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: user command "preview" (like inccommand) #18194
Conversation
💯 do not add more Vimscript syntax without a very strong reason.
I don't understand the reasoning there. Why is this worth increasing the surface area of code we need to maintain, documentation that users need to read and understand, syntax elements that need to be highlighted, errors that need to be surfaced, ...? Using |
Does this close #7370 or at least partially address it? Please reference relevant issues. |
Alright, I'll make it API-only in that case
I have no issue making it API-only. But I'm just wondering how it should be documented in that case. Putting it with other command attributes in the documentation would be weird since it'd be Lua only, and it's too much information to put in the documentation of |
There's precedent for that: the arguments passed to (only) Lua autocommand callbacks. A more structured way of indicating different API exposure ( |
True, but that can be improved later. For example the list can become agnostic, and then referenced from Vimscript is the "eval" part of Vim (including |
26ae0a3
to
edd9ef5
Compare
I think that's moreso the fault of |
361b708
to
3c14cb1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getting pretty close! A bit worried about the no_send_tick
/ changedtick
buffer flag
local command = helpers.command | ||
|
||
-- Implementation of a :Replace command that's used for testing user inccommand | ||
local SetupReplaceCmd = [[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Let's stick to one convention. all Lua code in the codebase uses snake_case.
- This function is huge. Is it necessary for the test? Any way to reduce the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we could try having a completely different type of preview
function entirely. I made one that mimics :substitute
because that's currently the standard for how command preview should behave.
@@ -253,7 +253,7 @@ void buf_updates_send_changes(buf_T *buf, linenr_T firstline, int64_t num_added, | |||
for (size_t i = 0; i < kv_size(buf->update_callbacks); i++) { | |||
BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i); | |||
bool keep = true; | |||
if (cb.on_lines != LUA_NOREF && (cb.preview || !(State & MODE_CMDPREVIEW))) { | |||
if (cb.on_lines != LUA_NOREF && (cb.preview || !cmdpreview)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why did this change from a formal "editor state", to a global variable (an implicit pseudo-state)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite a few functions reset the value of State
, which caused inccommand preview for some commands to not work properly, changing it to a global state fixes that issue.
return false; | ||
} else if (!IS_USER_CMDIDX(ea.cmdidx)) { | ||
// find_ex_command sets the flags for user commands automatically | ||
ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did find_ex_command
have these side-effects before this PR? is that avoidable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It did. And I think it's fine the way it is since find_ex_command
also has some other side-effects, so if we wanted to remove side-effects we'd have to remove all of them, which'd be quite a hassle.
runtime/doc/map.txt
Outdated
line1 - 1, | ||
line2, | ||
0, | ||
new_lines |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example will look a lot less intimidating if we just don't wrap the function args like this. Don't worry too much about exceeding 80 chars for code examples, if it helps with readability.
@@ -197,6 +197,9 @@ void buf_updates_send_changes(buf_T *buf, linenr_T firstline, int64_t num_added, | |||
return; | |||
} | |||
|
|||
// Don't send b:changedtick during 'inccommand' preview if "buf" is the current buffer. | |||
bool send_tick = !(cmdpreview && buf == curbuf); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The buf == curbuf
condition makes me wonder if the cmdpreview protocol should forbid switching buffers? But it is common for plugins to temporarily switch buffers, and we don't have a way of preventing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine. If a plugin does something stupid, it's the plugin's fault and Neovim doesn't have to deal with that
Adds a Lua-only `preview` flag to user commands which allows the command to be incrementally previewed like `:substitute` when 'inccommand' is set.
55194fa
to
46536f5
Compare
/// 5. If the return value of the preview callback is not 0, update the screen while the effects | ||
/// of the preview are still in place. | ||
/// 6. Revert all changes made by the preview callback. | ||
static void cmdpreview_show(CommandLineState *s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A key feature of 'inccommand' :substitute
is that it skips the preview if the preview takes too long:
Lines 4430 to 4432 in 46536f5
if (got_quit || profile_passed_limit(timeout)) { // Too slow, disable. | |
set_string_option_direct("icm", -1, (char_u *)"", OPT_FREE, | |
SID_NONE); |
That should also be built into the handling of user-defined cmd preview.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another important optimization was to stop looking for matches if additional ones would not be shown to the user (either the preview buffer is full and icm=split, or they're out of the viewport of the current buffer with icm=nosplit). This PR is too complicated for me, so I could not discern if that was implemented, but I figured I'd mention it (ofc it's most helpfull in large files).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A key feature of 'inccommand'
:substitute
is that it skips the preview if the preview takes too long:Lines 4430 to 4432 in 46536f5
if (got_quit || profile_passed_limit(timeout)) { // Too slow, disable. set_string_option_direct("icm", -1, (char_u *)"", OPT_FREE, SID_NONE); That should also be built into the handling of user-defined cmd preview.
How should we implement that though? Or should we leave that to the preview callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How should we implement that though? Or should we leave that to the preview callback?
Should be done implicitly, builtin.
- Maybe
f_wait
(:help wait()
) could be used, or at least provides a starting point:Line 3869 in c632f64
static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr) - I think we need this: Lua: interrupt / cancel Lua code #6800
- related stale PR: [WIP] Allow interrupting lua code #6809
Another important optimization was to stop looking for matches ... I could not discern if that was implemented,
@KillTheMule I believe that is covered by tests so I don't think there was a regression.
CHANGES: - Add a mutli-cursor mapping TODO: - Live preview via neovim/neovim#18194 - Add a highlight group (potentially)
This PR aims to add support for
inccommand
incremental preview functionality to user commands. It defines an incremental preview "protocol" that a user command can follow to add support for incremental live preview of that command wheninccommand
is enabled. This PR adds an API-onlypreview
flag to user commands which allows a command to be incrementally previewed.Closes #7370