-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
paste: redesign, fixes, 10x speedup #4448
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
Conversation
c9b85ab
to
8898ee5
Compare
runtime/doc/eval.txt
Outdated
@@ -3435,11 +3435,11 @@ getchar([expr]) *getchar()* | |||
:endfunction | |||
< | |||
You may also receive synthetic characters, such as | |||
|<CursorHold>|. Often you will want to ignore this and get | |||
|<LeftMouse>|. Often you will want to ignore this and get |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@justinmk I'm not sure I understand the goal behind this PR, is it to decouple the logic of automatically toggling If so, I don't see much gain here: We still have bracketed paste parsing hardcoded into the TUI, only the
If you could implement this, then yes, we could completely decouple bracketed paste(and possibly many other terminal sequences) from the tui. But it should not be However, this seems to overlap with @bfredl's work on #4419 : map <command> <Paste> if &paste | set nopaste | else | set paste Maybe it would be even better if we simply supported user-defined synthetic keys: map <command> <User:SOME_KEY_ID> if &paste | set nopaste | else | set paste The question is: How can a plugin tell the UI to put such synthetic keys into the input buffer? Right now we can't, but the TUI will soon allow configuration, so a bracketed paste plugin could be summarized to something like this: let g:tui_keys_override = {
\ '\x1b[200~': '<User:Paste>'
\ '\x1b[201~': '<User:Paste>'
\}
imap <command> <User:Paste> if &paste | set nopaste | else | set paste That is, the plugin asks the tui to translate bracketed pastes into |
src/nvim/main.c
Outdated
@@ -328,6 +326,9 @@ int main(int argc, char **argv) | |||
"'\\c\\m" PROTO "\\(.\\{-}\\)//'), 1, '')})"); | |||
#undef PROTO | |||
|
|||
do_cmdline_cmd("autocmd PastePre * set paste|if mode()!~#'c\\|t'|call feedkeys('\x1C\xEi','n')|endif"); | |||
do_cmdline_cmd("autocmd PastePost * set nopaste|if mode()!~#'c\\|t'|call feedkeys('\x1C\xE','n')|endif"); |
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.
\xE
looks weird, better write \x0E
.
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.
Though no, it is better to write this as \"\\<C-\\>\\<C-n>\"
.
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.
And I would also suggest to create autocmd group __Builtin
for all built-in autocommands (currently only this one and term://* BufReadCmd), so that they are easy to identify, making user aware of what he sees and, possibly, changes.
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.
Regex is better written as stridx('ct', mode()) == -1
or mode() !~# '[ct]'
.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@justinmk Bracketed paste is terminal-UI-specific thing. GUIs do not have anything like this, all they have are events from user: clipboard and mouse. There is no “external paste”, there are things like |
@justinmk |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
By the way, consider that user pressed Also I saw that you test ignoring second
(with
: no escaping. Spurious |
The text is not provided in any register or
Thanks, I will fix it. |
Alright. What about your suggestion of adding a generic mechanism to allow execution of vimscript when a certain synthetic keys are processed? Assuming the TUI allows the user to override terminal code parsing(it will), a bracketed paste plugin could do this: let g:tui_keys_override = {
\ '\x1b[200~': '<User:PasteEnable>'
\ '\x1b[201~': '<User:PasteDisable>'
\} It seems like something that could work. Even FocusGain/FocusLost could work nicely on such infrastructure. |
I also do not see tests for pasting while in all other modes (visual, select, operator-pending, replace, virtual replace). |
I suppose that would be fine if no one is convinced that PastePre/PastePost will be useful for GUIs (I gave use-cases above). But:
|
Hmm I wonder how to implement "Send paste sequences to :terminal" with that. Is the remapping done by the tui module or do you mean runtime will add those mappings to insert mode? |
@bfredl Neither of suggested variants allow implementing “send paste sequences to |
This is "readfile()-style", see also ":help channel-lines".
Fixes strange behavior where sometimes the buffer contents of a series of paste chunks (vim._paste) would be out-of-order. Now the tui_spec.lua screen-tests are much more reliable. But they still sometimes fail because of off-by-one cursor (caused by "typeahead race" resulting in wrong mode; fixed later in this patch-series).
- Send `phase` parameter to the paste handler. - Redraw at intervals and when paste terminates. - Show "..." throbber during paste to indicate activity.
Workaround this failure: [ ERROR ] test/functional/terminal/tui_spec.lua @ 192: TUI paste: exactly 64 bytes test/functional/helpers.lua:403: retry() attempts: 478 test/functional/terminal/tui_spec.lua:201: Expected objects to be the same. Passed in: (table: 0x47cd77e8) { *[1] = 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz endz' } Expected: (table: 0x47cd7830) { *[1] = 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz end' } This happens because `curwin->w_cursor.col` is sometimes decremented at the end of `do_put`... because the editor is in Normal-mode instead of the expected Insert-mode. Caused by "typeahead race" (neovim#10826): there may be queued input in the main thread not yet processed, thus the editor mode (`State` global) will be "wrong" during paste. Example: input "i" followed immediately by a paste sequence: i<start-paste>...<stop-paste> ^ "i" does not get processed in time, so the editor is in Normal-mode instead of Insert-mode while handling the paste. Attempted workarounds: - vim.api.nvim_feedkeys('','x',false) in vim._paste() - exec_normal() in tinput_wait_enqueue() - LOOP_PROCESS_EVENTS(&main_loop,…,0) in tinput_wait_enqueue() ref neovim#10826
- Normal-mode redo idiom(?): prepend "i" and append ESC. - Insert-mode only needs AppendToRedobuffLit(). - Cmdline-mode: only paste the first line.
HACK: The cursor does not get repositioned after the paste completes. Scheduling a dummy event seems to fix it. Test case: 0. Revert this commit. 1. Paste some text in Normal-mode. 2. Notice the cursor is still in the cmdline area.
- Show error only once per "paste stream". - Drain remaining chunks until phase=3. - Lay groundwork for "cancel". - Constrain semantics of "cancel" to mean "client must stop"; it is unrelated to presence of error(s).
- nvim_paste(): Marshal through luaeval() instead of nvim_execute_lua() because the latter seems to hide some errors. - Handle 'nomodifiable' in `nvim_put()` explicitly. - Require explicit `false` from `vim.paste()` in order to "cancel", otherwise assume true ("continue").
Resolution/Summary
Notes:
Locked to keep the summary visible. You can always chat or open a ticket if you have new information/topics to discuss. |
99a1753
to
fee2e1c
Compare
- Introduce TRY_WRAP() until we have an *architectural* solution. - TODO: bfredl idea: prepare error-handling at "top level" (nv_event). - nvim_paste(): Revert luaeval() hack (see parent commit). - With TRY_WRAP() in nvim_put(), 'nomodifiable' error now correctly "bubbles up".
This PR improves paste behavior and performance.
filetype=cpp
orfiletype=ruby
)vim.paste
(Lua)nvim_paste
for UIs/clientsnvim_put
inserts text (weird but true: this was difficult before)Tasks:
string_to_array()
?nvim_put
[WIP] nvim_put #6819nvim_paste
TODO (future):
p_pt
nvim_input
chunk. API: nvim_input_flush #10826TextPutPre
/TextPutPost
(analogs forTextYankPost
) ?:terminal
p
,:put
, etc.