Comments (11)
If anything, this indeed sounds like an issue with the clipboard provider. I don't think it is a good idea to optimize the code specifically under the assumption that
getreginfo()
andgetregtype()
may take a long time.
I was thinking the same and I totally agree with you. A hacky workaround in wl-clipboard
should not make mini.nvim
code messier.
@Susensio, would you mind applying the following patch and see if the delay persists?
As far as I can tell, now there should be a single call to either
getregtype()
andgetreginfo()
when doing replace.
It works! The delay is barely noticeable! Thank you so much for your time on this.
I don't know if this affects much more people. The lack of bug reports on this topic is strange. From what I've been reading, this hack depends on the wayland protocol implemented by each compositor. Mutter (gnome wayland compositor) forces wl-clipboard to use that focus-stealing hack, and thus the delay. Maybe the intersection of people using wayland, gnome and mini.operators is small.
Topics I found about this, for cross reference:
bugaevc/wl-clipboard#12 (comment)
bugaevc/wl-clipboard#163
https://gitlab.gnome.org/GNOME/mutter/-/issues/524
bugaevc/wl-clipboard#227
It may be a niche problem but, from what I've read, it is not going to be fixed upstream anytime soon...
If you think this should not be part of mini.operators
, I would keep this as a local branch in my fork. Anyhow, this is super good enough for me, thanks!
from mini.nvim.
Thanks for the follow up!
That diff should now be part of the main
branch. It reduces relatively big piece of code while making the rest not that bigger. So it's a win-win kind of situation :)
from mini.nvim.
Thanks for the issue!
I can not reproduce. Would you mind listing exact steps that makes you reproduce the issue on your end?
When
vim.opt.clipboard=unnamedplus
,replace
takes about 1 second to execute.
With this information (specifically 1 second), my guess is that there is some conflicting mapping starting with gr
. This makes Neovim wait after gr
a 'timeoutlen' milliseconds (1000 by default, i.e. 1 second) until executing the currently typed keys.
What does :map gr
show? It should show only mappings from 'mini.operators' (and possibly 'mini.clue' if you use it with g
as trigger). Note that it is not :nmap gr
, but :map gr
, which will show available mappings in several modes.
from mini.nvim.
I'm using the minimal.lua provided, so no additional mappings should be present.
Anyway:
x gr * <Cmd>lua MiniOperators.replace('visual')<CR>
Replace selection
n grr gr_
Replace line
n gr * v:lua.MiniOperators.replace()
Replace operator
I've tested that changing vim.opt.clipboard=unnamedplus
to vim.opt.clipboard=''
fixes the delay. So it must be some problem with my system clipboard, but I cannot figure it out...
The steps for reproducing the issue:
- start neovim with
nvim -nu minimal.lua
- yank some line with
yy
- replace some other line with
grr
Recording:
https://asciinema.org/a/uOfLU2adUpLOTrG284DwjrN9e
from mini.nvim.
I've profiled the mini.operators code and most of the time is spent in
mini.nvim/lua/mini/operators.lua
Lines 1027 to 1031 in ebc8cb0
from mini.nvim.
I still can not reproduce this, but it indeed looks like an issue with caching and restoring "
register (which maybe automatically touches system clipboard if 'clipboard' is not empty).
Would you mind confirming a couple for things for me, please?
- Does explicitly yanking and replacing from register produce the delay? So steps are now
"ayy
and"agrr
. - Does the following patch fix the issue?
diff --git a/lua/mini/operators.lua b/lua/mini/operators.lua index cddea21..535b557 100644 --- a/lua/mini/operators.lua +++ b/lua/mini/operators.lua @@ -1027,6 +1027,8 @@ H.replace_do = function(data) H.do_between_marks('d', delete_data) -- Paste register (ensuring same submode type as region) + local cache_clipboard = vim.o.clipboard + vim.o.clipboard = '' H.with_temp_context({ registers = { register } }, function() H.set_reg_type(register, submode) @@ -1036,6 +1038,7 @@ H.replace_do = function(data) local paste_keys = string.format('%d"%s%s', data.count or 1, register, (is_edge and 'p' or 'P')) H.cmd_normal(paste_keys) end) + vim.o.clipboard = cache_clipboard -- Adjust cursor to be at start mark vim.api.nvim_win_set_cursor(0, { from_line, from_col })
from mini.nvim.
- Does explicitly yanking and replacing from register produce the delay? So steps are now
"ayy
and"agrr
.
It does not produce any delay.
If using system clipboard with "+grr
, there is a delay.
(that delay does not exists with simple paste with "+p
- Does the following patch fix the issue?
Nop, same delay
from mini.nvim.
If using system clipboard with
"+grr
, there is a delay.
And I presume there is no delay if using regular register (like a
)?
Some other questions that might help:
- What clipboard/OS you're using here?
- Does delay happen on other text manipulation operators? Like
exchange
(gxx
) andmultiple
(gmm
)?
Unfortunately, that diff was the best attempt at fixing this. I'd need more profiling information. My suggestion would be to create a _G.log
variable and iteratively add table.insert(_G.log, { place = '<descriptive place name>', time = vim.loop.hrtime() })
before and after suspected lines that might cause delay. Identifying the exact line (which is not a call to a function from this module) would massively help. Because there are a lot going on inside those 4 lines.
from mini.nvim.
If using system clipboard with
"+grr
, there is a delay.And I presume there is no delay if using regular register (like
a
)?
That is correct. My previous answer was misquoted.
- What clipboard/OS you're using here?
I'm on Debian Gnome, using wayland (nvim is using wl-copy and wl-paste)
- Does delay happen on other text manipulation operators? Like
exchange
(gxx
) andmultiple
(gmm
)?
gmm
and gxx
work fine, with no visible delay
Unfortunately, that diff was the best attempt at fixing this. I'd need more profiling information.
I've managed to pinpoint the issue.
vim.fn.getreginfo
It takes ~0.5ms with regular registers
and ~150ms with system registers.
I think it gets called more than once..
vim.fn.getregtype
has the same problem.
I think this is related to
neovim/neovim#12622 and neovim/neovim#23748
This coment neovim/neovim#23748 (comment) explains that wl-copy has some hacks with undesirable effects.
The thing is that substitute.nvim
has no noticeable delay. I think the reason is that vim.fn.getregtype
and vim.fn.getreginfo
are being called only once, and mini.operators
calls then multiple times.
from mini.nvim.
I've managed to pinpoint the issue.
vim.fn.getreginfo
It takes ~0.5ms with regular registers and ~150ms with system registers. I think it gets called more than once..
vim.fn.getregtype
has the same problem.I think this is related to neovim/neovim#12622 and neovim/neovim#23748
This coment neovim/neovim#23748 (comment) explains that wl-copy has some hacks with undesirable effects.
The thing is that
substitute.nvim
has no noticeable delay. I think the reason is thatvim.fn.getregtype
andvim.fn.getreginfo
are being called only once, andmini.operators
calls then multiple times.
I see. Thanks for the investigation!
If anything, this indeed sounds like an issue with the clipboard provider. I don't think it is a good idea to optimize the code specifically under the assumption that getreginfo()
and getregtype()
may take a long time.
I'll take a look, but no promises.
from mini.nvim.
@Susensio, would you mind applying the following patch and see if the delay persists?
diff --git a/lua/mini/operators.lua b/lua/mini/operators.lua
index cddea215..249fd5d4 100644
--- a/lua/mini/operators.lua
+++ b/lua/mini/operators.lua
@@ -997,8 +997,8 @@ H.replace_do = function(data)
local mark_from, mark_to = data.mark_from, data.mark_to
-- Do nothing with empty/unknown register
- local register_type = H.get_reg_type(register)
- if register_type == '' then H.error('Register ' .. vim.inspect(register) .. ' is empty or unknown.') end
+ local reg_info = vim.fn.getreginfo(register)
+ if reg_info.regtype == nil then H.error('Register ' .. vim.inspect(register) .. ' is empty or unknown.') end
-- Determine if region is at edge which is needed for the correct paste key
local from_line, from_col = unpack(H.get_mark(mark_from))
@@ -1026,16 +1026,18 @@ H.replace_do = function(data)
{ mark_from = mark_from, mark_to = mark_to, submode = forced_motion, mode = data.mode, register = '_' }
H.do_between_marks('d', delete_data)
- -- Paste register (ensuring same submode type as region)
- H.with_temp_context({ registers = { register } }, function()
- H.set_reg_type(register, submode)
+ -- Modify register data to have proper submode and indent
+ local new_reg_info = vim.deepcopy(reg_info)
+ if new_reg_info.regtype:sub(1, 1) ~= submode then new_reg_info.regtype = submode end
+ if should_reindent then new_reg_info.regcontents = H.update_indent(new_reg_info.regcontents, init_indent) end
+ vim.fn.setreg(register, new_reg_info)
- -- Possibly reindent
- if should_reindent then H.set_reg_indent(register, init_indent) end
+ -- Paste
+ local paste_keys = string.format('%d"%s%s', data.count or 1, register, (is_edge and 'p' or 'P'))
+ H.cmd_normal(paste_keys)
- local paste_keys = string.format('%d"%s%s', data.count or 1, register, (is_edge and 'p' or 'P'))
- H.cmd_normal(paste_keys)
- end)
+ -- Restore register data
+ vim.fn.setreg(register, reg_info)
-- Adjust cursor to be at start mark
vim.api.nvim_win_set_cursor(0, { from_line, from_col })
@@ -1152,26 +1154,6 @@ end
H.is_content = function(x) return type(x) == 'table' and H.islist(x.lines) and type(x.submode) == 'string' end
--- Registers ------------------------------------------------------------------
-H.get_reg_type = function(regname) return vim.fn.getregtype(regname):sub(1, 1) end
-
-H.set_reg_type = function(regname, new_regtype)
- local reg_info = vim.fn.getreginfo(regname)
- local cur_regtype, n_lines = reg_info.regtype:sub(1, 1), #reg_info.regcontents
-
- -- Do nothing if already the same type
- if cur_regtype == new_regtype then return end
-
- reg_info.regtype = new_regtype
- vim.fn.setreg(regname, reg_info)
-end
-
-H.set_reg_indent = function(regname, new_indent)
- local reg_info = vim.fn.getreginfo(regname)
- reg_info.regcontents = H.update_indent(reg_info.regcontents, new_indent)
- vim.fn.setreg(regname, reg_info)
-end
-
-- Marks ----------------------------------------------------------------------
H.get_region_data = function(mode)
local submode = H.get_submode(mode)
As far as I can tell, now there should be a single call to either getregtype()
and getreginfo()
when doing replace.
from mini.nvim.
Related Issues (20)
- get icons based on file paths rather than display text HOT 2
- Add support for 256 colors in mini-hipatterns HOT 2
- [help wanted] How to keep extmark from removed after commenting code
- Can't install in Astronvim: fatal error HOT 3
- mini.files preview only for directories HOT 1
- Expected string|function, got nil HOT 4
- count + next/last in nested surrounds HOT 1
- Unexpected behavior when deleting quotes from a string HOT 2
- `mini.diff` affects the `foldmethod` option of the window opened by `vim-flog`. HOT 1
- Error on second navigation using mini.files when mapped to `-` HOT 4
- `goto_left` and `goto_right` for next/last variants HOT 1
- mini.statusLine error `attempt to call field 'is_enabled' (a nil value)` HOT 3
- [mini.git] Can I use :G instead of :Git HOT 2
- Feature: add option jump_to_single_result to lsp picker HOT 2
- Jump using ctrl-o not correct after navigating with lsp picker HOT 4
- When opening mini.files in a buffer deep into a project, I want mini.files to show that file. HOT 4
- mini.breadcrumbs plugin to show breadcrumbs of current cursor position using treesitter. HOT 1
- mini.files content.postfix HOT 1
- Add git conflict resolution HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mini.nvim.