mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	fix(api): clamp range lines in nvim__redraw() (#31710)
				
					
				
			Problem:
`nvim__redraw()` doesn't clamp the lines in the `range` parameter before truncating to int. The resulting range may be empty when the original range contained buffer lines and vice versa.
E.g. for a buffer with 4 lines, these are the redrawn lines:
```lua
{ 2, 2 ^ 31 } -> none (should be { 2, 3 })
{ 2, 2 ^ 32 } -> none (should be { 2, 3 })
{ 2 ^ 32 - 1, 2 } -> { 0, 1 } (should be none)
```
Solution:
Clamp `range` values before truncating to int.
			
			
This commit is contained in:
		@@ -2374,13 +2374,23 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
 | 
			
		||||
             "%s", "Invalid 'range': Expected 2-tuple of Integers", {
 | 
			
		||||
      return;
 | 
			
		||||
    });
 | 
			
		||||
    linenr_T first = (linenr_T)kv_A(opts->range, 0).data.integer + 1;
 | 
			
		||||
    linenr_T last = (linenr_T)kv_A(opts->range, 1).data.integer;
 | 
			
		||||
    int64_t begin_raw = kv_A(opts->range, 0).data.integer;
 | 
			
		||||
    int64_t end_raw = kv_A(opts->range, 1).data.integer;
 | 
			
		||||
 | 
			
		||||
    buf_T *rbuf = win ? win->w_buffer : (buf ? buf : curbuf);
 | 
			
		||||
    if (last == -1) {
 | 
			
		||||
      last = rbuf->b_ml.ml_line_count;
 | 
			
		||||
    linenr_T line_count = rbuf->b_ml.ml_line_count;
 | 
			
		||||
 | 
			
		||||
    int begin = (int)MIN(begin_raw, line_count);
 | 
			
		||||
    int end;
 | 
			
		||||
    if (end_raw == -1) {
 | 
			
		||||
      end = line_count;
 | 
			
		||||
    } else {
 | 
			
		||||
      end = (int)MIN(MAX(begin, end_raw), line_count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (begin < end) {
 | 
			
		||||
      redraw_buf_range_later(rbuf, 1 + begin, end);
 | 
			
		||||
    }
 | 
			
		||||
    redraw_buf_range_later(rbuf, first, last);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Redraw later types require update_screen() so call implicitly unless set to false.
 | 
			
		||||
 
 | 
			
		||||
@@ -5385,8 +5385,53 @@ describe('API', function()
 | 
			
		||||
        13                                                          |
 | 
			
		||||
      ]],
 | 
			
		||||
    })
 | 
			
		||||
    -- takes buffer line count from correct buffer with "win" and {0, -1} "range"
 | 
			
		||||
    api.nvim__redraw({ win = 0, range = { 0, -1 } })
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('nvim__redraw range parameter', function()
 | 
			
		||||
    Screen.new(10, 5)
 | 
			
		||||
    fn.setline(1, fn.range(4))
 | 
			
		||||
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      _G.lines_list = {}
 | 
			
		||||
      ns = vim.api.nvim_create_namespace('')
 | 
			
		||||
      vim.api.nvim_set_decoration_provider(ns, {
 | 
			
		||||
        on_win = function()
 | 
			
		||||
        end,
 | 
			
		||||
        on_line = function(_, _, _, line)
 | 
			
		||||
          table.insert(_G.lines_list, line)
 | 
			
		||||
        end,
 | 
			
		||||
      })
 | 
			
		||||
      function _G.get_lines()
 | 
			
		||||
        local lines = _G.lines_list
 | 
			
		||||
        _G.lines_list = {}
 | 
			
		||||
        return lines
 | 
			
		||||
      end
 | 
			
		||||
    ]])
 | 
			
		||||
 | 
			
		||||
    api.nvim__redraw({ flush = true, valid = false })
 | 
			
		||||
    exec_lua('_G.get_lines()')
 | 
			
		||||
 | 
			
		||||
    local actual_lines = {}
 | 
			
		||||
    local function test(range)
 | 
			
		||||
      api.nvim__redraw({ win = 0, range = range })
 | 
			
		||||
      table.insert(actual_lines, exec_lua('return _G.get_lines()'))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test({ 0, -1 })
 | 
			
		||||
    test({ 2, 2 ^ 31 })
 | 
			
		||||
    test({ 2, 2 ^ 32 })
 | 
			
		||||
    test({ 2 ^ 31 - 1, 2 })
 | 
			
		||||
    test({ 2 ^ 32 - 1, 2 })
 | 
			
		||||
 | 
			
		||||
    local expected_lines = {
 | 
			
		||||
      { 0, 1, 2, 3 },
 | 
			
		||||
      { 2, 3 },
 | 
			
		||||
      { 2, 3 },
 | 
			
		||||
      {},
 | 
			
		||||
      {},
 | 
			
		||||
    }
 | 
			
		||||
    eq(expected_lines, actual_lines)
 | 
			
		||||
 | 
			
		||||
    n.assert_alive()
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user