@@ -122,6 +122,7 @@ local VIRTUAL_LINE_COUNT_KEY_PREFIX = 0
122122local PROPER_LINE_COUNT_KEY_PREFIX = 1
123123local TOPLINE_LOOKUP_KEY_PREFIX = 2
124124local GET_WINDOW_EDGES_KEY_PREFIX = 3
125+ local ROW_LENGTH_LOOKUP_KEY_PREFIX = 4
125126
126127-- Maps window ID and highlight group to a temporary highlight group with the
127128-- corresponding definition. This is reset on each refresh cycle.
@@ -437,7 +438,7 @@ local with_win_workspace = function(winid, fun)
437438 -- winbar-omitted height where applicable.
438439 height = math.max (1 , get_window_height (winid )),
439440 row = 0 ,
440- col = 0
441+ col = 0 ,
441442 })
442443 end )
443444 win_workspace_lookup [winid ] = workspace_winid
@@ -1379,6 +1380,52 @@ local get_scrollbar_character = function()
13791380 return character
13801381end
13811382
1383+ -- Returns a table that maps window rows to the length of text on that row.
1384+ -- WARN: When a multi-cell character is the last character on a row, the length
1385+ -- returned by this function represents the first cell of that character.
1386+ local get_row_length_lookup = function (winid )
1387+ local memoize_key =
1388+ table.concat ({ROW_LENGTH_LOOKUP_KEY_PREFIX , winid }, ' :' )
1389+ if memoize and cache [memoize_key ] then return cache [memoize_key ] end
1390+ local result = {}
1391+ with_win_workspace (winid , function ()
1392+ local scrolloff = api .nvim_win_get_option (0 , ' scrolloff' )
1393+ local virtualedit = api .nvim_win_get_option (0 , ' virtualedit' )
1394+ set_window_option (0 , ' scrolloff' , 0 )
1395+ set_window_option (0 , ' virtualedit' , ' none' )
1396+ fn .winrestview (api .nvim_win_call (winid , fn .winsaveview ))
1397+ vim .cmd (' keepjumps normal! H' )
1398+ local prior
1399+ -- Limit the number of steps as a precaution. The doubling of window height
1400+ -- is to be safe.
1401+ local max_steps = fn .winheight (0 ) * 2
1402+ local steps = 0
1403+ while fn .winline () > 1
1404+ and prior ~= fn .winline ()
1405+ and steps < max_steps do
1406+ steps = steps + 1
1407+ prior = fn .winline ()
1408+ vim .cmd (' keepjumps normal! g0gk' )
1409+ end
1410+ prior = nil
1411+ steps = 0
1412+ local winheight = get_window_height (0 )
1413+ while fn .winline () <= winheight
1414+ and prior ~= fn .winline ()
1415+ and steps < max_steps do
1416+ steps = steps + 1
1417+ prior = fn .winline ()
1418+ vim .cmd (' keepjumps normal! g$' )
1419+ result [fn .winline ()] = fn .wincol ()
1420+ vim .cmd (' keepjumps normal! g0gj' )
1421+ end
1422+ set_window_option (0 , ' scrolloff' , scrolloff )
1423+ set_window_option (0 , ' virtualedit' , virtualedit )
1424+ end )
1425+ if memoize then cache [memoize_key ] = result end
1426+ return result
1427+ end
1428+
13821429-- Show a scrollbar for the specified 'winid' window ID, using the specified
13831430-- 'bar_winid' floating window ID (a new floating window will be created if
13841431-- this is -1). Returns -1 if the bar is not shown, and the floating window ID
@@ -1444,6 +1491,15 @@ local show_scrollbar = function(winid, bar_winid)
14441491 return - 1
14451492 end
14461493 end
1494+ if to_bool (vim .g .scrollview_hide_on_text_intersect ) then
1495+ local row_length_lookup = get_row_length_lookup (winid )
1496+ for row = bar_position .row , bar_position .row + bar_position .height - 1 do
1497+ if row_length_lookup [row ] ~= nil
1498+ and row_length_lookup [row ] >= bar_position .col then
1499+ return - 1
1500+ end
1501+ end
1502+ end
14471503 if bar_bufnr == - 1 or not to_bool (fn .bufloaded (bar_bufnr )) then
14481504 if bar_bufnr == - 1 then
14491505 bar_bufnr = api .nvim_create_buf (false , true )
@@ -1800,6 +1856,16 @@ local show_signs = function(winid, sign_winids, bar_winid)
18001856 show = false
18011857 end
18021858 end
1859+ if to_bool (vim .g .scrollview_hide_on_text_intersect ) then
1860+ local row_length_lookup = get_row_length_lookup (winid )
1861+ for c = col , col + sign_width - 1 do
1862+ if row_length_lookup [row ] ~= nil
1863+ and row_length_lookup [row ] >= c then
1864+ show = false
1865+ break
1866+ end
1867+ end
1868+ end
18031869 if show then
18041870 if sign_bufnr == - 1 or not to_bool (fn .bufloaded (sign_bufnr )) then
18051871 if sign_bufnr == - 1 then
@@ -2584,6 +2650,13 @@ local enable = function()
25842650 \ | execute "lua require('scrollview').refresh_bars_async()"
25852651 \ | endif
25862652
2653+ " Refresh scrollview when text is changed in insert mode. This way,
2654+ " scrollbars and signs will appear/hide accordingly when modifying text.
2655+ autocmd TextChangedI *
2656+ \ if g:scrollview_hide_on_text_intersect
2657+ \ | execute "lua require('scrollview').refresh_bars_async()"
2658+ \ | endif
2659+
25872660 " The following handles when :e is used to load a file. The asynchronous
25882661 " version handles a case where :e is used to reload an existing file, that
25892662 " is already scrolled. This avoids a scenario where the scrollbar is
0 commit comments