dstein64 / nvim-scrollview

A Neovim plugin that displays interactive vertical scrollbars and signs.
MIT License
546 stars 10 forks source link

Pasting via the right-click menu inserts junk #133

Closed Jint-lzxy closed 3 months ago

Jint-lzxy commented 3 months ago

Neovim version: NVIM v0.10.0 Operating system: macOS 14.5

Hello! First of all, sorry for the somewhat complicated init.lua. I couldn't narrow it down further, and I'm not sure yet if this is really a bug :( Basically, this issue occurs when using the "Paste" action in the right-click dropdown. Often, texts like re("scrollview").handle_mouse("left", true) (which can vary in length) get inserted into the buffer, and other things get messed up too. Here's the minimal init.lua:

local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
    vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system({
        "git",
        "clone",
        "--filter=blob:none",
        "--single-branch",
        "https://github.com/folke/lazy.nvim.git",
        lazypath,
    })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
require("lazy").setup({
    "dstein64/nvim-scrollview",
}, {
    root = root .. "/plugins",
})

-- add anything else here
vim.g.mapleader = " "
vim.api.nvim_set_keymap("n", "<leader>r", "<Cmd>noh<CR>", {})

To reproduce this issue, the prerequisites are as follows:

Now use this init.lua to open any blank file, and insert some random content like the following:

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce sollicitudin dui et mauris bibendum, condimentum ultricies justo rutrum.

Position the cursor anywhere in the file and paste some random text via the right-click menu (e.g., the one above). This issue can then be observed along with other peculiar behaviors like Neovim starting to record content into the u register and entering Insert mode unexpectedly.

Just in case it could be helpful, here are the logs when I perform the paste action:

```console Searching for "autoload/provider/clipboard.vim" in runtime path Searching for "/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS/.repro//config/nvim/autoload/provider/clipboard.vim" Searching for "/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS/.repro/plugins/lazy.nvim/autoload/provider/clipboard.vim" Searching for "/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS/.repro/plugins/nvim-scrollview/autoload/provider/clipboard.vim" Searching for "/usr/local/Cellar/neovim/0.10.0/share/nvim/runtime/autoload/provider/clipboard.vim" chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) chdir(/usr/local/Cellar/neovim/0.10.0/share/nvim/runtime/autoload/provider/) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) sourcing "/usr/local/Cellar/neovim/0.10.0/share/nvim/runtime/autoload/provider/clipboard.vim" line 1: " The clipboard provider uses shell commands to communicate with the clipboard. line 2: " The provider function will only be registered if a supported command is line 3: " available. line 4: line 5: if exists('g:loaded_clipboard_provider') line 6: finish line 7: endif line 8: " Default to 1. provider#clipboard#Executable() may set 2. line 9: " To force a reload: line 10: " :unlet g:loaded_clipboard_provider line 11: " :runtime autoload/provider/clipboard.vim line 12: let g:loaded_clipboard_provider = 1 line 13: line 14: let s:copy = {} line 15: let s:paste = {} line 16: let s:clipboard = {} line 17: line 18: " When caching is enabled, store the jobid of the xclip/xsel process keeping line 19: " ownership of the selection, so we know how long the cache is valid. line 20: let s:selection = { 'owner': 0, 'data': [], 'stderr_buffered': v:true } line 21: line 22: function! s:selection.on_exit(jobid, data, event) abort line 35: line 36: let s:selections = { '*': s:selection, '+': copy(s:selection) } line 37: line 38: function! s:try_cmd(cmd, ...) abort line 51: line 52: " Returns TRUE if `cmd` exits with success, else FALSE. line 53: function! s:cmd_ok(cmd) abort line 57: line 58: function! s:split_cmd(cmd) abort line 61: line 62: let s:cache_enabled = 1 line 63: let s:err = '' line 64: line 65: function! provider#clipboard#Error() abort line 68: line 69: function! provider#clipboard#Executable() abort line 165: line 166: function! s:clipboard.get(reg) abort line 183: line 184: function! s:clipboard.set(lines, regtype, reg) abort line 242: line 243: function! provider#clipboard#Call(method, args) abort line 254: line 255: " eval_has_provider() decides based on this variable. line 256: let g:loaded_clipboard_provider = empty(provider#clipboard#Executable()) ? 1 : 2 calling provider#clipboard#Executable() line 1: " Setting g:clipboard to v:false explicitly opts-in to using the "builtin" clipboard providers below line 2: if exists('g:clipboard') && g:clipboard isnot# v:false line 3: if type({}) isnot# type(g:clipboard) || type({}) isnot# type(get(g:clipboard, 'copy', v:null)) || type({}) isnot# type(get(g:clipboard, 'paste', v:null)) line 6: let s:err = 'clipboard: invalid g:clipboard' line 7: return '' line 8: endif line 9: line 10: let s:copy = {} line 11: let s:copy['+'] = s:split_cmd(get(g:clipboard.copy, '+', v:null)) line 12: let s:copy['*'] = s:split_cmd(get(g:clipboard.copy, '*', v:null)) line 13: line 14: let s:paste = {} line 15: let s:paste['+'] = s:split_cmd(get(g:clipboard.paste, '+', v:null)) line 16: let s:paste['*'] = s:split_cmd(get(g:clipboard.paste, '*', v:null)) line 17: line 18: let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0) line 19: return get(g:clipboard, 'name', 'g:clipboard') line 20: elseif has('mac') line 21: let s:copy['+'] = ['pbcopy'] line 22: let s:paste['+'] = ['pbpaste'] line 23: let s:copy['*'] = s:copy['+'] line 24: let s:paste['*'] = s:paste['+'] line 25: let s:cache_enabled = 0 line 26: return 'pbcopy' provider#clipboard#Executable returning 'pbcopy' continuing in /usr/local/Cellar/neovim/0.10.0/share/nvim/runtime/autoload/provider/clipboard.vim finished sourcing /usr/local/Cellar/neovim/0.10.0/share/nvim/runtime/autoload/provider/clipboard.vim calling provider#clipboard#Call('get', ['+']) line 1: if get(s:, 'here', v:false) " Clipboard provider must not recurse. #7184 line 2: return 0 line 3: endif line 4: let s:here = v:true line 5: try line 6: return call(s:clipboard[a:method],a:args,s:clipboard) calling 2('+') line 1: if type(s:paste[a:reg]) == v:t_func line 2: return s:paste[a:reg]() line 3: elseif s:selections[a:reg].owner > 0 line 4: return s:selections[a:reg].data line 5: end line 6: line 7: let clipboard_data = s:try_cmd(s:paste[a:reg]) calling 44_try_cmd(['pbpaste']) line 1: let out = systemlist(a:cmd, (a:0 ? a:1 : ['']), 1) Executing command: "'/usr/bin/pbpaste'" line 2: if v:shell_error line 3: if !exists('s:did_error_try_cmd') line 4: echohl WarningMsg line 5: echomsg "clipboard: error: ".(len(out) ? out[0] : v:shell_error) line 6: echohl None line 7: let s:did_error_try_cmd = 1 line 8: endif line 9: return 0 line 10: endif line 11: return out 44_try_cmd returning ['Lorem ipsum dolor sit amet, consecte..., condimentum ultricies justo rutrum.'] continuing in 2 line 8: if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0 && type(clipboard_data) == v:t_list && get(s:selections[a:reg].data, 0, []) ==# clipboard_data line 11: " When system clipboard return is same as our cache return the cache line 12: " as it contains regtype information line 13: return s:selections[a:reg].data line 14: end line 15: return clipboard_data 2 returning ['Lorem ipsum dolor sit amet, consecte..., condimentum ultricies justo rutrum.'] continuing in provider#clipboard#Call :return ['Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'Fusce sollicitudin dui et mauris bibendum, condimentum ultricies justo rutrum.'] made pending line 7: finally line 8: let s:here = v:false line 9: endtry :return ['Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'Fusce sollicitudin dui et mauris bibendum, condimentum ultricies justo rutrum.'] resumed provider#clipboard#Call returning ['Lorem ipsum dolor sit amet, consecte..., condimentum ultricies justo rutrum.'] Executing CursorMoved Autocommands for "*" autocommand call s:Highlight_Matching_Pair() Executing: call s:Highlight_Matching_Pair() calling 15_Highlight_Matching_Pair() line 1: if !exists("w:matchparen_ids") line 2: let w:matchparen_ids = [] line 3: endif line 4: " Remove any previous match. line 5: call s:Remove_Matches() calling 15_Remove_Matches() line 1: if exists('w:paren_hl_on') && w:paren_hl_on line 2: while !empty(w:matchparen_ids) line 3: silent! call remove(w:matchparen_ids, 0)->matchdelete() line 4: endwhile line 5: let w:paren_hl_on = 0 line 6: endif 15_Remove_Matches returning #0 continuing in 15_Highlight_Matching_Pair line 6: line 7: " Avoid that we remove the popup menu. line 8: " Return when there are no colors (looks like the cursor jumps). line 9: if pumvisible() || (&t_Co < 8 && !has("gui_running")) line 10: return line 11: endif line 12: line 13: " Get the character under the cursor and check if it's in 'matchpairs'. line 14: let c_lnum = line('.') line 15: let c_col = col('.') line 16: let before = 0 line 17: line 18: let text = getline(c_lnum) line 19: let matches = matchlist(text, '\(.\)\=\%'.c_col.'c\(.\=\)') line 20: if empty(matches) line 21: let [c_before, c] = ['', ''] line 22: else line 23: let [c_before, c] = matches[1:2] line 24: endif line 25: let plist = split(&matchpairs, '.\zs[:,]') line 26: let i = index(plist, c) line 27: if i < 0 line 28: " not found, in Insert mode try character before the cursor line 29: if c_col > 1 && (mode() == 'i' || mode() == 'R') line 30: let before = strlen(c_before) line 31: let c = c_before line 32: let i = index(plist, c) line 33: endif line 34: if i < 0 line 35: " not found, nothing to do line 36: return 15_Highlight_Matching_Pair returning #0 continuing in CursorMoved Autocommands for "*" Executing CursorMoved Autocommands for "*" autocommand Executing: autocommand Executing: Executing TextChanged Autocommands for "*" autocommand call s:Highlight_Matching_Pair() Executing: call s:Highlight_Matching_Pair() calling 15_Highlight_Matching_Pair() line 1: if !exists("w:matchparen_ids") line 2: let w:matchparen_ids = [] line 3: endif line 4: " Remove any previous match. line 5: call s:Remove_Matches() calling 15_Remove_Matches() line 1: if exists('w:paren_hl_on') && w:paren_hl_on line 2: while !empty(w:matchparen_ids) line 3: silent! call remove(w:matchparen_ids, 0)->matchdelete() line 4: endwhile line 5: let w:paren_hl_on = 0 line 6: endif 15_Remove_Matches returning #0 continuing in 15_Highlight_Matching_Pair line 6: line 7: " Avoid that we remove the popup menu. line 8: " Return when there are no colors (looks like the cursor jumps). line 9: if pumvisible() || (&t_Co < 8 && !has("gui_running")) line 10: return line 11: endif line 12: line 13: " Get the character under the cursor and check if it's in 'matchpairs'. line 14: let c_lnum = line('.') line 15: let c_col = col('.') line 16: let before = 0 line 17: line 18: let text = getline(c_lnum) line 19: let matches = matchlist(text, '\(.\)\=\%'.c_col.'c\(.\=\)') line 20: if empty(matches) line 21: let [c_before, c] = ['', ''] line 22: else line 23: let [c_before, c] = matches[1:2] line 24: endif line 25: let plist = split(&matchpairs, '.\zs[:,]') line 26: let i = index(plist, c) line 27: if i < 0 line 28: " not found, in Insert mode try character before the cursor line 29: if c_col > 1 && (mode() == 'i' || mode() == 'R') line 30: let before = strlen(c_before) line 31: let c = c_before line 32: let i = index(plist, c) line 33: endif line 34: if i < 0 line 35: " not found, nothing to do line 36: return 15_Highlight_Matching_Pair returning #0 continuing in TextChanged Autocommands for "*" Executing TextChanged Autocommands for "*" autocommand lua require('scrollview').refresh_bars_async() Executing: lua require('scrollview').refresh_bars_async() Executing CursorMoved Autocommands for "*" autocommand call s:Highlight_Matching_Pair() Executing: call s:Highlight_Matching_Pair() calling 15_Highlight_Matching_Pair() line 1: if !exists("w:matchparen_ids") line 2: let w:matchparen_ids = [] line 3: endif line 4: " Remove any previous match. line 5: call s:Remove_Matches() calling 15_Remove_Matches() line 1: if exists('w:paren_hl_on') && w:paren_hl_on line 2: while !empty(w:matchparen_ids) line 3: silent! call remove(w:matchparen_ids, 0)->matchdelete() line 4: endwhile line 5: let w:paren_hl_on = 0 line 6: endif 15_Remove_Matches returning #0 continuing in 15_Highlight_Matching_Pair line 6: line 7: " Avoid that we remove the popup menu. line 8: " Return when there are no colors (looks like the cursor jumps). line 9: if pumvisible() || (&t_Co < 8 && !has("gui_running")) line 10: return line 11: endif line 12: line 13: " Get the character under the cursor and check if it's in 'matchpairs'. line 14: let c_lnum = line('.') line 15: let c_col = col('.') line 16: let before = 0 line 17: line 18: let text = getline(c_lnum) line 19: let matches = matchlist(text, '\(.\)\=\%'.c_col.'c\(.\=\)') line 20: if empty(matches) line 21: let [c_before, c] = ['', ''] line 22: else line 23: let [c_before, c] = matches[1:2] line 24: endif line 25: let plist = split(&matchpairs, '.\zs[:,]') line 26: let i = index(plist, c) line 27: if i < 0 line 28: " not found, in Insert mode try character before the cursor line 29: if c_col > 1 && (mode() == 'i' || mode() == 'R') line 30: let before = strlen(c_before) line 31: let c = c_before line 32: let i = index(plist, c) line 33: endif line 34: if i < 0 line 35: " not found, nothing to do line 36: return 15_Highlight_Matching_Pair returning #0 continuing in CursorMoved Autocommands for "*" Executing CursorMoved Autocommands for "*" autocommand Executing: autocommand Executing: Executing InsertEnter Autocommands for "*" autocommand Executing: autocommand Executing: autocommand Executing: Executing InsertEnter Autocommands for "*" autocommand let g:scrollview_ins_mode_buf_lines = nvim_buf_line_count(0) Executing: let g:scrollview_ins_mode_buf_lines = nvim_buf_line_count(0) Executing CursorMovedI Autocommands for "*" autocommand call s:Highlight_Matching_Pair() Executing: call s:Highlight_Matching_Pair() calling 15_Highlight_Matching_Pair() line 1: if !exists("w:matchparen_ids") line 2: let w:matchparen_ids = [] line 3: endif line 4: " Remove any previous match. line 5: call s:Remove_Matches() calling 15_Remove_Matches() line 1: if exists('w:paren_hl_on') && w:paren_hl_on line 2: while !empty(w:matchparen_ids) line 3: silent! call remove(w:matchparen_ids, 0)->matchdelete() line 4: endwhile line 5: let w:paren_hl_on = 0 line 6: endif 15_Remove_Matches returning #0 continuing in 15_Highlight_Matching_Pair line 6: line 7: " Avoid that we remove the popup menu. line 8: " Return when there are no colors (looks like the cursor jumps). line 9: if pumvisible() || (&t_Co < 8 && !has("gui_running")) line 10: return line 11: endif line 12: line 13: " Get the character under the cursor and check if it's in 'matchpairs'. line 14: let c_lnum = line('.') line 15: let c_col = col('.') line 16: let before = 0 line 17: line 18: let text = getline(c_lnum) line 19: let matches = matchlist(text, '\(.\)\=\%'.c_col.'c\(.\=\)') line 20: if empty(matches) line 21: let [c_before, c] = ['', ''] line 22: else line 23: let [c_before, c] = matches[1:2] line 24: endif line 25: let plist = split(&matchpairs, '.\zs[:,]') line 26: let i = index(plist, c) line 27: if i < 0 line 28: " not found, in Insert mode try character before the cursor line 29: if c_col > 1 && (mode() == 'i' || mode() == 'R') line 30: let before = strlen(c_before) line 31: let c = c_before line 32: let i = index(plist, c) line 33: endif line 34: if i < 0 line 35: " not found, nothing to do line 36: return 15_Highlight_Matching_Pair returning #0 continuing in CursorMovedI Autocommands for "*" Executing CursorMovedI Autocommands for "*" autocommand Executing: Executing TextChangedI Autocommands for "*" autocommand call s:Highlight_Matching_Pair() Executing: call s:Highlight_Matching_Pair() calling 15_Highlight_Matching_Pair() line 1: if !exists("w:matchparen_ids") line 2: let w:matchparen_ids = [] line 3: endif line 4: " Remove any previous match. line 5: call s:Remove_Matches() calling 15_Remove_Matches() line 1: if exists('w:paren_hl_on') && w:paren_hl_on line 2: while !empty(w:matchparen_ids) line 3: silent! call remove(w:matchparen_ids, 0)->matchdelete() line 4: endwhile line 5: let w:paren_hl_on = 0 line 6: endif 15_Remove_Matches returning #0 continuing in 15_Highlight_Matching_Pair line 6: line 7: " Avoid that we remove the popup menu. line 8: " Return when there are no colors (looks like the cursor jumps). line 9: if pumvisible() || (&t_Co < 8 && !has("gui_running")) line 10: return line 11: endif line 12: line 13: " Get the character under the cursor and check if it's in 'matchpairs'. line 14: let c_lnum = line('.') line 15: let c_col = col('.') line 16: let before = 0 line 17: line 18: let text = getline(c_lnum) line 19: let matches = matchlist(text, '\(.\)\=\%'.c_col.'c\(.\=\)') line 20: if empty(matches) line 21: let [c_before, c] = ['', ''] line 22: else line 23: let [c_before, c] = matches[1:2] line 24: endif line 25: let plist = split(&matchpairs, '.\zs[:,]') line 26: let i = index(plist, c) line 27: if i < 0 line 28: " not found, in Insert mode try character before the cursor line 29: if c_col > 1 && (mode() == 'i' || mode() == 'R') line 30: let before = strlen(c_before) line 31: let c = c_before line 32: let i = index(plist, c) line 33: endif line 34: if i < 0 line 35: " not found, nothing to do line 36: return 15_Highlight_Matching_Pair returning #0 continuing in TextChangedI Autocommands for "*" Executing TextChangedI Autocommands for "*" autocommand if g:scrollview_ins_mode_buf_lines !=# nvim_buf_line_count(0) | execute "lua require('scrollview').refresh_bars_async()" | endif | let g:scrollview_ins_mode_buf_lines = nvim_buf_line_count(0) Executing: if g:scrollview_ins_mode_buf_lines !=# nvim_buf_line_count(0) | execute "lua require('scrollview').refresh_bars_async()" | endif | let g:scrollview_ins_mode_buf_lines = nvim_buf_line_count(0) Executing: execute "lua require('scrollview').refresh_bars_async()" | endif | let g:scrollview_ins_mode_buf_lines = nvim_buf_line_count(0) Executing: lua require('scrollview').refresh_bars_async() Executing: endif | let g:scrollview_ins_mode_buf_lines = nvim_buf_line_count(0) Executing: let g:scrollview_ins_mode_buf_lines = nvim_buf_line_count(0)-- INSERT --recording @u chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS/.repro/plugins/nvim-scrollview/lua/) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS/.repro/plugins/nvim-scrollview/lua/) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS/.repro/plugins/nvim-scrollview/lua/) chdir(/private/var/folders/jy/91xg_8j9169dydct2k4r7yw80000gn/T/scrollview.23bT4H8aCS) Executing: doautocmd User ScrollViewRefresh Executing User Autocommands for "ScrollViewRefresh" autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand Executing: autocommand ```

Many thanks beforehand!

dstein64 commented 3 months ago

Thanks for reporting the issue @Jint-lzxy.

This is fixed in 30ca6e18265928eb4ea7402346b4dfddbd8ce41e. The code was updated to use noremap instead of map.

If you're still encountering a problem, please let me know with a new Issue or a comment here.

Jint-lzxy commented 3 months ago

The code is now working perfectly! Thanks again for the speedy response :D