diff --git a/README.md b/README.md index 93ef890..bf9b346 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ scrollview-configuration`). ## Requirements * `nvim>=0.6` -* Mouse functionality requires mouse support (see `:help 'mouse'`) +* Mouse functionality requires mouse support (see `:help 'mouse'`) and + `nvim>=0.11` * Signs require `nvim>=0.9` ## Installation diff --git a/autoload/scrollview.vim b/autoload/scrollview.vim index 240273d..03ef6bc 100644 --- a/autoload/scrollview.vim +++ b/autoload/scrollview.vim @@ -432,42 +432,6 @@ endif " * Mappings " ************************************************* -function! s:SetUpMouseMappings(button, primary) abort - if a:button isnot# v:null - " Create a mouse mapping only if mappings don't already exist and "!" is - " not used at the end of the button. For example, a mapping may already - " exist if the user uses swapped buttons from $VIMRUNTIME/pack/dist/opt - " /swapmouse/plugin/swapmouse.vim. Handling for that scenario would - " require modifications (e.g., possibly by updating the non-initial - " feedkeys calls in handle_mouse() to remap keys). - let l:force = v:false - let l:button = a:button - if strcharpart(l:button, strchars(l:button, 1) - 1, 1) ==# '!' - let l:force = v:true - let l:button = - \ strcharpart(l:button, 0, strchars(l:button, 1) - 1) - endif - " scrollview mouse handling is not supported in select-mode. #140 - for l:mapmode in ['n', 'x', 'i'] - execute printf( - \ 'silent! %snoremap %s <%smouse>' - \ .. ' lua require("scrollview").handle_mouse("%s", %s)', - \ l:mapmode, - \ l:force ? '' : '', - \ l:button, - \ l:button, - \ a:primary ? 'true' : 'false', - \ ) - endfor - endif -endfunction - -call s:SetUpMouseMappings(g:scrollview_mouse_primary, v:true) -" :popup doesn't work for nvim<0.8. -if has('nvim-0.8') - call s:SetUpMouseMappings(g:scrollview_mouse_secondary, v:false) -endif - " Additional mappings are defined for convenience of creating " user-defined mappings that call nvim-scrollview functionality. However, " since the usage of mappings requires recursive map commands, this diff --git a/doc/scrollview.txt b/doc/scrollview.txt index 381b36d..53bcaac 100644 --- a/doc/scrollview.txt +++ b/doc/scrollview.txt @@ -20,7 +20,8 @@ signs. The plugin is customizable (see |scrollview-configuration|). 1. Requirements *scrollview-requirements* * `nvim>=0.6` -* Scrollbar mouse dragging requires mouse support (see |'mouse'|) +* Scrollbar mouse functionality requires mouse support (see |'mouse'|) and + `nvim>=0.11` * Signs require `nvim>=0.9` ============================================================================ @@ -301,19 +302,15 @@ scrollview_mouse_primary *scrollview_mouse_primary* Possible values include `'left'`, `'middle'`, `'right'`, `'x1'`, and `'x2'`. These can be prepended with `'c-'` or `'m-'` for the control-key and alt-key variants (e.g., - `'c-left'` for control-left). An existing mapping will - not be clobbered, unless `'!'` is added at the end (e.g., - `'left!'`). Set to `v:null` to disable the functionality. - Defaults to `'left'`. Considered only when the plugin is - loaded. + `'c-left'` for control-left). Set to `v:null` to disable + the functionality. Defaults to `'left'`. scrollview_mouse_secondary *scrollview_mouse_secondary* |String| specifying the button for secondary mouse operations (clicking signs for additional information). See |scrollview_mouse_primary| for the possible values, - including how `'c-'`, `'m-'`, `'!'`, and `v:null` can be - utilized. Defaults to `'right'`. Considered only when the - plugin is loaded. + including how `'c-'`, `'m-'`, and `v:null` can be utilized. + Defaults to `'right'`. *scrollview_on_startup* scrollview_on_startup |Boolean| specifying whether scrollbars are enabled on diff --git a/lua/scrollview.lua b/lua/scrollview.lua index 9ab8482..c91a28a 100644 --- a/lua/scrollview.lua +++ b/lua/scrollview.lua @@ -138,6 +138,20 @@ local BORDER_RIGHT = 4 local BORDER_BOTTOM = 6 local BORDER_LEFT = 8 +-- Maps mouse buttons (e.g., 'left') to the Neovim key representation. +local MOUSE_LOOKUP = (function() + local valid_buttons = { + 'left', 'middle', 'right', 'x1', 'x2', + 'c-left', 'c-middle', 'c-right', 'c-x1', 'c-x2', + 'm-left', 'm-middle', 'm-right', 'm-x1', 'm-x2', + } + local result = {} + for _, button in ipairs(valid_buttons) do + result[button] = t('<' .. button .. 'mouse>') + end + return result +end)() + -- ************************************************* -- * Memoization -- ************************************************* @@ -2962,9 +2976,14 @@ local handle_mouse = function(button, primary) local mousedown = t('<' .. button .. 'mouse>') local mouseup = t('<' .. button .. 'release>') if not vim.g.scrollview_enabled then - -- nvim-scrollview is disabled. Process the click as it would ordinarily be - -- processed, by re-sending the click and returning. + -- We have to temporarily set handling_mouse to true so that the on_key + -- handler doesn't call handle_mouse. Setting it back to false is deferred + -- (a later comment explains why, where the same type of handling is used). + handling_mouse = true fn.feedkeys(mousedown, 'ni') + vim.defer_fn(function() + handling_mouse = false + end, 0) return end local state = init() @@ -3312,7 +3331,45 @@ local handle_mouse = function(button, primary) reset_memoize() end restore(state) - handling_mouse = false + -- The processing of feedkeys calls initiated above (that aren't consumed by + -- read_input_stream) does not happen immediately. Defer the setting of + -- handling_mouse to false, to prevent an infinite loop of calls to + -- handle_mouse (e.g., for an ordinary click not on a sign or scrollbar). + vim.defer_fn(function() + handling_mouse = false + end, 0) +end + +-- pcall is not necessary here to avoid an error in some cases (Neovim +-- #17273), since that would be necessary for nvim<0.8, where this code would +-- not execute (the on_key handling for the mouse requires nvim==0.11, for the +-- ability to ignore the key by returning the empty string). +if to_bool(fn.has('nvim-0.11')) then -- Neovim 0.11 for ignoring keys + vim.on_key(function(str) + local normalize = function(button) + if button == vim.NIL then + button = nil + elseif button:sub(-1) == '!' then + -- Remove a trailing "!", which was supported in older versions of the + -- plugin for clobbering mappings. + button = button:sub(1, -2) + end + return button + end + local primary = normalize(vim.g.scrollview_mouse_primary) + local secondary = normalize(vim.g.scrollview_mouse_secondary) + if primary ~= nil + and not handling_mouse + and str == MOUSE_LOOKUP[primary] then + handle_mouse(primary, true) + return '' -- ignore the mousedown + elseif secondary ~= nil + and not handling_mouse + and str == MOUSE_LOOKUP[secondary] then + handle_mouse(secondary, false) + return '' -- ignore the mousedown + end + end) end -- A convenience function for setting global options with