mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-03 17:24:29 +00:00 
			
		
		
		
	test: support upvalues in exec_lua
This commit is contained in:
		
				
					committed by
					
						
						Lewis Russell
					
				
			
			
				
	
			
			
			
						parent
						
							a19e89022d
						
					
				
				
					commit
					e5c174421d
				
			@@ -7,6 +7,7 @@ local MsgpackRpcStream = require('test.client.msgpack_rpc_stream')
 | 
			
		||||
--- @field private _prepare uv.uv_prepare_t
 | 
			
		||||
--- @field private _timer uv.uv_timer_t
 | 
			
		||||
--- @field private _is_running boolean
 | 
			
		||||
--- @field exec_lua_setup boolean
 | 
			
		||||
local Session = {}
 | 
			
		||||
Session.__index = Session
 | 
			
		||||
if package.loaded['jit'] then
 | 
			
		||||
 
 | 
			
		||||
@@ -282,19 +282,19 @@ describe('lua buffer event callbacks: on_lines', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function()
 | 
			
		||||
    local code = [[
 | 
			
		||||
    local code = function()
 | 
			
		||||
      local buf = vim.api.nvim_create_buf(false, false)
 | 
			
		||||
 | 
			
		||||
      vim.cmd"split"
 | 
			
		||||
      vim.cmd 'split'
 | 
			
		||||
      vim.api.nvim_win_set_buf(0, buf)
 | 
			
		||||
 | 
			
		||||
      vim.api.nvim_buf_attach(buf, false, {
 | 
			
		||||
        on_detach = function(_, buf)
 | 
			
		||||
        on_detach = function(_, buf0)
 | 
			
		||||
          vim.fn.tabpagebuflist()
 | 
			
		||||
          vim.fn.win_findbuf(buf)
 | 
			
		||||
        end
 | 
			
		||||
          vim.fn.win_findbuf(buf0)
 | 
			
		||||
        end,
 | 
			
		||||
      })
 | 
			
		||||
    ]]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    exec_lua(code)
 | 
			
		||||
    command('q!')
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
local t = require('test.testutil')
 | 
			
		||||
local n = require('test.functional.testnvim')()
 | 
			
		||||
 | 
			
		||||
local NIL = vim.NIL
 | 
			
		||||
local command = n.command
 | 
			
		||||
local clear = n.clear
 | 
			
		||||
local exec_lua = n.exec_lua
 | 
			
		||||
@@ -175,11 +174,11 @@ describe('vim.diagnostic', function()
 | 
			
		||||
    eq(3, #result)
 | 
			
		||||
    eq(
 | 
			
		||||
      2,
 | 
			
		||||
      exec_lua(function(result0)
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        return #vim.tbl_filter(function(d)
 | 
			
		||||
          return d.bufnr == _G.diagnostic_bufnr
 | 
			
		||||
        end, result0)
 | 
			
		||||
        end, result)
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
    eq('Diagnostic #1', result[1].message)
 | 
			
		||||
  end)
 | 
			
		||||
@@ -792,7 +791,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    --- @return table
 | 
			
		||||
    local function test_enable(legacy)
 | 
			
		||||
      local result = exec_lua(function(legacy0)
 | 
			
		||||
      return exec_lua(function()
 | 
			
		||||
        local other_bufnr = vim.api.nvim_create_buf(true, false)
 | 
			
		||||
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
 | 
			
		||||
@@ -823,7 +822,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
            + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if legacy0 then
 | 
			
		||||
        if legacy then
 | 
			
		||||
          vim.diagnostic.disable(_G.diagnostic_bufnr, _G.diagnostic_ns)
 | 
			
		||||
        else
 | 
			
		||||
          vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
 | 
			
		||||
@@ -836,7 +835,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
            + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if legacy0 then
 | 
			
		||||
        if legacy then
 | 
			
		||||
          vim.diagnostic.disable(_G.diagnostic_bufnr, _G.other_ns)
 | 
			
		||||
        else
 | 
			
		||||
          vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns })
 | 
			
		||||
@@ -849,7 +848,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
            + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if legacy0 then
 | 
			
		||||
        if legacy then
 | 
			
		||||
          vim.diagnostic.enable(_G.diagnostic_bufnr, _G.diagnostic_ns)
 | 
			
		||||
        else
 | 
			
		||||
          vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
 | 
			
		||||
@@ -862,7 +861,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
            + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if legacy0 then
 | 
			
		||||
        if legacy then
 | 
			
		||||
          -- Should have no effect
 | 
			
		||||
          vim.diagnostic.disable(other_bufnr, _G.other_ns)
 | 
			
		||||
        else
 | 
			
		||||
@@ -878,9 +877,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return result
 | 
			
		||||
      end, legacy)
 | 
			
		||||
 | 
			
		||||
      return result
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it('with both buffer and namespace arguments', function()
 | 
			
		||||
@@ -1052,7 +1049,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('will not cycle when wrap is off', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        vim.NIL,
 | 
			
		||||
        nil,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
 | 
			
		||||
            _G.make_error('Diagnostic #1', 1, 1, 1, 1),
 | 
			
		||||
@@ -1261,7 +1258,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('respects wrap parameter', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        vim.NIL,
 | 
			
		||||
        nil,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
 | 
			
		||||
            _G.make_error('Diagnostic #2', 4, 4, 4, 4),
 | 
			
		||||
@@ -1514,12 +1511,14 @@ describe('vim.diagnostic', function()
 | 
			
		||||
  describe('count', function()
 | 
			
		||||
    it('returns actually present severity counts', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua [[return {
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return {
 | 
			
		||||
            [vim.diagnostic.severity.ERROR] = 4,
 | 
			
		||||
            [vim.diagnostic.severity.WARN] = 3,
 | 
			
		||||
            [vim.diagnostic.severity.INFO] = 2,
 | 
			
		||||
            [vim.diagnostic.severity.HINT] = 1,
 | 
			
		||||
        }]],
 | 
			
		||||
          }
 | 
			
		||||
        end),
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
 | 
			
		||||
            _G.make_error('Error 1', 1, 1, 1, 2),
 | 
			
		||||
@@ -1537,10 +1536,12 @@ describe('vim.diagnostic', function()
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua [[return {
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return {
 | 
			
		||||
            [vim.diagnostic.severity.ERROR] = 2,
 | 
			
		||||
            [vim.diagnostic.severity.INFO] = 1,
 | 
			
		||||
        }]],
 | 
			
		||||
          }
 | 
			
		||||
        end),
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
 | 
			
		||||
            _G.make_error('Error 1', 1, 1, 1, 2),
 | 
			
		||||
@@ -1554,11 +1555,17 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('returns only requested diagnostics count when severity range is supplied', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua [[return {
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return {
 | 
			
		||||
            { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 },
 | 
			
		||||
          { [vim.diagnostic.severity.WARN] = 1,  [vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.HINT] = 1 },
 | 
			
		||||
            {
 | 
			
		||||
              [vim.diagnostic.severity.WARN] = 1,
 | 
			
		||||
              [vim.diagnostic.severity.INFO] = 1,
 | 
			
		||||
              [vim.diagnostic.severity.HINT] = 1,
 | 
			
		||||
            },
 | 
			
		||||
            { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
 | 
			
		||||
        }]],
 | 
			
		||||
          }
 | 
			
		||||
        end),
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
 | 
			
		||||
            _G.make_error('Error 1', 1, 1, 1, 5),
 | 
			
		||||
@@ -1589,11 +1596,13 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('returns only requested diagnostics when severities are supplied', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua [[return {
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return {
 | 
			
		||||
            { [vim.diagnostic.severity.WARN] = 1 },
 | 
			
		||||
            { [vim.diagnostic.severity.ERROR] = 1 },
 | 
			
		||||
            { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
 | 
			
		||||
        }]],
 | 
			
		||||
          }
 | 
			
		||||
        end),
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
 | 
			
		||||
            _G.make_error('Error 1', 1, 1, 1, 5),
 | 
			
		||||
@@ -1624,10 +1633,12 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('allows filtering by line', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua [[return {
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return {
 | 
			
		||||
            [vim.diagnostic.severity.WARN] = 1,
 | 
			
		||||
            [vim.diagnostic.severity.INFO] = 1,
 | 
			
		||||
        }]],
 | 
			
		||||
          }
 | 
			
		||||
        end),
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
 | 
			
		||||
            _G.make_error('Error 1', 1, 1, 1, 5),
 | 
			
		||||
@@ -1764,11 +1775,11 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('allows filtering by severity', function()
 | 
			
		||||
      local get_extmark_count_with_severity = function(min_severity)
 | 
			
		||||
        return exec_lua(function(min_severity0)
 | 
			
		||||
        return exec_lua(function()
 | 
			
		||||
          vim.diagnostic.config({
 | 
			
		||||
            underline = false,
 | 
			
		||||
            virtual_text = {
 | 
			
		||||
              severity = { min = min_severity0 },
 | 
			
		||||
              severity = { min = min_severity },
 | 
			
		||||
            },
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
@@ -1777,7 +1788,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
 | 
			
		||||
        end, min_severity)
 | 
			
		||||
        end)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      -- No messages with Error or higher
 | 
			
		||||
@@ -2512,7 +2523,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
      -- End position is exclusive
 | 
			
		||||
      eq(
 | 
			
		||||
        vim.NIL,
 | 
			
		||||
        nil,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          local diagnostics = {
 | 
			
		||||
            _G.make_error('Syntax error', 1, 1, 2, 0),
 | 
			
		||||
@@ -2606,7 +2617,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
      -- End position is exclusive
 | 
			
		||||
      eq(
 | 
			
		||||
        vim.NIL,
 | 
			
		||||
        nil,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          local diagnostics = {
 | 
			
		||||
            _G.make_error('Syntax error', 1, 1, 1, 3),
 | 
			
		||||
@@ -2851,10 +2862,10 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('can filter by severity', function()
 | 
			
		||||
      local count_diagnostics_with_severity = function(min_severity, max_severity)
 | 
			
		||||
        return exec_lua(function(min_severity0, max_severity0)
 | 
			
		||||
        return exec_lua(function()
 | 
			
		||||
          vim.diagnostic.config({
 | 
			
		||||
            float = {
 | 
			
		||||
              severity = { min = min_severity0, max = max_severity0 },
 | 
			
		||||
              severity = { min = min_severity, max = max_severity },
 | 
			
		||||
            },
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
@@ -2874,7 +2885,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
          local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
 | 
			
		||||
          vim.api.nvim_win_close(winnr, true)
 | 
			
		||||
          return #lines
 | 
			
		||||
        end, min_severity, max_severity)
 | 
			
		||||
        end)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      eq(2, count_diagnostics_with_severity('ERROR'))
 | 
			
		||||
@@ -3060,7 +3071,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
      -- open float failed non diagnostic lnum
 | 
			
		||||
      eq(
 | 
			
		||||
        vim.NIL,
 | 
			
		||||
        nil,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.api.nvim_win_set_cursor(0, { 1, 0 })
 | 
			
		||||
          local _, winnr = vim.diagnostic.open_float(0, { header = false })
 | 
			
		||||
@@ -3068,7 +3079,7 @@ describe('vim.diagnostic', function()
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      eq(
 | 
			
		||||
        vim.NIL,
 | 
			
		||||
        nil,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.api.nvim_win_set_cursor(0, { 1, 0 })
 | 
			
		||||
          local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
 | 
			
		||||
@@ -3180,19 +3191,19 @@ describe('vim.diagnostic', function()
 | 
			
		||||
      }
 | 
			
		||||
      eq(
 | 
			
		||||
        diagnostic,
 | 
			
		||||
        exec_lua(function(msg0)
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.diagnostic.match(
 | 
			
		||||
            msg0,
 | 
			
		||||
            msg,
 | 
			
		||||
            '^(%w+): [^:]+:(%d+):(%d+):(.+)$',
 | 
			
		||||
            { 'severity', 'lnum', 'col', 'message' }
 | 
			
		||||
          )
 | 
			
		||||
        end, msg)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('returns nil if the pattern fails to match', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        NIL,
 | 
			
		||||
        nil,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          local msg = 'The answer to life, the universe, and everything is'
 | 
			
		||||
          return vim.diagnostic.match(msg, 'This definitely will not match', {})
 | 
			
		||||
@@ -3212,15 +3223,15 @@ describe('vim.diagnostic', function()
 | 
			
		||||
      }
 | 
			
		||||
      eq(
 | 
			
		||||
        diagnostic,
 | 
			
		||||
        exec_lua(function(msg0)
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.diagnostic.match(
 | 
			
		||||
            msg0,
 | 
			
		||||
            msg,
 | 
			
		||||
            '^[^:]+:(%d+):(.+)$',
 | 
			
		||||
            { 'lnum', 'message' },
 | 
			
		||||
            nil,
 | 
			
		||||
            { severity = vim.diagnostic.severity.INFO }
 | 
			
		||||
          )
 | 
			
		||||
        end, msg)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
@@ -3236,14 +3247,14 @@ describe('vim.diagnostic', function()
 | 
			
		||||
      }
 | 
			
		||||
      eq(
 | 
			
		||||
        diagnostic,
 | 
			
		||||
        exec_lua(function(msg0)
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.diagnostic.match(
 | 
			
		||||
            msg0,
 | 
			
		||||
            msg,
 | 
			
		||||
            '^(%d+):(%w+):(.+)$',
 | 
			
		||||
            { 'lnum', 'severity', 'message' },
 | 
			
		||||
            { FATAL = vim.diagnostic.severity.ERROR }
 | 
			
		||||
          )
 | 
			
		||||
        end, msg)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ describe('ffi.cdef', function()
 | 
			
		||||
 | 
			
		||||
    eq(
 | 
			
		||||
      12,
 | 
			
		||||
      exec_lua [=[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        local ffi = require('ffi')
 | 
			
		||||
 | 
			
		||||
        ffi.cdef [[
 | 
			
		||||
@@ -27,12 +27,12 @@ describe('ffi.cdef', function()
 | 
			
		||||
        vim.cmd('set number numberwidth=4 signcolumn=yes:4')
 | 
			
		||||
 | 
			
		||||
        return ffi.C.win_col_off(ffi.C.curwin)
 | 
			
		||||
    ]=]
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    eq(
 | 
			
		||||
      20,
 | 
			
		||||
      exec_lua [=[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        local ffi = require('ffi')
 | 
			
		||||
 | 
			
		||||
        ffi.cdef [[
 | 
			
		||||
@@ -71,19 +71,19 @@ describe('ffi.cdef', function()
 | 
			
		||||
          nil,
 | 
			
		||||
          nil
 | 
			
		||||
        )
 | 
			
		||||
    ]=]
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    -- Check that extern symbols are exported and accessible
 | 
			
		||||
    eq(
 | 
			
		||||
      true,
 | 
			
		||||
      exec_lua [[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        local ffi = require('ffi')
 | 
			
		||||
 | 
			
		||||
        ffi.cdef('uint64_t display_tick;')
 | 
			
		||||
 | 
			
		||||
        return ffi.C.display_tick >= 0
 | 
			
		||||
    ]]
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
@@ -70,15 +70,15 @@ describe('vim.filetype', function()
 | 
			
		||||
 | 
			
		||||
    eq(
 | 
			
		||||
      'dosini',
 | 
			
		||||
      exec_lua(function(root0)
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.filetype.add({
 | 
			
		||||
          filename = {
 | 
			
		||||
            ['config'] = 'toml',
 | 
			
		||||
            [root0 .. '/.config/fun/config'] = 'dosini',
 | 
			
		||||
            [root .. '/.config/fun/config'] = 'dosini',
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
        return vim.filetype.match({ filename = root0 .. '/.config/fun/config' })
 | 
			
		||||
      end, root)
 | 
			
		||||
        return vim.filetype.match({ filename = root .. '/.config/fun/config' })
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
@@ -123,7 +123,7 @@ describe('vim.filetype', function()
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        -- Needs to be set so detect#sh doesn't fail
 | 
			
		||||
        vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$'
 | 
			
		||||
        return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } })
 | 
			
		||||
        return (vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }))
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
  end)
 | 
			
		||||
@@ -152,7 +152,12 @@ describe('vim.filetype', function()
 | 
			
		||||
      xml = { formatexpr = 'xmlformat#Format()' },
 | 
			
		||||
    } do
 | 
			
		||||
      for option, value in pairs(opts) do
 | 
			
		||||
        eq(value, exec_lua([[ return vim.filetype.get_option(...) ]], ft, option))
 | 
			
		||||
        eq(
 | 
			
		||||
          value,
 | 
			
		||||
          exec_lua(function()
 | 
			
		||||
            return vim.filetype.get_option(ft, option)
 | 
			
		||||
          end)
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -141,14 +141,14 @@ describe('vim.fs', function()
 | 
			
		||||
    it('works', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        true,
 | 
			
		||||
        exec_lua(function(dir, nvim)
 | 
			
		||||
          for name, type in vim.fs.dir(dir) do
 | 
			
		||||
            if name == nvim and type == 'file' then
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          for name, type in vim.fs.dir(nvim_dir) do
 | 
			
		||||
            if name == nvim_prog_basename and type == 'file' then
 | 
			
		||||
              return true
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
          return false
 | 
			
		||||
        end, nvim_dir, nvim_prog_basename)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
@@ -167,22 +167,21 @@ describe('vim.fs', function()
 | 
			
		||||
      io.open('testd/a/b/c/c4', 'w'):close()
 | 
			
		||||
 | 
			
		||||
      local function run(dir, depth, skip)
 | 
			
		||||
        local r = exec_lua(function(dir0, depth0, skip0)
 | 
			
		||||
        return exec_lua(function()
 | 
			
		||||
          local r = {}
 | 
			
		||||
          local skip_f
 | 
			
		||||
          if skip0 then
 | 
			
		||||
          if skip then
 | 
			
		||||
            skip_f = function(n0)
 | 
			
		||||
              if vim.tbl_contains(skip0 or {}, n0) then
 | 
			
		||||
              if vim.tbl_contains(skip or {}, n0) then
 | 
			
		||||
                return false
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
          for name, type_ in vim.fs.dir(dir0, { depth = depth0, skip = skip_f }) do
 | 
			
		||||
          for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f }) do
 | 
			
		||||
            r[name] = type_
 | 
			
		||||
          end
 | 
			
		||||
          return r
 | 
			
		||||
        end, dir, depth, skip)
 | 
			
		||||
        return r
 | 
			
		||||
        end)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      local exp = {}
 | 
			
		||||
@@ -252,9 +251,12 @@ describe('vim.fs', function()
 | 
			
		||||
 | 
			
		||||
      opts = { path = test_source_path .. '/contrib', limit = math.huge }
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua(function(dir)
 | 
			
		||||
          return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir .. '/contrib/*', false, true))
 | 
			
		||||
        end, test_source_path),
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.tbl_map(
 | 
			
		||||
            vim.fs.basename,
 | 
			
		||||
            vim.fn.glob(test_source_path .. '/contrib/*', false, true)
 | 
			
		||||
          )
 | 
			
		||||
        end),
 | 
			
		||||
        vim.tbl_map(
 | 
			
		||||
          vim.fs.basename,
 | 
			
		||||
          vim.fs.find(function(_, d)
 | 
			
		||||
@@ -337,10 +339,10 @@ describe('vim.fs', function()
 | 
			
		||||
      local xdg_config_home = test_build_dir .. '/.config'
 | 
			
		||||
      eq(
 | 
			
		||||
        xdg_config_home .. '/nvim',
 | 
			
		||||
        exec_lua(function(...)
 | 
			
		||||
          vim.env.XDG_CONFIG_HOME = ...
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.env.XDG_CONFIG_HOME = xdg_config_home
 | 
			
		||||
          return vim.fs.normalize('$XDG_CONFIG_HOME/nvim')
 | 
			
		||||
        end, xdg_config_home)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,16 +2,15 @@ local t = require('test.testutil')
 | 
			
		||||
local n = require('test.functional.testnvim')()
 | 
			
		||||
 | 
			
		||||
local eq = t.eq
 | 
			
		||||
local exec_lua = n.exec_lua
 | 
			
		||||
 | 
			
		||||
describe('glob', function()
 | 
			
		||||
  before_each(n.clear)
 | 
			
		||||
  after_each(n.clear)
 | 
			
		||||
 | 
			
		||||
  local match = function(...)
 | 
			
		||||
    return exec_lua(function(pattern, str)
 | 
			
		||||
  local match = function(pattern, str)
 | 
			
		||||
    return n.exec_lua(function()
 | 
			
		||||
      return require('vim.glob').to_lpeg(pattern):match(str) ~= nil
 | 
			
		||||
    end, ...)
 | 
			
		||||
    end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe('glob matching', function()
 | 
			
		||||
 
 | 
			
		||||
@@ -31,10 +31,10 @@ describe('vim.highlight.range', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('works with charwise selection', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local ns = vim.api.nvim_create_namespace('')
 | 
			
		||||
      vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 })
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^asdfghjkl{1:$}                                                  |
 | 
			
		||||
      «口{10:=口»}{100:$}                                                    |
 | 
			
		||||
@@ -46,10 +46,10 @@ describe('vim.highlight.range', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('works with linewise selection', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local ns = vim.api.nvim_create_namespace('')
 | 
			
		||||
      vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' })
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      {10:^asdfghjkl}{100:$}                                                  |
 | 
			
		||||
      {10:«口=口»}{100:$}                                                    |
 | 
			
		||||
@@ -61,10 +61,10 @@ describe('vim.highlight.range', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('works with blockwise selection', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local ns = vim.api.nvim_create_namespace('')
 | 
			
		||||
      vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' })
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      {10:^asdf}ghjkl{1:$}                                                  |
 | 
			
		||||
      {10:«口=}口»{1:$}                                                    |
 | 
			
		||||
@@ -76,10 +76,10 @@ describe('vim.highlight.range', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('works with blockwise selection with width', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local ns = vim.api.nvim_create_namespace('')
 | 
			
		||||
      vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' })
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^asdf{10:ghjkl}{1:$}                                                  |
 | 
			
		||||
      «口={10:口»}{1:$}                                                    |
 | 
			
		||||
@@ -91,11 +91,11 @@ describe('vim.highlight.range', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('can use -1 or v:maxcol to indicate end of line', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local ns = vim.api.nvim_create_namespace('')
 | 
			
		||||
      vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {})
 | 
			
		||||
      vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {})
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^asdf{10:ghjkl}{100:$}                                                  |
 | 
			
		||||
      {10:«口=口»}{100:$}                                                    |
 | 
			
		||||
@@ -114,33 +114,37 @@ describe('vim.highlight.on_yank', function()
 | 
			
		||||
 | 
			
		||||
  it('does not show errors even if buffer is wiped before timeout', function()
 | 
			
		||||
    command('new')
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}})
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.highlight.on_yank({
 | 
			
		||||
        timeout = 10,
 | 
			
		||||
        on_macro = true,
 | 
			
		||||
        event = { operator = 'y', regtype = 'v' },
 | 
			
		||||
      })
 | 
			
		||||
      vim.cmd('bwipeout!')
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    vim.uv.sleep(10)
 | 
			
		||||
    n.feed('<cr>') -- avoid hang if error message exists
 | 
			
		||||
    eq('', eval('v:errmsg'))
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('does not close timer twice', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}})
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } })
 | 
			
		||||
      vim.uv.sleep(10)
 | 
			
		||||
      vim.schedule(function()
 | 
			
		||||
        vim.highlight.on_yank({timeout = 0, on_macro = true, event = {operator = "y"}})
 | 
			
		||||
        vim.highlight.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
 | 
			
		||||
      end)
 | 
			
		||||
    end)
 | 
			
		||||
    ]])
 | 
			
		||||
    eq('', eval('v:errmsg'))
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('does not show in another window', function()
 | 
			
		||||
    command('vsplit')
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0,"[",1,1,{})
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0,"]",1,1,{})
 | 
			
		||||
      vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
 | 
			
		||||
    ]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
 | 
			
		||||
      vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
 | 
			
		||||
    end)
 | 
			
		||||
    local ns = api.nvim_create_namespace('hlyank')
 | 
			
		||||
    local win = api.nvim_get_current_win()
 | 
			
		||||
    eq({ win }, api.nvim__ns_get(ns).wins)
 | 
			
		||||
@@ -150,19 +154,19 @@ describe('vim.highlight.on_yank', function()
 | 
			
		||||
 | 
			
		||||
  it('removes old highlight if new one is created before old one times out', function()
 | 
			
		||||
    command('vnew')
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0,"[",1,1,{})
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0,"]",1,1,{})
 | 
			
		||||
      vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
 | 
			
		||||
    ]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
 | 
			
		||||
      vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
 | 
			
		||||
    end)
 | 
			
		||||
    local ns = api.nvim_create_namespace('hlyank')
 | 
			
		||||
    eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1])
 | 
			
		||||
    command('wincmd w')
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0,"[",1,1,{})
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0,"]",1,1,{})
 | 
			
		||||
      vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
 | 
			
		||||
    ]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
 | 
			
		||||
      vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
 | 
			
		||||
      vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
 | 
			
		||||
    end)
 | 
			
		||||
    local win = api.nvim_get_current_win()
 | 
			
		||||
    eq({ win }, api.nvim__ns_get(ns).wins)
 | 
			
		||||
    command('wincmd w')
 | 
			
		||||
 
 | 
			
		||||
@@ -12,22 +12,21 @@ describe('vim.inspect_pos', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('it returns items', function()
 | 
			
		||||
    local ret = exec_lua([[
 | 
			
		||||
    local buf, items, other_buf_syntax = exec_lua(function()
 | 
			
		||||
      local buf = vim.api.nvim_create_buf(true, false)
 | 
			
		||||
      local buf1 = vim.api.nvim_create_buf(true, false)
 | 
			
		||||
      local ns1 = vim.api.nvim_create_namespace("ns1")
 | 
			
		||||
      local ns2 = vim.api.nvim_create_namespace("")
 | 
			
		||||
      local ns1 = vim.api.nvim_create_namespace('ns1')
 | 
			
		||||
      local ns2 = vim.api.nvim_create_namespace('')
 | 
			
		||||
      vim.api.nvim_set_current_buf(buf)
 | 
			
		||||
      vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"})
 | 
			
		||||
      vim.api.nvim_buf_set_lines(buf1, 0, -1, false, {"--commentline"})
 | 
			
		||||
      vim.api.nvim_buf_set_lines(0, 0, -1, false, { 'local a = 123' })
 | 
			
		||||
      vim.api.nvim_buf_set_lines(buf1, 0, -1, false, { '--commentline' })
 | 
			
		||||
      vim.bo[buf].filetype = 'lua'
 | 
			
		||||
      vim.bo[buf1].filetype = 'lua'
 | 
			
		||||
      vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = "Normal" })
 | 
			
		||||
      vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" })
 | 
			
		||||
      vim.cmd("syntax on")
 | 
			
		||||
      return {buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax }
 | 
			
		||||
    ]])
 | 
			
		||||
    local buf, items, other_buf_syntax = unpack(ret)
 | 
			
		||||
      vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = 'Normal' })
 | 
			
		||||
      vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = 'Normal' })
 | 
			
		||||
      vim.cmd('syntax on')
 | 
			
		||||
      return buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq('', eval('v:errmsg'))
 | 
			
		||||
    eq({
 | 
			
		||||
@@ -95,14 +94,14 @@ describe('vim.show_pos', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('it does not error', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local buf = vim.api.nvim_create_buf(true, false)
 | 
			
		||||
      vim.api.nvim_set_current_buf(buf)
 | 
			
		||||
      vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"})
 | 
			
		||||
      vim.api.nvim_buf_set_lines(0, 0, -1, false, { 'local a = 123' })
 | 
			
		||||
      vim.bo[buf].filetype = 'lua'
 | 
			
		||||
      vim.cmd("syntax on")
 | 
			
		||||
      vim.cmd('syntax on')
 | 
			
		||||
      return { buf, vim.show_pos(0, 0, 10) }
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    eq('', eval('v:errmsg'))
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,10 @@ describe('vim.loader', function()
 | 
			
		||||
 | 
			
		||||
  it('can work in compatibility with --luamod-dev #27413', function()
 | 
			
		||||
    clear({ args = { '--luamod-dev' } })
 | 
			
		||||
    exec_lua [[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.loader.enable()
 | 
			
		||||
 | 
			
		||||
      require("vim.fs")
 | 
			
		||||
      require('vim.fs')
 | 
			
		||||
 | 
			
		||||
      -- try to load other vim submodules as well (Nvim Lua stdlib)
 | 
			
		||||
      for key, _ in pairs(vim._submodules) do
 | 
			
		||||
@@ -28,28 +28,25 @@ describe('vim.loader', function()
 | 
			
		||||
          ('%s != require("%s"), %s != %s'):format(modname, modname, tostring(lhs), tostring(rhs))
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
    ]]
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('handles changing files (#23027)', function()
 | 
			
		||||
    exec_lua [[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.loader.enable()
 | 
			
		||||
    ]]
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    local tmp = t.tmpname()
 | 
			
		||||
    command('edit ' .. tmp)
 | 
			
		||||
 | 
			
		||||
    eq(
 | 
			
		||||
      1,
 | 
			
		||||
      exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=1' })
 | 
			
		||||
        vim.cmd.write()
 | 
			
		||||
      loadfile(...)()
 | 
			
		||||
        loadfile(tmp)()
 | 
			
		||||
        return _G.TEST
 | 
			
		||||
    ]],
 | 
			
		||||
        tmp
 | 
			
		||||
      )
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    -- fs latency
 | 
			
		||||
@@ -57,15 +54,12 @@ describe('vim.loader', function()
 | 
			
		||||
 | 
			
		||||
    eq(
 | 
			
		||||
      2,
 | 
			
		||||
      exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=2' })
 | 
			
		||||
        vim.cmd.write()
 | 
			
		||||
      loadfile(...)()
 | 
			
		||||
        loadfile(tmp)()
 | 
			
		||||
        return _G.TEST
 | 
			
		||||
    ]],
 | 
			
		||||
        tmp
 | 
			
		||||
      )
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,20 +25,24 @@ describe('vim.uv', function()
 | 
			
		||||
  it('timer', function()
 | 
			
		||||
    exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {})
 | 
			
		||||
 | 
			
		||||
    local code = [[
 | 
			
		||||
    local code = function()
 | 
			
		||||
      local touch = 0
 | 
			
		||||
      local function wait(ms)
 | 
			
		||||
        local this = coroutine.running()
 | 
			
		||||
        assert(this)
 | 
			
		||||
        local timer = vim.uv.new_timer()
 | 
			
		||||
        timer:start(ms, 0, vim.schedule_wrap(function ()
 | 
			
		||||
        local timer = assert(vim.uv.new_timer())
 | 
			
		||||
        timer:start(
 | 
			
		||||
          ms,
 | 
			
		||||
          0,
 | 
			
		||||
          vim.schedule_wrap(function()
 | 
			
		||||
            timer:close()
 | 
			
		||||
            touch = touch + 1
 | 
			
		||||
            coroutine.resume(this)
 | 
			
		||||
            touch = touch + 1
 | 
			
		||||
            assert(touch == 3)
 | 
			
		||||
          vim.api.nvim_set_var("coroutine_cnt_1", touch)
 | 
			
		||||
        end))
 | 
			
		||||
            vim.api.nvim_set_var('coroutine_cnt_1', touch)
 | 
			
		||||
          end)
 | 
			
		||||
        )
 | 
			
		||||
        coroutine.yield()
 | 
			
		||||
        touch = touch + 1
 | 
			
		||||
        return touch
 | 
			
		||||
@@ -46,9 +50,9 @@ describe('vim.uv', function()
 | 
			
		||||
      coroutine.wrap(function()
 | 
			
		||||
        local touched = wait(10)
 | 
			
		||||
        assert(touched == touch)
 | 
			
		||||
        vim.api.nvim_set_var("coroutine_cnt", touched)
 | 
			
		||||
        vim.api.nvim_set_var('coroutine_cnt', touched)
 | 
			
		||||
      end)()
 | 
			
		||||
    ]]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    eq(0, api.nvim_get_var('coroutine_cnt'))
 | 
			
		||||
    exec_lua(code)
 | 
			
		||||
@@ -99,15 +103,19 @@ describe('vim.uv', function()
 | 
			
		||||
 | 
			
		||||
    -- callbacks can be scheduled to be executed in the main event loop
 | 
			
		||||
    -- where the entire API is available
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      local timer = vim.uv.new_timer()
 | 
			
		||||
      timer:start(20, 0, vim.schedule_wrap(function ()
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local timer = assert(vim.uv.new_timer())
 | 
			
		||||
      timer:start(
 | 
			
		||||
        20,
 | 
			
		||||
        0,
 | 
			
		||||
        vim.schedule_wrap(function()
 | 
			
		||||
          _G.is_fast = vim.in_fast_event()
 | 
			
		||||
          timer:close()
 | 
			
		||||
        vim.api.nvim_set_var("valid", true)
 | 
			
		||||
          vim.api.nvim_set_var('valid', true)
 | 
			
		||||
          vim.api.nvim_command("echomsg 'howdy'")
 | 
			
		||||
      end))
 | 
			
		||||
    ]])
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^                                                  |
 | 
			
		||||
@@ -118,15 +126,15 @@ describe('vim.uv', function()
 | 
			
		||||
    eq(false, exec_lua('return _G.is_fast'))
 | 
			
		||||
 | 
			
		||||
    -- fast (not deferred) API functions are allowed to be called directly
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      local timer = vim.uv.new_timer()
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local timer = assert(vim.uv.new_timer())
 | 
			
		||||
      timer:start(20, 0, function()
 | 
			
		||||
        timer:close()
 | 
			
		||||
        -- input is queued for processing after the callback returns
 | 
			
		||||
        vim.api.nvim_input("isneaky")
 | 
			
		||||
        vim.api.nvim_input('isneaky')
 | 
			
		||||
        _G.mode = vim.api.nvim_get_mode()
 | 
			
		||||
      end)
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      sneaky^                                            |
 | 
			
		||||
      {1:~                                                 }|*8
 | 
			
		||||
@@ -134,15 +142,15 @@ describe('vim.uv', function()
 | 
			
		||||
    ]])
 | 
			
		||||
    eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode'))
 | 
			
		||||
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      local timer = vim.uv.new_timer()
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local timer = assert(vim.uv.new_timer())
 | 
			
		||||
      timer:start(20, 0, function()
 | 
			
		||||
        _G.is_fast = vim.in_fast_event()
 | 
			
		||||
        timer:close()
 | 
			
		||||
        _G.value = vim.fn.has("nvim-0.5")
 | 
			
		||||
        _G.unvalue = vim.fn.has("python3")
 | 
			
		||||
        _G.value = vim.fn.has('nvim-0.5')
 | 
			
		||||
        _G.unvalue = vim.fn.has('python3')
 | 
			
		||||
      end)
 | 
			
		||||
    end)
 | 
			
		||||
    ]])
 | 
			
		||||
 | 
			
		||||
    screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] })
 | 
			
		||||
    feed('<cr>')
 | 
			
		||||
 
 | 
			
		||||
@@ -11,20 +11,20 @@ describe('lua vim.mpack', function()
 | 
			
		||||
  it('encodes vim.NIL', function()
 | 
			
		||||
    eq(
 | 
			
		||||
      { true, true, true, true },
 | 
			
		||||
      exec_lua [[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        local var = vim.mpack.decode(vim.mpack.encode({ 33, vim.NIL, 77 }))
 | 
			
		||||
        return { var[1] == 33, var[2] == vim.NIL, var[3] == 77, var[4] == nil }
 | 
			
		||||
    ]]
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('encodes vim.empty_dict()', function()
 | 
			
		||||
    eq(
 | 
			
		||||
      { { {}, 'foo', {} }, true, false },
 | 
			
		||||
      exec_lua [[
 | 
			
		||||
      local var = vim.mpack.decode(vim.mpack.encode({{}, "foo", vim.empty_dict()}))
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        local var = vim.mpack.decode(vim.mpack.encode({ {}, 'foo', vim.empty_dict() }))
 | 
			
		||||
        return { var, vim.islist(var[1]), vim.islist(var[3]) }
 | 
			
		||||
    ]]
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
@@ -134,14 +134,12 @@ describe('print', function()
 | 
			
		||||
    eq('abc  def', exec_capture('lua print("abc", "", "def")'))
 | 
			
		||||
  end)
 | 
			
		||||
  it('defers printing in luv event handlers', function()
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      local cmd = ...
 | 
			
		||||
    exec_lua(function(cmd)
 | 
			
		||||
      function test()
 | 
			
		||||
        local timer = vim.uv.new_timer()
 | 
			
		||||
        local done = false
 | 
			
		||||
        timer:start(10, 0, function()
 | 
			
		||||
          print("very fast")
 | 
			
		||||
          print('very fast')
 | 
			
		||||
          timer:close()
 | 
			
		||||
          done = true
 | 
			
		||||
        end)
 | 
			
		||||
@@ -149,14 +147,12 @@ describe('print', function()
 | 
			
		||||
        -- loop until we know for sure the callback has been executed
 | 
			
		||||
        while not done do
 | 
			
		||||
          os.execute(cmd)
 | 
			
		||||
          vim.uv.run("nowait") -- fake os_breakcheck()
 | 
			
		||||
          vim.uv.run('nowait') -- fake os_breakcheck()
 | 
			
		||||
        end
 | 
			
		||||
        print("very slow")
 | 
			
		||||
        vim.api.nvim_command("sleep 1m") -- force deferred event processing
 | 
			
		||||
        print('very slow')
 | 
			
		||||
        vim.api.nvim_command('sleep 1m') -- force deferred event processing
 | 
			
		||||
      end
 | 
			
		||||
    ]],
 | 
			
		||||
      (is_os('win') and 'timeout 1') or 'sleep 0.1'
 | 
			
		||||
    )
 | 
			
		||||
    end, (is_os('win') and 'timeout 1') or 'sleep 0.1')
 | 
			
		||||
    eq('very slow\nvery fast', exec_capture('lua test()'))
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,10 +6,8 @@ local exec_lua = n.exec_lua
 | 
			
		||||
local eq = t.eq
 | 
			
		||||
 | 
			
		||||
local function system_sync(cmd, opts)
 | 
			
		||||
  return exec_lua(
 | 
			
		||||
    [[
 | 
			
		||||
    local cmd, opts = ...
 | 
			
		||||
    local obj = vim.system(...)
 | 
			
		||||
  return exec_lua(function()
 | 
			
		||||
    local obj = vim.system(cmd, opts)
 | 
			
		||||
 | 
			
		||||
    if opts.timeout then
 | 
			
		||||
      -- Minor delay before calling wait() so the timeout uv timer can have a headstart over the
 | 
			
		||||
@@ -24,16 +22,11 @@ local function system_sync(cmd, opts)
 | 
			
		||||
    assert(not proc, 'process still exists')
 | 
			
		||||
 | 
			
		||||
    return res
 | 
			
		||||
  ]],
 | 
			
		||||
    cmd,
 | 
			
		||||
    opts
 | 
			
		||||
  )
 | 
			
		||||
  end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function system_async(cmd, opts)
 | 
			
		||||
  return exec_lua(
 | 
			
		||||
    [[
 | 
			
		||||
    local cmd, opts = ...
 | 
			
		||||
  return exec_lua(function()
 | 
			
		||||
    _G.done = false
 | 
			
		||||
    local obj = vim.system(cmd, opts, function(obj)
 | 
			
		||||
      _G.done = true
 | 
			
		||||
@@ -51,10 +44,7 @@ local function system_async(cmd, opts)
 | 
			
		||||
    assert(not proc, 'process still exists')
 | 
			
		||||
 | 
			
		||||
    return _G.ret
 | 
			
		||||
  ]],
 | 
			
		||||
    cmd,
 | 
			
		||||
    opts
 | 
			
		||||
  )
 | 
			
		||||
  end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe('vim.system', function()
 | 
			
		||||
@@ -84,7 +74,7 @@ describe('vim.system', function()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it('kill processes', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local signal
 | 
			
		||||
      local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r)
 | 
			
		||||
        signal = r.signal
 | 
			
		||||
@@ -104,19 +94,21 @@ describe('vim.system', function()
 | 
			
		||||
      assert(not proc, 'process still exists')
 | 
			
		||||
 | 
			
		||||
      assert(signal == 2)
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('SystemObj:wait() does not process non-fast events #27292', function()
 | 
			
		||||
    eq(
 | 
			
		||||
      false,
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        _G.processed = false
 | 
			
		||||
        local cmd = vim.system({ 'sleep', '1' })
 | 
			
		||||
        vim.schedule(function() _G.processed = true end)
 | 
			
		||||
        vim.schedule(function()
 | 
			
		||||
          _G.processed = true
 | 
			
		||||
        end)
 | 
			
		||||
        cmd:wait()
 | 
			
		||||
        return _G.processed
 | 
			
		||||
      ]])
 | 
			
		||||
      end)
 | 
			
		||||
    )
 | 
			
		||||
    eq(true, exec_lua([[return _G.processed]]))
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ local eq = t.eq
 | 
			
		||||
local pathsep = n.get_pathsep()
 | 
			
		||||
local fn = n.fn
 | 
			
		||||
local api = n.api
 | 
			
		||||
local exec_lua = n.exec_lua
 | 
			
		||||
 | 
			
		||||
local testdir = 'Xtest-editorconfig'
 | 
			
		||||
 | 
			
		||||
@@ -227,12 +226,12 @@ But not this one
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('does not operate on invalid buffers', function()
 | 
			
		||||
    local ok, err = unpack(exec_lua([[
 | 
			
		||||
    local ok, err = unpack(n.exec_lua(function()
 | 
			
		||||
      vim.cmd.edit('test.txt')
 | 
			
		||||
      local bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
      vim.cmd.bwipeout(bufnr)
 | 
			
		||||
      return { pcall(require('editorconfig').config, bufnr) }
 | 
			
		||||
    ]]))
 | 
			
		||||
    end))
 | 
			
		||||
 | 
			
		||||
    eq(true, ok, err)
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -13,36 +13,34 @@ describe('vim.lsp.codelens', function()
 | 
			
		||||
 | 
			
		||||
  it('on_codelens_stores_and_displays_lenses', function()
 | 
			
		||||
    local fake_uri = 'file:///fake/uri'
 | 
			
		||||
    local bufnr = exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      fake_uri = ...
 | 
			
		||||
    local bufnr = exec_lua(function()
 | 
			
		||||
      local bufnr = vim.uri_to_bufnr(fake_uri)
 | 
			
		||||
      local lines = { 'So', 'many', 'lines' }
 | 
			
		||||
      vim.fn.bufload(bufnr)
 | 
			
		||||
      vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
 | 
			
		||||
      return bufnr
 | 
			
		||||
    ]],
 | 
			
		||||
      fake_uri
 | 
			
		||||
    )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      local bufnr = ...
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local lenses = {
 | 
			
		||||
        {
 | 
			
		||||
          range = {
 | 
			
		||||
            start = { line = 0, character = 0, },
 | 
			
		||||
            ['end'] = { line = 0, character = 0 }
 | 
			
		||||
            start = { line = 0, character = 0 },
 | 
			
		||||
            ['end'] = { line = 0, character = 0 },
 | 
			
		||||
          },
 | 
			
		||||
          command = { title = 'Lens1', command = 'Dummy' }
 | 
			
		||||
          command = { title = 'Lens1', command = 'Dummy' },
 | 
			
		||||
        },
 | 
			
		||||
      }
 | 
			
		||||
      vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
 | 
			
		||||
    ]],
 | 
			
		||||
      bufnr
 | 
			
		||||
      vim.lsp.codelens.on_codelens(
 | 
			
		||||
        nil,
 | 
			
		||||
        lenses,
 | 
			
		||||
        { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
 | 
			
		||||
    local stored_lenses = exec_lua(function()
 | 
			
		||||
      return vim.lsp.codelens.get(bufnr)
 | 
			
		||||
    end)
 | 
			
		||||
    local expected = {
 | 
			
		||||
      {
 | 
			
		||||
        range = {
 | 
			
		||||
@@ -57,58 +55,54 @@ describe('vim.lsp.codelens', function()
 | 
			
		||||
    }
 | 
			
		||||
    eq(expected, stored_lenses)
 | 
			
		||||
 | 
			
		||||
    local virtual_text_chunks = exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      local bufnr = ...
 | 
			
		||||
    local virtual_text_chunks = exec_lua(function()
 | 
			
		||||
      local ns = vim.lsp.codelens.__namespaces[1]
 | 
			
		||||
      local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {})
 | 
			
		||||
      return vim.api.nvim_buf_get_extmark_by_id(bufnr, ns, extmarks[1][1], { details = true })[3].virt_text
 | 
			
		||||
    ]],
 | 
			
		||||
      bufnr
 | 
			
		||||
    )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq({ [1] = { 'Lens1', 'LspCodeLens' } }, virtual_text_chunks)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('can clear all lens', function()
 | 
			
		||||
    local fake_uri = 'file:///fake/uri'
 | 
			
		||||
    local bufnr = exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      fake_uri = ...
 | 
			
		||||
    local bufnr = exec_lua(function()
 | 
			
		||||
      local bufnr = vim.uri_to_bufnr(fake_uri)
 | 
			
		||||
      local lines = { 'So', 'many', 'lines' }
 | 
			
		||||
      vim.fn.bufload(bufnr)
 | 
			
		||||
      vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
 | 
			
		||||
      return bufnr
 | 
			
		||||
    ]],
 | 
			
		||||
      fake_uri
 | 
			
		||||
    )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      local bufnr = ...
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local lenses = {
 | 
			
		||||
        {
 | 
			
		||||
          range = {
 | 
			
		||||
            start = { line = 0, character = 0, },
 | 
			
		||||
            ['end'] = { line = 0, character = 0 }
 | 
			
		||||
            start = { line = 0, character = 0 },
 | 
			
		||||
            ['end'] = { line = 0, character = 0 },
 | 
			
		||||
          },
 | 
			
		||||
          command = { title = 'Lens1', command = 'Dummy' }
 | 
			
		||||
          command = { title = 'Lens1', command = 'Dummy' },
 | 
			
		||||
        },
 | 
			
		||||
      }
 | 
			
		||||
      vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
 | 
			
		||||
    ]],
 | 
			
		||||
      bufnr
 | 
			
		||||
      vim.lsp.codelens.on_codelens(
 | 
			
		||||
        nil,
 | 
			
		||||
        lenses,
 | 
			
		||||
        { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
 | 
			
		||||
    local stored_lenses = exec_lua(function()
 | 
			
		||||
      return vim.lsp.codelens.get(bufnr)
 | 
			
		||||
    end)
 | 
			
		||||
    eq(1, #stored_lenses)
 | 
			
		||||
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.lsp.codelens.clear()
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
 | 
			
		||||
    stored_lenses = exec_lua(function()
 | 
			
		||||
      return vim.lsp.codelens.get(bufnr)
 | 
			
		||||
    end)
 | 
			
		||||
    eq(0, #stored_lenses)
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,10 @@ local function complete(line, candidates, lnum, server_boundary)
 | 
			
		||||
  -- nvim_win_get_cursor returns 0 based column, line:find returns 1 based
 | 
			
		||||
  local cursor_col = line:find('|') - 1
 | 
			
		||||
  line = line:gsub('|', '')
 | 
			
		||||
  return exec_lua(
 | 
			
		||||
    [[
 | 
			
		||||
    local line, cursor_col, lnum, result, server_boundary = ...
 | 
			
		||||
  return exec_lua(function(result)
 | 
			
		||||
    local line_to_cursor = line:sub(1, cursor_col)
 | 
			
		||||
    local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$')
 | 
			
		||||
    local items, new_server_boundary = require("vim.lsp.completion")._convert_results(
 | 
			
		||||
    local items, new_server_boundary = require('vim.lsp.completion')._convert_results(
 | 
			
		||||
      line,
 | 
			
		||||
      lnum,
 | 
			
		||||
      cursor_col,
 | 
			
		||||
@@ -36,19 +34,13 @@ local function complete(line, candidates, lnum, server_boundary)
 | 
			
		||||
      client_start_boundary,
 | 
			
		||||
      server_boundary,
 | 
			
		||||
      result,
 | 
			
		||||
      "utf-16"
 | 
			
		||||
      'utf-16'
 | 
			
		||||
    )
 | 
			
		||||
    return {
 | 
			
		||||
      items = items,
 | 
			
		||||
      server_start_boundary = new_server_boundary
 | 
			
		||||
      server_start_boundary = new_server_boundary,
 | 
			
		||||
    }
 | 
			
		||||
  ]],
 | 
			
		||||
    line,
 | 
			
		||||
    cursor_col,
 | 
			
		||||
    lnum,
 | 
			
		||||
    candidates,
 | 
			
		||||
    server_boundary
 | 
			
		||||
  )
 | 
			
		||||
  end, candidates)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe('vim.lsp.completion: item conversion', function()
 | 
			
		||||
@@ -483,13 +475,14 @@ describe('vim.lsp.completion: protocol', function()
 | 
			
		||||
  before_each(function()
 | 
			
		||||
    clear()
 | 
			
		||||
    exec_lua(create_server_definition)
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      _G.capture = {}
 | 
			
		||||
      --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
      vim.fn.complete = function(col, matches)
 | 
			
		||||
        _G.capture.col = col
 | 
			
		||||
        _G.capture.matches = matches
 | 
			
		||||
      end
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  after_each(clear)
 | 
			
		||||
@@ -497,32 +490,34 @@ describe('vim.lsp.completion: protocol', function()
 | 
			
		||||
  --- @param completion_result lsp.CompletionList
 | 
			
		||||
  --- @return integer
 | 
			
		||||
  local function create_server(completion_result)
 | 
			
		||||
    return exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      local result = ...
 | 
			
		||||
      local server = _create_server({
 | 
			
		||||
    return exec_lua(function()
 | 
			
		||||
      local server = _G._create_server({
 | 
			
		||||
        capabilities = {
 | 
			
		||||
          completionProvider = {
 | 
			
		||||
            triggerCharacters = { '.' }
 | 
			
		||||
          }
 | 
			
		||||
            triggerCharacters = { '.' },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        handlers = {
 | 
			
		||||
          ['textDocument/completion'] = function(_, _, callback)
 | 
			
		||||
            callback(nil, result)
 | 
			
		||||
          end
 | 
			
		||||
        }
 | 
			
		||||
            callback(nil, completion_result)
 | 
			
		||||
          end,
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
      local bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
      vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
      return vim.lsp.start({ name = 'dummy', cmd = server.cmd, on_attach = function(client, bufnr)
 | 
			
		||||
        vim.lsp.completion.enable(true, client.id, bufnr, { convert = function(item)
 | 
			
		||||
      return vim.lsp.start({
 | 
			
		||||
        name = 'dummy',
 | 
			
		||||
        cmd = server.cmd,
 | 
			
		||||
        on_attach = function(client, bufnr0)
 | 
			
		||||
          vim.lsp.completion.enable(true, client.id, bufnr0, {
 | 
			
		||||
            convert = function(item)
 | 
			
		||||
              return { abbr = item.label:gsub('%b()', '') }
 | 
			
		||||
        end})
 | 
			
		||||
      end})
 | 
			
		||||
    ]],
 | 
			
		||||
      completion_result
 | 
			
		||||
    )
 | 
			
		||||
            end,
 | 
			
		||||
          })
 | 
			
		||||
        end,
 | 
			
		||||
      })
 | 
			
		||||
    end)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  local function assert_matches(fn)
 | 
			
		||||
@@ -533,14 +528,11 @@ describe('vim.lsp.completion: protocol', function()
 | 
			
		||||
 | 
			
		||||
  --- @param pos [integer, integer]
 | 
			
		||||
  local function trigger_at_pos(pos)
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local win = vim.api.nvim_get_current_win()
 | 
			
		||||
      vim.api.nvim_win_set_cursor(win, ...)
 | 
			
		||||
      vim.api.nvim_win_set_cursor(win, pos)
 | 
			
		||||
      vim.lsp.completion.trigger()
 | 
			
		||||
    ]],
 | 
			
		||||
      pos
 | 
			
		||||
    )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    retry(nil, nil, function()
 | 
			
		||||
      neq(nil, exec_lua('return _G.capture.col'))
 | 
			
		||||
@@ -683,37 +675,30 @@ describe('vim.lsp.completion: protocol', function()
 | 
			
		||||
    }
 | 
			
		||||
    local client_id = create_server(completion_list)
 | 
			
		||||
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      _G.called = false
 | 
			
		||||
      local client = vim.lsp.get_client_by_id(...)
 | 
			
		||||
      local client = assert(vim.lsp.get_client_by_id(client_id))
 | 
			
		||||
      client.commands.dummy = function()
 | 
			
		||||
        _G.called = true
 | 
			
		||||
      end
 | 
			
		||||
    ]],
 | 
			
		||||
      client_id
 | 
			
		||||
    )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    feed('ih')
 | 
			
		||||
    trigger_at_pos({ 1, 1 })
 | 
			
		||||
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      local client_id, item = ...
 | 
			
		||||
    local item = completion_list.items[1]
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.v.completed_item = {
 | 
			
		||||
        user_data = {
 | 
			
		||||
          nvim = {
 | 
			
		||||
            lsp = {
 | 
			
		||||
              client_id = client_id,
 | 
			
		||||
              completion_item = item
 | 
			
		||||
              completion_item = item,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    ]],
 | 
			
		||||
      client_id,
 | 
			
		||||
      completion_list.items[1]
 | 
			
		||||
    )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    feed('<C-x><C-o><C-y>')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,9 @@ local neq = t.neq
 | 
			
		||||
local create_server_definition = t_lsp.create_server_definition
 | 
			
		||||
 | 
			
		||||
describe('vim.lsp.diagnostic', function()
 | 
			
		||||
  local fake_uri
 | 
			
		||||
  local fake_uri --- @type string
 | 
			
		||||
  local client_id --- @type integer
 | 
			
		||||
  local diagnostic_bufnr --- @type integer
 | 
			
		||||
 | 
			
		||||
  before_each(function()
 | 
			
		||||
    clear { env = {
 | 
			
		||||
@@ -19,79 +21,98 @@ describe('vim.lsp.diagnostic', function()
 | 
			
		||||
      VIMRUNTIME = os.getenv 'VIMRUNTIME',
 | 
			
		||||
    } }
 | 
			
		||||
 | 
			
		||||
    exec_lua [[
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      require('vim.lsp')
 | 
			
		||||
 | 
			
		||||
      make_range = function(x1, y1, x2, y2)
 | 
			
		||||
      _G.make_range = function(x1, y1, x2, y2)
 | 
			
		||||
        return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      make_error = function(msg, x1, y1, x2, y2)
 | 
			
		||||
      _G.make_error = function(msg, x1, y1, x2, y2)
 | 
			
		||||
        return {
 | 
			
		||||
          range = make_range(x1, y1, x2, y2),
 | 
			
		||||
          range = _G.make_range(x1, y1, x2, y2),
 | 
			
		||||
          message = msg,
 | 
			
		||||
          severity = 1,
 | 
			
		||||
        }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      make_warning = function(msg, x1, y1, x2, y2)
 | 
			
		||||
      _G.make_warning = function(msg, x1, y1, x2, y2)
 | 
			
		||||
        return {
 | 
			
		||||
          range = make_range(x1, y1, x2, y2),
 | 
			
		||||
          range = _G.make_range(x1, y1, x2, y2),
 | 
			
		||||
          message = msg,
 | 
			
		||||
          severity = 2,
 | 
			
		||||
        }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      make_information = function(msg, x1, y1, x2, y2)
 | 
			
		||||
      _G.make_information = function(msg, x1, y1, x2, y2)
 | 
			
		||||
        return {
 | 
			
		||||
          range = make_range(x1, y1, x2, y2),
 | 
			
		||||
          range = _G.make_range(x1, y1, x2, y2),
 | 
			
		||||
          message = msg,
 | 
			
		||||
          severity = 3,
 | 
			
		||||
        }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      function get_extmarks(bufnr, client_id)
 | 
			
		||||
        local namespace = vim.lsp.diagnostic.get_namespace(client_id)
 | 
			
		||||
      function _G.get_extmarks(bufnr, client_id0)
 | 
			
		||||
        local namespace = vim.lsp.diagnostic.get_namespace(client_id0)
 | 
			
		||||
        local ns = vim.diagnostic.get_namespace(namespace)
 | 
			
		||||
        local extmarks = {}
 | 
			
		||||
        if ns.user_data.virt_text_ns then
 | 
			
		||||
          for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do
 | 
			
		||||
          for _, e in
 | 
			
		||||
            pairs(
 | 
			
		||||
              vim.api.nvim_buf_get_extmarks(
 | 
			
		||||
                bufnr,
 | 
			
		||||
                ns.user_data.virt_text_ns,
 | 
			
		||||
                0,
 | 
			
		||||
                -1,
 | 
			
		||||
                { details = true }
 | 
			
		||||
              )
 | 
			
		||||
            )
 | 
			
		||||
          do
 | 
			
		||||
            table.insert(extmarks, e)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
        if ns.user_data.underline_ns then
 | 
			
		||||
          for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do
 | 
			
		||||
          for _, e in
 | 
			
		||||
            pairs(
 | 
			
		||||
              vim.api.nvim_buf_get_extmarks(
 | 
			
		||||
                bufnr,
 | 
			
		||||
                ns.user_data.underline_ns,
 | 
			
		||||
                0,
 | 
			
		||||
                -1,
 | 
			
		||||
                { details = true }
 | 
			
		||||
              )
 | 
			
		||||
            )
 | 
			
		||||
          do
 | 
			
		||||
            table.insert(extmarks, e)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
        return extmarks
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      client_id = vim.lsp.start_client {
 | 
			
		||||
      client_id = assert(vim.lsp.start_client {
 | 
			
		||||
        cmd_env = {
 | 
			
		||||
          NVIM_LUA_NOTRACK = "1";
 | 
			
		||||
        };
 | 
			
		||||
          NVIM_LUA_NOTRACK = '1',
 | 
			
		||||
        },
 | 
			
		||||
        cmd = {
 | 
			
		||||
          vim.v.progpath, '-es', '-u', 'NONE', '--headless'
 | 
			
		||||
        };
 | 
			
		||||
        offset_encoding = "utf-16";
 | 
			
		||||
      }
 | 
			
		||||
    ]]
 | 
			
		||||
          vim.v.progpath,
 | 
			
		||||
          '-es',
 | 
			
		||||
          '-u',
 | 
			
		||||
          'NONE',
 | 
			
		||||
          '--headless',
 | 
			
		||||
        },
 | 
			
		||||
        offset_encoding = 'utf-16',
 | 
			
		||||
      })
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    fake_uri = 'file:///fake/uri'
 | 
			
		||||
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      fake_uri = ...
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      diagnostic_bufnr = vim.uri_to_bufnr(fake_uri)
 | 
			
		||||
      local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"}
 | 
			
		||||
      local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' }
 | 
			
		||||
      vim.fn.bufload(diagnostic_bufnr)
 | 
			
		||||
      vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
 | 
			
		||||
      vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
 | 
			
		||||
      return diagnostic_bufnr
 | 
			
		||||
    ]],
 | 
			
		||||
      fake_uri
 | 
			
		||||
    )
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  after_each(function()
 | 
			
		||||
@@ -101,89 +122,73 @@ describe('vim.lsp.diagnostic', function()
 | 
			
		||||
  describe('vim.lsp.diagnostic.on_publish_diagnostics', function()
 | 
			
		||||
    it('allows configuring the virtual text via vim.lsp.with', function()
 | 
			
		||||
      local expected_spacing = 10
 | 
			
		||||
      local extmarks = exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
 | 
			
		||||
      local extmarks = exec_lua(function()
 | 
			
		||||
        _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
 | 
			
		||||
          virtual_text = {
 | 
			
		||||
            spacing = ...,
 | 
			
		||||
            spacing = expected_spacing,
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        PublishDiagnostics(nil, {
 | 
			
		||||
        _G.PublishDiagnostics(nil, {
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          diagnostics = {
 | 
			
		||||
              make_error('Delayed Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
            }
 | 
			
		||||
          }, {client_id=client_id}
 | 
			
		||||
        )
 | 
			
		||||
            _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
          },
 | 
			
		||||
        }, { client_id = client_id })
 | 
			
		||||
 | 
			
		||||
        return get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
      ]],
 | 
			
		||||
        expected_spacing
 | 
			
		||||
      )
 | 
			
		||||
        return _G.get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      local virt_text = extmarks[1][4].virt_text
 | 
			
		||||
      local spacing = virt_text[1][1]
 | 
			
		||||
      local spacing = extmarks[1][4].virt_text[1][1]
 | 
			
		||||
 | 
			
		||||
      eq(expected_spacing, #spacing)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('allows configuring the virtual text via vim.lsp.with using a function', function()
 | 
			
		||||
      local expected_spacing = 10
 | 
			
		||||
      local extmarks = exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        spacing = ...
 | 
			
		||||
 | 
			
		||||
        PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
 | 
			
		||||
      local extmarks = exec_lua(function()
 | 
			
		||||
        _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
 | 
			
		||||
          virtual_text = function()
 | 
			
		||||
            return {
 | 
			
		||||
              spacing = spacing,
 | 
			
		||||
              spacing = expected_spacing,
 | 
			
		||||
            }
 | 
			
		||||
          end,
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        PublishDiagnostics(nil, {
 | 
			
		||||
        _G.PublishDiagnostics(nil, {
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          diagnostics = {
 | 
			
		||||
              make_error('Delayed Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
            }
 | 
			
		||||
          }, {client_id=client_id}
 | 
			
		||||
        )
 | 
			
		||||
            _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
          },
 | 
			
		||||
        }, { client_id = client_id })
 | 
			
		||||
 | 
			
		||||
        return get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
      ]],
 | 
			
		||||
        expected_spacing
 | 
			
		||||
      )
 | 
			
		||||
        return _G.get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      local virt_text = extmarks[1][4].virt_text
 | 
			
		||||
      local spacing = virt_text[1][1]
 | 
			
		||||
      local spacing = extmarks[1][4].virt_text[1][1]
 | 
			
		||||
 | 
			
		||||
      eq(expected_spacing, #spacing)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('allows filtering via severity limit', function()
 | 
			
		||||
      local get_extmark_count_with_severity = function(severity_limit)
 | 
			
		||||
        return exec_lua(
 | 
			
		||||
          [[
 | 
			
		||||
          PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
 | 
			
		||||
        return exec_lua(function()
 | 
			
		||||
          _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
 | 
			
		||||
            underline = false,
 | 
			
		||||
            virtual_text = {
 | 
			
		||||
              severity = { min = ... }
 | 
			
		||||
              severity = { min = severity_limit },
 | 
			
		||||
            },
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          PublishDiagnostics(nil, {
 | 
			
		||||
          _G.PublishDiagnostics(nil, {
 | 
			
		||||
            uri = fake_uri,
 | 
			
		||||
            diagnostics = {
 | 
			
		||||
                make_warning('Delayed Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
              }
 | 
			
		||||
            }, {client_id=client_id}
 | 
			
		||||
          )
 | 
			
		||||
              _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
            },
 | 
			
		||||
          }, { client_id = client_id })
 | 
			
		||||
 | 
			
		||||
          return #get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
        ]],
 | 
			
		||||
          severity_limit
 | 
			
		||||
        )
 | 
			
		||||
          return #_G.get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
        end, client_id, fake_uri, severity_limit)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      -- No messages with Error or higher
 | 
			
		||||
@@ -196,246 +201,284 @@ describe('vim.lsp.diagnostic', function()
 | 
			
		||||
 | 
			
		||||
    it('correctly handles UTF-16 offsets', function()
 | 
			
		||||
      local line = 'All 💼 and no 🎉 makes Jack a dull 👦'
 | 
			
		||||
      local result = exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        local line = ...
 | 
			
		||||
      local result = exec_lua(function()
 | 
			
		||||
        vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, { line })
 | 
			
		||||
 | 
			
		||||
        vim.lsp.diagnostic.on_publish_diagnostics(nil, {
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          diagnostics = {
 | 
			
		||||
              make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
 | 
			
		||||
            }
 | 
			
		||||
          }, {client_id=client_id}
 | 
			
		||||
        )
 | 
			
		||||
            _G.make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
 | 
			
		||||
          },
 | 
			
		||||
        }, { client_id = client_id })
 | 
			
		||||
 | 
			
		||||
        local diags = vim.diagnostic.get(diagnostic_bufnr)
 | 
			
		||||
        vim.lsp.stop_client(client_id)
 | 
			
		||||
        vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
 | 
			
		||||
        return diags
 | 
			
		||||
      ]],
 | 
			
		||||
        line
 | 
			
		||||
      )
 | 
			
		||||
      end)
 | 
			
		||||
      eq(1, #result)
 | 
			
		||||
      eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col)
 | 
			
		||||
      eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col)
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.str_byteindex(line, 7, true)
 | 
			
		||||
        end),
 | 
			
		||||
        result[1].col
 | 
			
		||||
      )
 | 
			
		||||
      eq(
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.str_byteindex(line, 8, true)
 | 
			
		||||
        end),
 | 
			
		||||
        result[1].end_col
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('does not create buffer on empty diagnostics', function()
 | 
			
		||||
      local bufnr
 | 
			
		||||
 | 
			
		||||
      -- No buffer is created without diagnostics
 | 
			
		||||
      bufnr = exec_lua [[
 | 
			
		||||
      eq(
 | 
			
		||||
        -1,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.diagnostic.on_publish_diagnostics(nil, {
 | 
			
		||||
          uri = "file:///fake/uri2",
 | 
			
		||||
            uri = 'file:///fake/uri2',
 | 
			
		||||
            diagnostics = {},
 | 
			
		||||
          }, { client_id = client_id })
 | 
			
		||||
        return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
 | 
			
		||||
      ]]
 | 
			
		||||
      eq(-1, bufnr)
 | 
			
		||||
          return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      -- Create buffer on diagnostics
 | 
			
		||||
      bufnr = exec_lua [[
 | 
			
		||||
      neq(
 | 
			
		||||
        -1,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.diagnostic.on_publish_diagnostics(nil, {
 | 
			
		||||
          uri = "file:///fake/uri2",
 | 
			
		||||
            uri = 'file:///fake/uri2',
 | 
			
		||||
            diagnostics = {
 | 
			
		||||
            make_error('Diagnostic', 0, 0, 0, 0),
 | 
			
		||||
              _G.make_error('Diagnostic', 0, 0, 0, 0),
 | 
			
		||||
            },
 | 
			
		||||
          }, { client_id = client_id })
 | 
			
		||||
        return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
 | 
			
		||||
      ]]
 | 
			
		||||
      neq(-1, bufnr)
 | 
			
		||||
      eq(1, exec_lua([[return #vim.diagnostic.get(...)]], bufnr))
 | 
			
		||||
          return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      eq(
 | 
			
		||||
        1,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return #vim.diagnostic.get(_G.bufnr)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      -- Clear diagnostics after buffer was created
 | 
			
		||||
      bufnr = exec_lua [[
 | 
			
		||||
      neq(
 | 
			
		||||
        -1,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.diagnostic.on_publish_diagnostics(nil, {
 | 
			
		||||
          uri = "file:///fake/uri2",
 | 
			
		||||
            uri = 'file:///fake/uri2',
 | 
			
		||||
            diagnostics = {},
 | 
			
		||||
          }, { client_id = client_id })
 | 
			
		||||
        return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
 | 
			
		||||
      ]]
 | 
			
		||||
      neq(-1, bufnr)
 | 
			
		||||
      eq(0, exec_lua([[return #vim.diagnostic.get(...)]], bufnr))
 | 
			
		||||
          return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      eq(
 | 
			
		||||
        0,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return #vim.diagnostic.get(_G.bufnr)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  describe('vim.lsp.diagnostic.on_diagnostic', function()
 | 
			
		||||
    before_each(function()
 | 
			
		||||
      exec_lua(create_server_definition)
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        server = _create_server({
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        _G.server = _G._create_server({
 | 
			
		||||
          capabilities = {
 | 
			
		||||
            diagnosticProvider = {
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
            diagnosticProvider = {},
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        function get_extmarks(bufnr, client_id)
 | 
			
		||||
          local namespace = vim.lsp.diagnostic.get_namespace(client_id, true)
 | 
			
		||||
        function _G.get_extmarks(bufnr, client_id0)
 | 
			
		||||
          local namespace = vim.lsp.diagnostic.get_namespace(client_id0, true)
 | 
			
		||||
          local ns = vim.diagnostic.get_namespace(namespace)
 | 
			
		||||
          local extmarks = {}
 | 
			
		||||
          if ns.user_data.virt_text_ns then
 | 
			
		||||
            for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do
 | 
			
		||||
            for _, e in
 | 
			
		||||
              pairs(
 | 
			
		||||
                vim.api.nvim_buf_get_extmarks(
 | 
			
		||||
                  bufnr,
 | 
			
		||||
                  ns.user_data.virt_text_ns,
 | 
			
		||||
                  0,
 | 
			
		||||
                  -1,
 | 
			
		||||
                  { details = true }
 | 
			
		||||
                )
 | 
			
		||||
              )
 | 
			
		||||
            do
 | 
			
		||||
              table.insert(extmarks, e)
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
          if ns.user_data.underline_ns then
 | 
			
		||||
            for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do
 | 
			
		||||
            for _, e in
 | 
			
		||||
              pairs(
 | 
			
		||||
                vim.api.nvim_buf_get_extmarks(
 | 
			
		||||
                  bufnr,
 | 
			
		||||
                  ns.user_data.underline_ns,
 | 
			
		||||
                  0,
 | 
			
		||||
                  -1,
 | 
			
		||||
                  { details = true }
 | 
			
		||||
                )
 | 
			
		||||
              )
 | 
			
		||||
            do
 | 
			
		||||
              table.insert(extmarks, e)
 | 
			
		||||
            end
 | 
			
		||||
          end
 | 
			
		||||
          return extmarks
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('adds diagnostics to vim.diagnostics', function()
 | 
			
		||||
      local diags = exec_lua([[
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil,
 | 
			
		||||
          {
 | 
			
		||||
      local diags = exec_lua(function()
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil, {
 | 
			
		||||
          kind = 'full',
 | 
			
		||||
          items = {
 | 
			
		||||
              make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
            }
 | 
			
		||||
            _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
        }, {
 | 
			
		||||
          params = {
 | 
			
		||||
            textDocument = { uri = fake_uri },
 | 
			
		||||
          },
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          client_id = client_id,
 | 
			
		||||
          },
 | 
			
		||||
          {}
 | 
			
		||||
        )
 | 
			
		||||
        }, {})
 | 
			
		||||
 | 
			
		||||
        return vim.diagnostic.get(diagnostic_bufnr)
 | 
			
		||||
      ]])
 | 
			
		||||
      end)
 | 
			
		||||
      eq(1, #diags)
 | 
			
		||||
      eq('Pull Diagnostic', diags[1].message)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('severity defaults to error if missing', function()
 | 
			
		||||
      ---@type vim.Diagnostic[]
 | 
			
		||||
      local diagnostics = exec_lua([[
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil,
 | 
			
		||||
          {
 | 
			
		||||
      local diagnostics = exec_lua(function()
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil, {
 | 
			
		||||
          kind = 'full',
 | 
			
		||||
          items = {
 | 
			
		||||
            {
 | 
			
		||||
                range = make_range(4, 4, 4, 4),
 | 
			
		||||
                message = "bad!",
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
              range = _G.make_range(4, 4, 4, 4),
 | 
			
		||||
              message = 'bad!',
 | 
			
		||||
            },
 | 
			
		||||
          {
 | 
			
		||||
          },
 | 
			
		||||
        }, {
 | 
			
		||||
          params = {
 | 
			
		||||
            textDocument = { uri = fake_uri },
 | 
			
		||||
          },
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          client_id = client_id,
 | 
			
		||||
          },
 | 
			
		||||
          {}
 | 
			
		||||
        )
 | 
			
		||||
        }, {})
 | 
			
		||||
        return vim.diagnostic.get(diagnostic_bufnr)
 | 
			
		||||
      ]])
 | 
			
		||||
      end)
 | 
			
		||||
      eq(1, #diagnostics)
 | 
			
		||||
      eq(1, diagnostics[1].severity)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('allows configuring the virtual text via vim.lsp.with', function()
 | 
			
		||||
      local expected_spacing = 10
 | 
			
		||||
      local extmarks = exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
 | 
			
		||||
      local extmarks = exec_lua(function()
 | 
			
		||||
        _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
 | 
			
		||||
          virtual_text = {
 | 
			
		||||
            spacing = ...,
 | 
			
		||||
            spacing = expected_spacing,
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        Diagnostic(nil,
 | 
			
		||||
          {
 | 
			
		||||
        _G.Diagnostic(nil, {
 | 
			
		||||
          kind = 'full',
 | 
			
		||||
          items = {
 | 
			
		||||
              make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
            }
 | 
			
		||||
            _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
        }, {
 | 
			
		||||
          params = {
 | 
			
		||||
            textDocument = { uri = fake_uri },
 | 
			
		||||
          },
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          client_id = client_id,
 | 
			
		||||
          },
 | 
			
		||||
          {}
 | 
			
		||||
        )
 | 
			
		||||
        }, {})
 | 
			
		||||
 | 
			
		||||
        return get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
      ]],
 | 
			
		||||
        expected_spacing
 | 
			
		||||
      )
 | 
			
		||||
        return _G.get_extmarks(diagnostic_bufnr, client_id)
 | 
			
		||||
      end)
 | 
			
		||||
      eq(2, #extmarks)
 | 
			
		||||
      eq(expected_spacing, #extmarks[1][4].virt_text[1][1])
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('clears diagnostics when client detaches', function()
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil,
 | 
			
		||||
          {
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil, {
 | 
			
		||||
          kind = 'full',
 | 
			
		||||
          items = {
 | 
			
		||||
              make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
            }
 | 
			
		||||
            _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
        }, {
 | 
			
		||||
          params = {
 | 
			
		||||
            textDocument = { uri = fake_uri },
 | 
			
		||||
          },
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          client_id = client_id,
 | 
			
		||||
          },
 | 
			
		||||
          {}
 | 
			
		||||
        }, {})
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      eq(
 | 
			
		||||
        1,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return #vim.diagnostic.get(diagnostic_bufnr)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      ]])
 | 
			
		||||
      local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
 | 
			
		||||
      eq(1, #diags)
 | 
			
		||||
 | 
			
		||||
      exec_lua([[ vim.lsp.stop_client(client_id) ]])
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.stop_client(client_id)
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
 | 
			
		||||
      eq(0, #diags)
 | 
			
		||||
      eq(
 | 
			
		||||
        0,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return #vim.diagnostic.get(diagnostic_bufnr)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('keeps diagnostics when one client detaches and others still are attached', function()
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        client_id2 = vim.lsp.start({ name = 'dummy2', cmd = server.cmd })
 | 
			
		||||
      local client_id2
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server.cmd })
 | 
			
		||||
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil,
 | 
			
		||||
          {
 | 
			
		||||
        vim.lsp.diagnostic.on_diagnostic(nil, {
 | 
			
		||||
          kind = 'full',
 | 
			
		||||
          items = {
 | 
			
		||||
              make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
            }
 | 
			
		||||
            _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
        }, {
 | 
			
		||||
          params = {
 | 
			
		||||
            textDocument = { uri = fake_uri },
 | 
			
		||||
          },
 | 
			
		||||
          uri = fake_uri,
 | 
			
		||||
          client_id = client_id,
 | 
			
		||||
          },
 | 
			
		||||
          {}
 | 
			
		||||
        }, {})
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      eq(
 | 
			
		||||
        1,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return #vim.diagnostic.get(diagnostic_bufnr)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      ]])
 | 
			
		||||
      local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
 | 
			
		||||
      eq(1, #diags)
 | 
			
		||||
 | 
			
		||||
      exec_lua([[ vim.lsp.stop_client(client_id2) ]])
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.stop_client(client_id2)
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
 | 
			
		||||
      eq(1, #diags)
 | 
			
		||||
      eq(
 | 
			
		||||
        1,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return #vim.diagnostic.get(diagnostic_bufnr)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,28 +11,31 @@ describe('lsp-handlers', function()
 | 
			
		||||
    it('should return a table with the default keys', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        { hello = 'world' },
 | 
			
		||||
        exec_lua [[
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.lsp._with_extend('test', { hello = 'world' })
 | 
			
		||||
      ]]
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('should override with config keys', function()
 | 
			
		||||
      eq(
 | 
			
		||||
        { hello = 'universe', other = true },
 | 
			
		||||
        exec_lua [[
 | 
			
		||||
        return vim.lsp._with_extend('test', { other = true, hello = 'world' }, { hello = 'universe' })
 | 
			
		||||
      ]]
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.lsp._with_extend(
 | 
			
		||||
            'test',
 | 
			
		||||
            { other = true, hello = 'world' },
 | 
			
		||||
            { hello = 'universe' }
 | 
			
		||||
          )
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('should not allow invalid keys', function()
 | 
			
		||||
      matches(
 | 
			
		||||
        '.*Invalid option for `test`.*',
 | 
			
		||||
        pcall_err(
 | 
			
		||||
          exec_lua,
 | 
			
		||||
          "return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })"
 | 
			
		||||
        )
 | 
			
		||||
        pcall_err(exec_lua, function()
 | 
			
		||||
          return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,11 +10,9 @@ local feed = n.feed
 | 
			
		||||
 | 
			
		||||
before_each(function()
 | 
			
		||||
  clear()
 | 
			
		||||
  exec_lua [[
 | 
			
		||||
    local evname = ...
 | 
			
		||||
  exec_lua(function()
 | 
			
		||||
    local sync = require('vim.lsp.sync')
 | 
			
		||||
    local events = {}
 | 
			
		||||
    local buffer_cache = {}
 | 
			
		||||
 | 
			
		||||
    -- local format_line_ending = {
 | 
			
		||||
    --   ["unix"] = '\n',
 | 
			
		||||
@@ -24,19 +22,25 @@ before_each(function()
 | 
			
		||||
 | 
			
		||||
    -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    function test_register(bufnr, id, offset_encoding, line_ending)
 | 
			
		||||
      local curr_lines
 | 
			
		||||
    --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
    function _G.test_register(bufnr, id, offset_encoding, line_ending)
 | 
			
		||||
      local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
 | 
			
		||||
 | 
			
		||||
      local function callback(_, bufnr, changedtick, firstline, lastline, new_lastline)
 | 
			
		||||
        if test_unreg == id then
 | 
			
		||||
      local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline)
 | 
			
		||||
        if _G.test_unreg == id then
 | 
			
		||||
          return true
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        local curr_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
 | 
			
		||||
        local curr_lines = vim.api.nvim_buf_get_lines(bufnr0, 0, -1, true)
 | 
			
		||||
        local incremental_change = sync.compute_diff(
 | 
			
		||||
          prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding, line_ending)
 | 
			
		||||
          prev_lines,
 | 
			
		||||
          curr_lines,
 | 
			
		||||
          firstline,
 | 
			
		||||
          lastline,
 | 
			
		||||
          new_lastline,
 | 
			
		||||
          offset_encoding,
 | 
			
		||||
          line_ending
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        table.insert(events, incremental_change)
 | 
			
		||||
        prev_lines = curr_lines
 | 
			
		||||
@@ -45,14 +49,16 @@ before_each(function()
 | 
			
		||||
      vim.api.nvim_buf_attach(bufnr, false, opts)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    function get_events()
 | 
			
		||||
    --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
    function _G.get_events()
 | 
			
		||||
      local ret_events = events
 | 
			
		||||
      events = {}
 | 
			
		||||
      return ret_events
 | 
			
		||||
    end
 | 
			
		||||
  ]]
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
--- @param edit_operations string[]
 | 
			
		||||
local function test_edit(
 | 
			
		||||
  prev_buffer,
 | 
			
		||||
  edit_operations,
 | 
			
		||||
@@ -64,13 +70,22 @@ local function test_edit(
 | 
			
		||||
  line_ending = line_ending or '\n'
 | 
			
		||||
 | 
			
		||||
  api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer)
 | 
			
		||||
  exec_lua('return test_register(...)', 0, 'test1', offset_encoding, line_ending)
 | 
			
		||||
  exec_lua(function()
 | 
			
		||||
    return _G.test_register(0, 'test1', offset_encoding, line_ending)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  for _, edit in ipairs(edit_operations) do
 | 
			
		||||
    feed(edit)
 | 
			
		||||
  end
 | 
			
		||||
  eq(expected_text_changes, exec_lua('return get_events(...)'))
 | 
			
		||||
  exec_lua("test_unreg = 'test1'")
 | 
			
		||||
  eq(
 | 
			
		||||
    expected_text_changes,
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      return _G.get_events()
 | 
			
		||||
    end)
 | 
			
		||||
  )
 | 
			
		||||
  exec_lua(function()
 | 
			
		||||
    _G.test_unreg = 'test1'
 | 
			
		||||
  end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe('incremental synchronization', function()
 | 
			
		||||
 
 | 
			
		||||
@@ -57,16 +57,22 @@ int main() {
 | 
			
		||||
 | 
			
		||||
  --- @type test.functional.ui.screen
 | 
			
		||||
  local screen
 | 
			
		||||
 | 
			
		||||
  --- @type integer
 | 
			
		||||
  local client_id
 | 
			
		||||
 | 
			
		||||
  --- @type integer
 | 
			
		||||
  local bufnr
 | 
			
		||||
 | 
			
		||||
  before_each(function()
 | 
			
		||||
    clear_notrace()
 | 
			
		||||
    screen = Screen.new(50, 9)
 | 
			
		||||
    screen:attach()
 | 
			
		||||
 | 
			
		||||
    bufnr = n.api.nvim_get_current_buf()
 | 
			
		||||
    exec_lua(create_server_definition)
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
    local response = ...
 | 
			
		||||
    server = _create_server({
 | 
			
		||||
    client_id = exec_lua(function()
 | 
			
		||||
      _G.server = _G._create_server({
 | 
			
		||||
        capabilities = {
 | 
			
		||||
          inlayHintProvider = true,
 | 
			
		||||
        },
 | 
			
		||||
@@ -74,19 +80,16 @@ int main() {
 | 
			
		||||
          ['textDocument/inlayHint'] = function(_, _, callback)
 | 
			
		||||
            callback(nil, vim.json.decode(response))
 | 
			
		||||
          end,
 | 
			
		||||
      }
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
    bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
    vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
 | 
			
		||||
    client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
  ]],
 | 
			
		||||
      response
 | 
			
		||||
    )
 | 
			
		||||
      return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    insert(text)
 | 
			
		||||
    exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect({ grid = grid_with_inlay_hints })
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
@@ -95,13 +98,15 @@ int main() {
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('clears inlay hints when sole client detaches', function()
 | 
			
		||||
    exec_lua([[vim.lsp.stop_client(client_id)]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.lsp.stop_client(client_id)
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('does not clear inlay hints when one of several clients detaches', function()
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      server2 = _create_server({
 | 
			
		||||
    local client_id2 = exec_lua(function()
 | 
			
		||||
      _G.server2 = _G._create_server({
 | 
			
		||||
        capabilities = {
 | 
			
		||||
          inlayHintProvider = true,
 | 
			
		||||
        },
 | 
			
		||||
@@ -109,13 +114,16 @@ int main() {
 | 
			
		||||
          ['textDocument/inlayHint'] = function(_, _, callback)
 | 
			
		||||
            callback(nil, {})
 | 
			
		||||
          end,
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
      client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
 | 
			
		||||
      local client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd })
 | 
			
		||||
      vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
 | 
			
		||||
    ]])
 | 
			
		||||
      return client_id2
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    exec_lua([[ vim.lsp.stop_client(client2) ]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.lsp.stop_client(client_id2)
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
@@ -123,61 +131,85 @@ int main() {
 | 
			
		||||
    it('validation', function()
 | 
			
		||||
      t.matches(
 | 
			
		||||
        'enable: expected boolean, got table',
 | 
			
		||||
        t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })]])
 | 
			
		||||
        t.pcall_err(exec_lua, function()
 | 
			
		||||
          --- @diagnostic disable-next-line:param-type-mismatch
 | 
			
		||||
          vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      t.matches(
 | 
			
		||||
        'enable: expected boolean, got number',
 | 
			
		||||
        t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(42)]])
 | 
			
		||||
        t.pcall_err(exec_lua, function()
 | 
			
		||||
          --- @diagnostic disable-next-line:param-type-mismatch
 | 
			
		||||
          vim.lsp.inlay_hint.enable(42)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
      t.matches(
 | 
			
		||||
        'filter: expected table, got number',
 | 
			
		||||
        t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(true, 42)]])
 | 
			
		||||
        t.pcall_err(exec_lua, function()
 | 
			
		||||
          --- @diagnostic disable-next-line:param-type-mismatch
 | 
			
		||||
          vim.lsp.inlay_hint.enable(true, 42)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    describe('clears/applies inlay hints when passed false/true/nil', function()
 | 
			
		||||
      local bufnr2 --- @type integer
 | 
			
		||||
      before_each(function()
 | 
			
		||||
        exec_lua([[
 | 
			
		||||
          bufnr2 = vim.api.nvim_create_buf(true, false)
 | 
			
		||||
          vim.lsp.buf_attach_client(bufnr2, client_id)
 | 
			
		||||
          vim.api.nvim_win_set_buf(0, bufnr2)
 | 
			
		||||
        ]])
 | 
			
		||||
        bufnr2 = exec_lua(function()
 | 
			
		||||
          local bufnr2_0 = vim.api.nvim_create_buf(true, false)
 | 
			
		||||
          vim.lsp.buf_attach_client(bufnr2_0, client_id)
 | 
			
		||||
          vim.api.nvim_win_set_buf(0, bufnr2_0)
 | 
			
		||||
          return bufnr2_0
 | 
			
		||||
        end)
 | 
			
		||||
        insert(text)
 | 
			
		||||
        exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })]])
 | 
			
		||||
        exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })
 | 
			
		||||
        end)
 | 
			
		||||
        n.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        screen:expect({ grid = grid_with_inlay_hints })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      it('for one single buffer', function()
 | 
			
		||||
        exec_lua([[
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.inlay_hint.enable(false, { bufnr = bufnr })
 | 
			
		||||
          vim.api.nvim_win_set_buf(0, bufnr2)
 | 
			
		||||
        ]])
 | 
			
		||||
        end)
 | 
			
		||||
        screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
 | 
			
		||||
        exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
 | 
			
		||||
        n.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
 | 
			
		||||
 | 
			
		||||
        exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
 | 
			
		||||
        end)
 | 
			
		||||
        screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
 | 
			
		||||
 | 
			
		||||
        exec_lua(
 | 
			
		||||
          [[vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr })]]
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.inlay_hint.enable(
 | 
			
		||||
            not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }),
 | 
			
		||||
            { bufnr = bufnr }
 | 
			
		||||
          )
 | 
			
		||||
        end)
 | 
			
		||||
        screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
 | 
			
		||||
 | 
			
		||||
        exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
 | 
			
		||||
        end)
 | 
			
		||||
        screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      it('for all buffers', function()
 | 
			
		||||
        exec_lua([[vim.lsp.inlay_hint.enable(false)]])
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.inlay_hint.enable(false)
 | 
			
		||||
        end)
 | 
			
		||||
        screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
 | 
			
		||||
        exec_lua([[vim.api.nvim_win_set_buf(0, bufnr2)]])
 | 
			
		||||
        n.api.nvim_win_set_buf(0, bufnr2)
 | 
			
		||||
        screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
 | 
			
		||||
 | 
			
		||||
        exec_lua([[vim.lsp.inlay_hint.enable(true)]])
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.inlay_hint.enable(true)
 | 
			
		||||
        end)
 | 
			
		||||
        screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
 | 
			
		||||
        exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
 | 
			
		||||
        n.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
 | 
			
		||||
      end)
 | 
			
		||||
    end)
 | 
			
		||||
@@ -198,10 +230,8 @@ int main() {
 | 
			
		||||
        paddingRight = false,
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        local expected2 = ...
 | 
			
		||||
        server2 = _create_server({
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        _G.server2 = _G._create_server({
 | 
			
		||||
          capabilities = {
 | 
			
		||||
            inlayHintProvider = true,
 | 
			
		||||
          },
 | 
			
		||||
@@ -209,52 +239,63 @@ int main() {
 | 
			
		||||
            ['textDocument/inlayHint'] = function(_, _, callback)
 | 
			
		||||
              callback(nil, { expected2 })
 | 
			
		||||
            end,
 | 
			
		||||
          }
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
        client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
 | 
			
		||||
        _G.client2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd })
 | 
			
		||||
        vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
 | 
			
		||||
      ]],
 | 
			
		||||
        expected2
 | 
			
		||||
      )
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      --- @type vim.lsp.inlay_hint.get.ret
 | 
			
		||||
      local res = exec_lua([[return vim.lsp.inlay_hint.get()]])
 | 
			
		||||
      eq({
 | 
			
		||||
      eq(
 | 
			
		||||
        {
 | 
			
		||||
          { bufnr = 1, client_id = 1, inlay_hint = expected[1] },
 | 
			
		||||
          { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
 | 
			
		||||
          { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
 | 
			
		||||
          { bufnr = 1, client_id = 2, inlay_hint = expected2 },
 | 
			
		||||
      }, res)
 | 
			
		||||
        },
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.lsp.inlay_hint.get()
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      --- @type vim.lsp.inlay_hint.get.ret
 | 
			
		||||
      res = exec_lua([[return vim.lsp.inlay_hint.get({
 | 
			
		||||
      eq(
 | 
			
		||||
        {
 | 
			
		||||
          { bufnr = 1, client_id = 2, inlay_hint = expected2 },
 | 
			
		||||
        },
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.lsp.inlay_hint.get({
 | 
			
		||||
            range = {
 | 
			
		||||
              start = { line = 2, character = 10 },
 | 
			
		||||
          ["end"] = { line = 2, character = 10 },
 | 
			
		||||
              ['end'] = { line = 2, character = 10 },
 | 
			
		||||
            },
 | 
			
		||||
      })]])
 | 
			
		||||
      eq({
 | 
			
		||||
        { bufnr = 1, client_id = 2, inlay_hint = expected2 },
 | 
			
		||||
      }, res)
 | 
			
		||||
          })
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      --- @type vim.lsp.inlay_hint.get.ret
 | 
			
		||||
      res = exec_lua([[return vim.lsp.inlay_hint.get({
 | 
			
		||||
      eq(
 | 
			
		||||
        {
 | 
			
		||||
          { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
 | 
			
		||||
          { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
 | 
			
		||||
        },
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.lsp.inlay_hint.get({
 | 
			
		||||
            bufnr = vim.api.nvim_get_current_buf(),
 | 
			
		||||
            range = {
 | 
			
		||||
              start = { line = 4, character = 18 },
 | 
			
		||||
          ["end"] = { line = 5, character = 17 },
 | 
			
		||||
              ['end'] = { line = 5, character = 17 },
 | 
			
		||||
            },
 | 
			
		||||
      })]])
 | 
			
		||||
      eq({
 | 
			
		||||
        { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
 | 
			
		||||
        { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
 | 
			
		||||
      }, res)
 | 
			
		||||
          })
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      --- @type vim.lsp.inlay_hint.get.ret
 | 
			
		||||
      res = exec_lua([[return vim.lsp.inlay_hint.get({
 | 
			
		||||
      eq(
 | 
			
		||||
        {},
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.lsp.inlay_hint.get({
 | 
			
		||||
            bufnr = vim.api.nvim_get_current_buf() + 1,
 | 
			
		||||
      })]])
 | 
			
		||||
      eq({}, res)
 | 
			
		||||
          })
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
@@ -288,16 +329,22 @@ test text
 | 
			
		||||
 | 
			
		||||
  --- @type test.functional.ui.screen
 | 
			
		||||
  local screen
 | 
			
		||||
 | 
			
		||||
  --- @type integer
 | 
			
		||||
  local client_id
 | 
			
		||||
 | 
			
		||||
  --- @type integer
 | 
			
		||||
  local bufnr
 | 
			
		||||
 | 
			
		||||
  before_each(function()
 | 
			
		||||
    clear_notrace()
 | 
			
		||||
    screen = Screen.new(50, 3)
 | 
			
		||||
    screen:attach()
 | 
			
		||||
 | 
			
		||||
    exec_lua(create_server_definition)
 | 
			
		||||
    exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
    local response = ...
 | 
			
		||||
    server = _create_server({
 | 
			
		||||
    bufnr = n.api.nvim_get_current_buf()
 | 
			
		||||
    client_id = exec_lua(function()
 | 
			
		||||
      _G.server = _G._create_server({
 | 
			
		||||
        capabilities = {
 | 
			
		||||
          inlayHintProvider = true,
 | 
			
		||||
        },
 | 
			
		||||
@@ -305,23 +352,22 @@ test text
 | 
			
		||||
          ['textDocument/inlayHint'] = function(_, _, callback)
 | 
			
		||||
            callback(nil, vim.json.decode(response))
 | 
			
		||||
          end,
 | 
			
		||||
      }
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
    bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
      vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
 | 
			
		||||
    client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
  ]],
 | 
			
		||||
      response
 | 
			
		||||
    )
 | 
			
		||||
      return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
    end)
 | 
			
		||||
    insert(text)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('renders hints with same position in received order', function()
 | 
			
		||||
    exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
 | 
			
		||||
    screen:expect({ grid = grid_with_inlay_hints })
 | 
			
		||||
    exec_lua([[vim.lsp.stop_client(client_id)]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.lsp.stop_client(client_id)
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ after_each(function()
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
describe('semantic token highlighting', function()
 | 
			
		||||
  local screen
 | 
			
		||||
  local screen --- @type test.functional.ui.screen
 | 
			
		||||
  before_each(function()
 | 
			
		||||
    screen = Screen.new(40, 16)
 | 
			
		||||
    screen:attach()
 | 
			
		||||
@@ -84,10 +84,8 @@ describe('semantic token highlighting', function()
 | 
			
		||||
 | 
			
		||||
    before_each(function()
 | 
			
		||||
      exec_lua(create_server_definition)
 | 
			
		||||
      exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        local legend, response, edit_response = ...
 | 
			
		||||
        server = _create_server({
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        _G.server = _G._create_server({
 | 
			
		||||
          capabilities = {
 | 
			
		||||
            semanticTokensProvider = {
 | 
			
		||||
              full = { delta = true },
 | 
			
		||||
@@ -101,23 +99,19 @@ describe('semantic token highlighting', function()
 | 
			
		||||
            ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
 | 
			
		||||
              callback(nil, vim.fn.json_decode(edit_response))
 | 
			
		||||
            end,
 | 
			
		||||
          }
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
      ]],
 | 
			
		||||
        legend,
 | 
			
		||||
        response,
 | 
			
		||||
        edit_response
 | 
			
		||||
      )
 | 
			
		||||
      end, legend, response, edit_response)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('buffer is highlighted when attached', function()
 | 
			
		||||
      insert(text)
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        local bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        vim.bo[bufnr].filetype = 'some-filetype'
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
        vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -141,21 +135,19 @@ describe('semantic token highlighting', function()
 | 
			
		||||
 | 
			
		||||
    it('use LspTokenUpdate and highlight_token', function()
 | 
			
		||||
      insert(text)
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        vim.api.nvim_create_autocmd("LspTokenUpdate", {
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.api.nvim_create_autocmd('LspTokenUpdate', {
 | 
			
		||||
          callback = function(args)
 | 
			
		||||
            local token = args.data.token
 | 
			
		||||
            if token.type == "function" and token.modifiers.declaration then
 | 
			
		||||
              vim.lsp.semantic_tokens.highlight_token(
 | 
			
		||||
                token, args.buf, args.data.client_id, "Macro"
 | 
			
		||||
              )
 | 
			
		||||
            local token = args.data.token --- @type STTokenRange
 | 
			
		||||
            if token.type == 'function' and token.modifiers.declaration then
 | 
			
		||||
              vim.lsp.semantic_tokens.highlight_token(token, args.buf, args.data.client_id, 'Macro')
 | 
			
		||||
            end
 | 
			
		||||
          end,
 | 
			
		||||
        })
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        local bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
        vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -180,19 +172,21 @@ describe('semantic token highlighting', function()
 | 
			
		||||
    it('buffer is unhighlighted when client is detached', function()
 | 
			
		||||
      insert(text)
 | 
			
		||||
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
      local bufnr = n.api.nvim_get_current_buf()
 | 
			
		||||
      local client_id = exec_lua(function()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
        local client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
        vim.wait(1000, function()
 | 
			
		||||
          return #server.messages > 1
 | 
			
		||||
          return #_G.server.messages > 1
 | 
			
		||||
        end)
 | 
			
		||||
        return client_id
 | 
			
		||||
      end)
 | 
			
		||||
      ]])
 | 
			
		||||
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
        vim.notify = function() end
 | 
			
		||||
        vim.lsp.buf_detach_client(bufnr, client_id)
 | 
			
		||||
      ]])
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -217,18 +211,19 @@ describe('semantic token highlighting', function()
 | 
			
		||||
    it(
 | 
			
		||||
      'buffer is highlighted and unhighlighted when semantic token highlighting is started and stopped',
 | 
			
		||||
      function()
 | 
			
		||||
        exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        local bufnr = n.api.nvim_get_current_buf()
 | 
			
		||||
        local client_id = exec_lua(function()
 | 
			
		||||
          vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
          return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
        end)
 | 
			
		||||
 | 
			
		||||
        insert(text)
 | 
			
		||||
 | 
			
		||||
        exec_lua([[
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
          vim.notify = function() end
 | 
			
		||||
          vim.lsp.semantic_tokens.stop(bufnr, client_id)
 | 
			
		||||
      ]])
 | 
			
		||||
        end)
 | 
			
		||||
 | 
			
		||||
        screen:expect {
 | 
			
		||||
          grid = [[
 | 
			
		||||
@@ -249,9 +244,9 @@ describe('semantic token highlighting', function()
 | 
			
		||||
      ]],
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        exec_lua([[
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.semantic_tokens.start(bufnr, client_id)
 | 
			
		||||
      ]])
 | 
			
		||||
        end)
 | 
			
		||||
 | 
			
		||||
        screen:expect {
 | 
			
		||||
          grid = [[
 | 
			
		||||
@@ -275,18 +270,17 @@ describe('semantic token highlighting', function()
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    it('highlights start and stop when using "0" for current buffer', function()
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
      local client_id = exec_lua(function()
 | 
			
		||||
        return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      insert(text)
 | 
			
		||||
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
        vim.notify = function() end
 | 
			
		||||
        vim.lsp.semantic_tokens.stop(0, client_id)
 | 
			
		||||
      ]])
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -307,9 +301,9 @@ describe('semantic token highlighting', function()
 | 
			
		||||
      ]],
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.semantic_tokens.start(0, client_id)
 | 
			
		||||
      ]])
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -333,11 +327,9 @@ describe('semantic token highlighting', function()
 | 
			
		||||
 | 
			
		||||
    it('buffer is re-highlighted when force refreshed', function()
 | 
			
		||||
      insert(text)
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -358,9 +350,9 @@ describe('semantic token highlighting', function()
 | 
			
		||||
      ]],
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        vim.lsp.semantic_tokens.force_refresh(bufnr)
 | 
			
		||||
      ]])
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.semantic_tokens.force_refresh()
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -384,7 +376,9 @@ describe('semantic token highlighting', function()
 | 
			
		||||
 | 
			
		||||
      local messages = exec_lua('return server.messages')
 | 
			
		||||
      local token_request_count = 0
 | 
			
		||||
      for _, message in ipairs(messages) do
 | 
			
		||||
      for _, message in
 | 
			
		||||
        ipairs(messages --[[@as {method:string,params:table}[] ]])
 | 
			
		||||
      do
 | 
			
		||||
        assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
 | 
			
		||||
        if message.method == 'textDocument/semanticTokens/full' then
 | 
			
		||||
          token_request_count = token_request_count + 1
 | 
			
		||||
@@ -394,31 +388,28 @@ describe('semantic token highlighting', function()
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('destroys the highlighter if the buffer is deleted', function()
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      insert(text)
 | 
			
		||||
 | 
			
		||||
      local highlighters = exec_lua([[
 | 
			
		||||
      eq(
 | 
			
		||||
        {},
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          local bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
          vim.api.nvim_buf_delete(bufnr, { force = true })
 | 
			
		||||
        local semantic_tokens = vim.lsp.semantic_tokens
 | 
			
		||||
        return semantic_tokens.__STHighlighter.active
 | 
			
		||||
      ]])
 | 
			
		||||
 | 
			
		||||
      eq({}, highlighters)
 | 
			
		||||
          return vim.lsp.semantic_tokens.__STHighlighter.active
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('updates highlights with delta request on buffer change', function()
 | 
			
		||||
      insert(text)
 | 
			
		||||
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -460,45 +451,49 @@ describe('semantic token highlighting', function()
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('prevents starting semantic token highlighting with invalid conditions', function()
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start_client({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
        notifications = {}
 | 
			
		||||
        vim.notify = function(...) table.insert(notifications, 1, {...}) end
 | 
			
		||||
      ]])
 | 
			
		||||
      eq(false, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)'))
 | 
			
		||||
      local client_id = exec_lua(function()
 | 
			
		||||
        _G.notifications = {}
 | 
			
		||||
        --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
        vim.notify = function(...)
 | 
			
		||||
          table.insert(_G.notifications, 1, { ... })
 | 
			
		||||
        end
 | 
			
		||||
        return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
      eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
 | 
			
		||||
 | 
			
		||||
      insert(text)
 | 
			
		||||
 | 
			
		||||
      local notifications = exec_lua([[
 | 
			
		||||
        vim.lsp.semantic_tokens.start(bufnr, client_id)
 | 
			
		||||
        return notifications
 | 
			
		||||
      ]])
 | 
			
		||||
      matches('%[LSP%] Client with id %d not attached to buffer %d', notifications[1][1])
 | 
			
		||||
      matches(
 | 
			
		||||
        '%[LSP%] Client with id %d not attached to buffer %d',
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.semantic_tokens.start(0, client_id)
 | 
			
		||||
          return _G.notifications[1][1]
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      notifications = exec_lua([[
 | 
			
		||||
        vim.lsp.semantic_tokens.start(bufnr, client_id + 1)
 | 
			
		||||
        return notifications
 | 
			
		||||
      ]])
 | 
			
		||||
      matches('%[LSP%] No client with id %d', notifications[1][1])
 | 
			
		||||
      matches(
 | 
			
		||||
        '%[LSP%] No client with id %d',
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          vim.lsp.semantic_tokens.start(0, client_id + 1)
 | 
			
		||||
          return _G.notifications[1][1]
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it(
 | 
			
		||||
      'opt-out: does not activate semantic token highlighting if disabled in client attach',
 | 
			
		||||
      function()
 | 
			
		||||
        exec_lua([[
 | 
			
		||||
          bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
          vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
          client_id = vim.lsp.start({
 | 
			
		||||
        local client_id = exec_lua(function()
 | 
			
		||||
          return vim.lsp.start({
 | 
			
		||||
            name = 'dummy',
 | 
			
		||||
            cmd = server.cmd,
 | 
			
		||||
            on_attach = vim.schedule_wrap(function(client, bufnr)
 | 
			
		||||
            cmd = _G.server.cmd,
 | 
			
		||||
            --- @param client vim.lsp.Client
 | 
			
		||||
            on_attach = vim.schedule_wrap(function(client, _bufnr)
 | 
			
		||||
              client.server_capabilities.semanticTokensProvider = nil
 | 
			
		||||
            end),
 | 
			
		||||
          })
 | 
			
		||||
        ]])
 | 
			
		||||
        eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)'))
 | 
			
		||||
        end)
 | 
			
		||||
        eq(true, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
 | 
			
		||||
 | 
			
		||||
        insert(text)
 | 
			
		||||
 | 
			
		||||
@@ -521,13 +516,18 @@ describe('semantic token highlighting', function()
 | 
			
		||||
        ]],
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        local notifications = exec_lua([[
 | 
			
		||||
        eq(
 | 
			
		||||
          '[LSP] Server does not support semantic tokens',
 | 
			
		||||
          exec_lua(function()
 | 
			
		||||
            local notifications = {}
 | 
			
		||||
          vim.notify = function(...) table.insert(notifications, 1, {...}) end
 | 
			
		||||
          vim.lsp.semantic_tokens.start(bufnr, client_id)
 | 
			
		||||
          return notifications
 | 
			
		||||
        ]])
 | 
			
		||||
        eq('[LSP] Server does not support semantic tokens', notifications[1][1])
 | 
			
		||||
            --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
            vim.notify = function(...)
 | 
			
		||||
              table.insert(notifications, 1, { ... })
 | 
			
		||||
            end
 | 
			
		||||
            vim.lsp.semantic_tokens.start(0, client_id)
 | 
			
		||||
            return notifications[1][1]
 | 
			
		||||
          end)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        screen:expect {
 | 
			
		||||
          grid = [[
 | 
			
		||||
@@ -552,28 +552,32 @@ describe('semantic token highlighting', function()
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    it('ignores null responses from the server', function()
 | 
			
		||||
      exec_lua([[
 | 
			
		||||
        local legend, response, edit_response = ...
 | 
			
		||||
        server2 = _create_server({
 | 
			
		||||
      local client_id = exec_lua(function()
 | 
			
		||||
        _G.server2 = _G._create_server({
 | 
			
		||||
          capabilities = {
 | 
			
		||||
            semanticTokensProvider = {
 | 
			
		||||
              full = { delta = false },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          handlers = {
 | 
			
		||||
            --- @param callback function
 | 
			
		||||
            ['textDocument/semanticTokens/full'] = function(_, _, callback)
 | 
			
		||||
              callback(nil, nil)
 | 
			
		||||
            end,
 | 
			
		||||
            ['textDocument/semanticTokens/full/delta'] = function()
 | 
			
		||||
            --- @param callback function
 | 
			
		||||
            ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
 | 
			
		||||
              callback(nil, nil)
 | 
			
		||||
            end,
 | 
			
		||||
          }
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd })
 | 
			
		||||
      ]])
 | 
			
		||||
      eq(true, exec_lua('return vim.lsp.buf_is_attached(bufnr, client_id)'))
 | 
			
		||||
        return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
      eq(
 | 
			
		||||
        true,
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          return vim.lsp.buf_is_attached(0, client_id)
 | 
			
		||||
        end)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      insert(text)
 | 
			
		||||
 | 
			
		||||
@@ -599,10 +603,8 @@ describe('semantic token highlighting', function()
 | 
			
		||||
 | 
			
		||||
    it('does not send delta requests if not supported by server', function()
 | 
			
		||||
      insert(text)
 | 
			
		||||
      exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        local legend, response, edit_response = ...
 | 
			
		||||
        server2 = _create_server({
 | 
			
		||||
      exec_lua(function()
 | 
			
		||||
        _G.server2 = _G._create_server({
 | 
			
		||||
          capabilities = {
 | 
			
		||||
            semanticTokensProvider = {
 | 
			
		||||
              full = { delta = false },
 | 
			
		||||
@@ -616,16 +618,10 @@ describe('semantic token highlighting', function()
 | 
			
		||||
            ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
 | 
			
		||||
              callback(nil, vim.fn.json_decode(edit_response))
 | 
			
		||||
            end,
 | 
			
		||||
          }
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
        bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
        vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
        client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd })
 | 
			
		||||
      ]],
 | 
			
		||||
        legend,
 | 
			
		||||
        response,
 | 
			
		||||
        edit_response
 | 
			
		||||
      )
 | 
			
		||||
        return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      screen:expect {
 | 
			
		||||
        grid = [[
 | 
			
		||||
@@ -670,7 +666,9 @@ describe('semantic token highlighting', function()
 | 
			
		||||
      }
 | 
			
		||||
      local messages = exec_lua('return server2.messages')
 | 
			
		||||
      local token_request_count = 0
 | 
			
		||||
      for _, message in ipairs(messages) do
 | 
			
		||||
      for _, message in
 | 
			
		||||
        ipairs(messages --[[@as {method:string,params:table}[] ]])
 | 
			
		||||
      do
 | 
			
		||||
        assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
 | 
			
		||||
        if message.method == 'textDocument/semanticTokens/full' then
 | 
			
		||||
          token_request_count = token_request_count + 1
 | 
			
		||||
@@ -1065,10 +1063,8 @@ b = "as"]],
 | 
			
		||||
    }) do
 | 
			
		||||
      it(test.it, function()
 | 
			
		||||
        exec_lua(create_server_definition)
 | 
			
		||||
        exec_lua(
 | 
			
		||||
          [[
 | 
			
		||||
          local legend, resp = ...
 | 
			
		||||
          server = _create_server({
 | 
			
		||||
        local client_id = exec_lua(function(legend, resp)
 | 
			
		||||
          _G.server = _G._create_server({
 | 
			
		||||
            capabilities = {
 | 
			
		||||
              semanticTokensProvider = {
 | 
			
		||||
                full = { delta = false },
 | 
			
		||||
@@ -1079,25 +1075,22 @@ b = "as"]],
 | 
			
		||||
              ['textDocument/semanticTokens/full'] = function(_, _, callback)
 | 
			
		||||
                callback(nil, vim.fn.json_decode(resp))
 | 
			
		||||
              end,
 | 
			
		||||
            }
 | 
			
		||||
            },
 | 
			
		||||
          })
 | 
			
		||||
          bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
          vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
          client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
        ]],
 | 
			
		||||
          test.legend,
 | 
			
		||||
          test.response
 | 
			
		||||
        )
 | 
			
		||||
          return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
 | 
			
		||||
        end, test.legend, test.response)
 | 
			
		||||
 | 
			
		||||
        insert(test.text)
 | 
			
		||||
 | 
			
		||||
        test.expected_screen()
 | 
			
		||||
 | 
			
		||||
        local highlights = exec_lua([[
 | 
			
		||||
          local semantic_tokens = vim.lsp.semantic_tokens
 | 
			
		||||
          return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
 | 
			
		||||
        ]])
 | 
			
		||||
        eq(test.expected, highlights)
 | 
			
		||||
        eq(
 | 
			
		||||
          test.expected,
 | 
			
		||||
          exec_lua(function()
 | 
			
		||||
            local bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
            return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
 | 
			
		||||
          end)
 | 
			
		||||
        )
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
  end)
 | 
			
		||||
@@ -1450,12 +1443,11 @@ int main()
 | 
			
		||||
      },
 | 
			
		||||
    }) do
 | 
			
		||||
      it(test.it, function()
 | 
			
		||||
        local bufnr = n.api.nvim_get_current_buf()
 | 
			
		||||
        insert(test.text1)
 | 
			
		||||
        exec_lua(create_server_definition)
 | 
			
		||||
        exec_lua(
 | 
			
		||||
          [[
 | 
			
		||||
          local legend, resp1, resp2 = ...
 | 
			
		||||
          server = _create_server({
 | 
			
		||||
        local client_id = exec_lua(function(legend, resp1, resp2)
 | 
			
		||||
          _G.server = _G._create_server({
 | 
			
		||||
            capabilities = {
 | 
			
		||||
              semanticTokensProvider = {
 | 
			
		||||
                full = { delta = true },
 | 
			
		||||
@@ -1469,52 +1461,44 @@ int main()
 | 
			
		||||
              ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
 | 
			
		||||
                callback(nil, vim.fn.json_decode(resp2))
 | 
			
		||||
              end,
 | 
			
		||||
            }
 | 
			
		||||
            },
 | 
			
		||||
          })
 | 
			
		||||
          bufnr = vim.api.nvim_get_current_buf()
 | 
			
		||||
          vim.api.nvim_win_set_buf(0, bufnr)
 | 
			
		||||
          client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
 | 
			
		||||
          local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }))
 | 
			
		||||
 | 
			
		||||
          -- speed up vim.api.nvim_buf_set_lines calls by changing debounce to 10 for these tests
 | 
			
		||||
          semantic_tokens = vim.lsp.semantic_tokens
 | 
			
		||||
          vim.schedule(function()
 | 
			
		||||
            semantic_tokens.stop(bufnr, client_id)
 | 
			
		||||
            semantic_tokens.start(bufnr, client_id, { debounce = 10 })
 | 
			
		||||
            vim.lsp.semantic_tokens.stop(bufnr, client_id)
 | 
			
		||||
            vim.lsp.semantic_tokens.start(bufnr, client_id, { debounce = 10 })
 | 
			
		||||
          end)
 | 
			
		||||
        ]],
 | 
			
		||||
          test.legend,
 | 
			
		||||
          test.response1,
 | 
			
		||||
          test.response2
 | 
			
		||||
        )
 | 
			
		||||
          return client_id
 | 
			
		||||
        end, test.legend, test.response1, test.response2)
 | 
			
		||||
 | 
			
		||||
        test.expected_screen1()
 | 
			
		||||
 | 
			
		||||
        local highlights = exec_lua([[
 | 
			
		||||
          return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
 | 
			
		||||
        ]])
 | 
			
		||||
 | 
			
		||||
        eq(test.expected1, highlights)
 | 
			
		||||
        eq(
 | 
			
		||||
          test.expected1,
 | 
			
		||||
          exec_lua(function()
 | 
			
		||||
            return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
 | 
			
		||||
          end)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if test.edit then
 | 
			
		||||
          feed(test.edit)
 | 
			
		||||
        else
 | 
			
		||||
          exec_lua(
 | 
			
		||||
            [[
 | 
			
		||||
            local text = ...
 | 
			
		||||
            vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, "\n"))
 | 
			
		||||
          exec_lua(function(text)
 | 
			
		||||
            vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, '\n'))
 | 
			
		||||
            vim.wait(15) -- wait for debounce
 | 
			
		||||
          ]],
 | 
			
		||||
            test.text2
 | 
			
		||||
          )
 | 
			
		||||
          end, test.text2)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        test.expected_screen2()
 | 
			
		||||
 | 
			
		||||
        highlights = exec_lua([[
 | 
			
		||||
          return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
 | 
			
		||||
        ]])
 | 
			
		||||
 | 
			
		||||
        eq(test.expected2, highlights)
 | 
			
		||||
        eq(
 | 
			
		||||
          test.expected2,
 | 
			
		||||
          exec_lua(function()
 | 
			
		||||
            return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
 | 
			
		||||
          end)
 | 
			
		||||
        )
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -108,20 +108,21 @@ M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua'
 | 
			
		||||
M.fake_lsp_logfile = 'Xtest-fake-lsp.log'
 | 
			
		||||
 | 
			
		||||
local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
 | 
			
		||||
  exec_lua(
 | 
			
		||||
    function(test_name0, fake_lsp_code0, fake_lsp_logfile0, timeout, options0, settings0)
 | 
			
		||||
  exec_lua(function(fake_lsp_code, fake_lsp_logfile, timeout)
 | 
			
		||||
    options = options or {}
 | 
			
		||||
    settings = settings or {}
 | 
			
		||||
    _G.lsp = require('vim.lsp')
 | 
			
		||||
    _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client {
 | 
			
		||||
      cmd_env = {
 | 
			
		||||
          NVIM_LOG_FILE = fake_lsp_logfile0,
 | 
			
		||||
        NVIM_LOG_FILE = fake_lsp_logfile,
 | 
			
		||||
        NVIM_LUA_NOTRACK = '1',
 | 
			
		||||
        NVIM_APPNAME = 'nvim_lsp_test',
 | 
			
		||||
      },
 | 
			
		||||
      cmd = {
 | 
			
		||||
        vim.v.progpath,
 | 
			
		||||
        '-l',
 | 
			
		||||
          fake_lsp_code0,
 | 
			
		||||
          test_name0,
 | 
			
		||||
        fake_lsp_code,
 | 
			
		||||
        test_name,
 | 
			
		||||
        tostring(timeout),
 | 
			
		||||
      },
 | 
			
		||||
      handlers = setmetatable({}, {
 | 
			
		||||
@@ -147,22 +148,15 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
 | 
			
		||||
        vim.rpcrequest(1, 'init', result)
 | 
			
		||||
      end,
 | 
			
		||||
      flags = {
 | 
			
		||||
          allow_incremental_sync = options0.allow_incremental_sync or false,
 | 
			
		||||
          debounce_text_changes = options0.debounce_text_changes or 0,
 | 
			
		||||
        allow_incremental_sync = options.allow_incremental_sync or false,
 | 
			
		||||
        debounce_text_changes = options.debounce_text_changes or 0,
 | 
			
		||||
      },
 | 
			
		||||
        settings = settings0,
 | 
			
		||||
      settings = settings,
 | 
			
		||||
      on_exit = function(...)
 | 
			
		||||
        vim.rpcnotify(1, 'exit', ...)
 | 
			
		||||
      end,
 | 
			
		||||
    }
 | 
			
		||||
    end,
 | 
			
		||||
    test_name,
 | 
			
		||||
    M.fake_lsp_code,
 | 
			
		||||
    M.fake_lsp_logfile,
 | 
			
		||||
    timeout_ms or 1e3,
 | 
			
		||||
    options or {},
 | 
			
		||||
    settings or {}
 | 
			
		||||
  )
 | 
			
		||||
  end, M.fake_lsp_code, M.fake_lsp_logfile, timeout_ms or 1e3)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @class test.lsp.Config
 | 
			
		||||
@@ -193,13 +187,12 @@ function M.test_rpc_server(config)
 | 
			
		||||
      -- Otherwise I would just return the value here.
 | 
			
		||||
      return function(...)
 | 
			
		||||
        return exec_lua(function(...)
 | 
			
		||||
          local name0 = ...
 | 
			
		||||
          if type(_G.TEST_RPC_CLIENT[name0]) == 'function' then
 | 
			
		||||
            return _G.TEST_RPC_CLIENT[name0](select(2, ...))
 | 
			
		||||
          if type(_G.TEST_RPC_CLIENT[name]) == 'function' then
 | 
			
		||||
            return _G.TEST_RPC_CLIENT[name](...)
 | 
			
		||||
          else
 | 
			
		||||
            return _G.TEST_RPC_CLIENT[name0]
 | 
			
		||||
            return _G.TEST_RPC_CLIENT[name]
 | 
			
		||||
          end
 | 
			
		||||
        end, name, ...)
 | 
			
		||||
        end, ...)
 | 
			
		||||
      end
 | 
			
		||||
    end,
 | 
			
		||||
  })
 | 
			
		||||
 
 | 
			
		||||
@@ -11,21 +11,11 @@ describe('vim.lsp.util', function()
 | 
			
		||||
 | 
			
		||||
  describe('stylize_markdown', function()
 | 
			
		||||
    local stylize_markdown = function(content, opts)
 | 
			
		||||
      return exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
        local bufnr = vim.uri_to_bufnr("file:///fake/uri")
 | 
			
		||||
      return exec_lua(function()
 | 
			
		||||
        local bufnr = vim.uri_to_bufnr('file:///fake/uri')
 | 
			
		||||
        vim.fn.bufload(bufnr)
 | 
			
		||||
 | 
			
		||||
        local args = { ... }
 | 
			
		||||
        local content = args[1]
 | 
			
		||||
        local opts = args[2]
 | 
			
		||||
        local stripped_content = vim.lsp.util.stylize_markdown(bufnr, content, opts)
 | 
			
		||||
 | 
			
		||||
        return stripped_content
 | 
			
		||||
      ]],
 | 
			
		||||
        content,
 | 
			
		||||
        opts
 | 
			
		||||
      )
 | 
			
		||||
        return vim.lsp.util.stylize_markdown(bufnr, content, opts)
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it('code fences', function()
 | 
			
		||||
@@ -95,7 +85,7 @@ describe('vim.lsp.util', function()
 | 
			
		||||
 | 
			
		||||
  describe('normalize_markdown', function()
 | 
			
		||||
    it('collapses consecutive blank lines', function()
 | 
			
		||||
      local result = exec_lua [[
 | 
			
		||||
      local result = exec_lua(function()
 | 
			
		||||
        local lines = {
 | 
			
		||||
          'foo',
 | 
			
		||||
          '',
 | 
			
		||||
@@ -103,25 +93,25 @@ describe('vim.lsp.util', function()
 | 
			
		||||
          '',
 | 
			
		||||
          'bar',
 | 
			
		||||
          '',
 | 
			
		||||
          'baz'
 | 
			
		||||
          'baz',
 | 
			
		||||
        }
 | 
			
		||||
        return vim.lsp.util._normalize_markdown(lines)
 | 
			
		||||
      ]]
 | 
			
		||||
      end)
 | 
			
		||||
      local expected = { 'foo', '', 'bar', '', 'baz' }
 | 
			
		||||
      eq(expected, result)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('removes preceding and trailing empty lines', function()
 | 
			
		||||
      local result = exec_lua [[
 | 
			
		||||
      local result = exec_lua(function()
 | 
			
		||||
        local lines = {
 | 
			
		||||
          '',
 | 
			
		||||
          'foo',
 | 
			
		||||
          'bar',
 | 
			
		||||
          '',
 | 
			
		||||
          ''
 | 
			
		||||
          '',
 | 
			
		||||
        }
 | 
			
		||||
        return vim.lsp.util._normalize_markdown(lines)
 | 
			
		||||
      ]]
 | 
			
		||||
      end)
 | 
			
		||||
      local expected = { 'foo', 'bar' }
 | 
			
		||||
      eq(expected, result)
 | 
			
		||||
    end)
 | 
			
		||||
@@ -129,19 +119,14 @@ describe('vim.lsp.util', function()
 | 
			
		||||
 | 
			
		||||
  describe('make_floating_popup_options', function()
 | 
			
		||||
    local function assert_anchor(anchor_bias, expected_anchor)
 | 
			
		||||
      local opts = exec_lua(
 | 
			
		||||
        [[
 | 
			
		||||
          local args = { ... }
 | 
			
		||||
          local anchor_bias = args[1]
 | 
			
		||||
      local opts = exec_lua(function()
 | 
			
		||||
        return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
 | 
			
		||||
        ]],
 | 
			
		||||
        anchor_bias
 | 
			
		||||
      )
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      eq(expected_anchor, string.sub(opts.anchor, 1, 1))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local screen
 | 
			
		||||
    local screen --- @type test.functional.ui.screen
 | 
			
		||||
    before_each(function()
 | 
			
		||||
      n.clear()
 | 
			
		||||
      screen = Screen.new(80, 80)
 | 
			
		||||
@@ -221,9 +206,9 @@ describe('vim.lsp.util', function()
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      it('bordered window truncates dimensions correctly', function()
 | 
			
		||||
        local opts = exec_lua([[
 | 
			
		||||
        local opts = exec_lua(function()
 | 
			
		||||
          return vim.lsp.util.make_floating_popup_options(100, 100, { border = 'single' })
 | 
			
		||||
        ]])
 | 
			
		||||
        end)
 | 
			
		||||
 | 
			
		||||
        eq(56, opts.height)
 | 
			
		||||
      end)
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -16,21 +16,20 @@ local is_ci = t.is_ci
 | 
			
		||||
 | 
			
		||||
-- Collects all names passed to find_path() after attempting ":Man foo".
 | 
			
		||||
local function get_search_history(name)
 | 
			
		||||
  return exec_lua(function()
 | 
			
		||||
    local args = vim.split(name, ' ')
 | 
			
		||||
  local code = [[
 | 
			
		||||
    local args = ...
 | 
			
		||||
    local man = require('man')
 | 
			
		||||
    local res = {}
 | 
			
		||||
    man.find_path = function(sect, name)
 | 
			
		||||
      table.insert(res, {sect, name})
 | 
			
		||||
    --- @diagnostic disable-next-line:duplicate-set-field
 | 
			
		||||
    man.find_path = function(sect, name0)
 | 
			
		||||
      table.insert(res, { sect, name0 })
 | 
			
		||||
      return nil
 | 
			
		||||
    end
 | 
			
		||||
    local ok, rv = pcall(man.open_page, -1, { tab = 0 }, args)
 | 
			
		||||
    assert(not ok)
 | 
			
		||||
    assert(rv and rv:match('no manual entry'))
 | 
			
		||||
    return res
 | 
			
		||||
  ]]
 | 
			
		||||
  return exec_lua(code, args)
 | 
			
		||||
  end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
clear()
 | 
			
		||||
 
 | 
			
		||||
@@ -210,9 +210,7 @@ describe(':TOhtml', function()
 | 
			
		||||
    exec('set termguicolors')
 | 
			
		||||
    local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
 | 
			
		||||
    local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
 | 
			
		||||
    exec_lua [[
 | 
			
		||||
    local html = vim.cmd'2,2TOhtml'
 | 
			
		||||
    ]]
 | 
			
		||||
    n.command('2,2TOhtml')
 | 
			
		||||
    local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
 | 
			
		||||
    eq({
 | 
			
		||||
      '<!DOCTYPE html>',
 | 
			
		||||
@@ -408,12 +406,12 @@ describe(':TOhtml', function()
 | 
			
		||||
    local function run()
 | 
			
		||||
      local buf = api.nvim_get_current_buf()
 | 
			
		||||
      run_tohtml_and_assert(screen, function()
 | 
			
		||||
        exec_lua [[
 | 
			
		||||
        exec_lua(function()
 | 
			
		||||
          local outfile = vim.fn.tempname() .. '.html'
 | 
			
		||||
          local html = require('tohtml').tohtml(0, { number_lines = true })
 | 
			
		||||
          vim.fn.writefile(html, outfile)
 | 
			
		||||
          vim.cmd.split(outfile)
 | 
			
		||||
        ]]
 | 
			
		||||
        end)
 | 
			
		||||
      end)
 | 
			
		||||
      api.nvim_set_current_buf(buf)
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -837,21 +837,173 @@ function M.exec_capture(code)
 | 
			
		||||
  return M.api.nvim_exec2(code, { output = true }).output
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @param code string|function
 | 
			
		||||
--- @return any
 | 
			
		||||
function M.exec_lua(code, ...)
 | 
			
		||||
  if type(code) == 'function' then
 | 
			
		||||
    return M.api.nvim_exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      local code = ...
 | 
			
		||||
      return loadstring(code)(select(2, ...))
 | 
			
		||||
    ]],
 | 
			
		||||
      { string.dump(code), ... }
 | 
			
		||||
--- @param f function
 | 
			
		||||
--- @return table<string,any>
 | 
			
		||||
local function get_upvalues(f)
 | 
			
		||||
  local i = 1
 | 
			
		||||
  local upvalues = {} --- @type table<string,any>
 | 
			
		||||
  while true do
 | 
			
		||||
    local n, v = debug.getupvalue(f, i)
 | 
			
		||||
    if not n then
 | 
			
		||||
      break
 | 
			
		||||
    end
 | 
			
		||||
    upvalues[n] = v
 | 
			
		||||
    i = i + 1
 | 
			
		||||
  end
 | 
			
		||||
  return upvalues
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @param f function
 | 
			
		||||
--- @param upvalues table<string,any>
 | 
			
		||||
local function set_upvalues(f, upvalues)
 | 
			
		||||
  local i = 1
 | 
			
		||||
  while true do
 | 
			
		||||
    local n = debug.getupvalue(f, i)
 | 
			
		||||
    if not n then
 | 
			
		||||
      break
 | 
			
		||||
    end
 | 
			
		||||
    if upvalues[n] then
 | 
			
		||||
      debug.setupvalue(f, i, upvalues[n])
 | 
			
		||||
    end
 | 
			
		||||
    i = i + 1
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @type fun(f: function): table<string,any>
 | 
			
		||||
_G.__get_upvalues = nil
 | 
			
		||||
 | 
			
		||||
--- @type fun(f: function, upvalues: table<string,any>)
 | 
			
		||||
_G.__set_upvalues = nil
 | 
			
		||||
 | 
			
		||||
--- @param self table<string,function>
 | 
			
		||||
--- @param bytecode string
 | 
			
		||||
--- @param upvalues table<string,any>
 | 
			
		||||
--- @param ... any[]
 | 
			
		||||
--- @return any[] result
 | 
			
		||||
--- @return table<string,any> upvalues
 | 
			
		||||
local function exec_lua_handler(self, bytecode, upvalues, ...)
 | 
			
		||||
  local f = assert(loadstring(bytecode))
 | 
			
		||||
  self.set_upvalues(f, upvalues)
 | 
			
		||||
  local ret = { f(...) } --- @type any[]
 | 
			
		||||
  --- @type table<string,any>
 | 
			
		||||
  local new_upvalues = self.get_upvalues(f)
 | 
			
		||||
 | 
			
		||||
  do -- Check return value types for better error messages
 | 
			
		||||
    local invalid_types = {
 | 
			
		||||
      ['thread'] = true,
 | 
			
		||||
      ['function'] = true,
 | 
			
		||||
      ['userdata'] = true,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for k, v in pairs(ret) do
 | 
			
		||||
      if invalid_types[type(v)] then
 | 
			
		||||
        error(
 | 
			
		||||
          string.format(
 | 
			
		||||
            "Return index %d with value '%s' of type '%s' cannot be serialized over RPC",
 | 
			
		||||
            k,
 | 
			
		||||
            tostring(v),
 | 
			
		||||
            type(v)
 | 
			
		||||
          )
 | 
			
		||||
        )
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  return ret, new_upvalues
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- Execute Lua code in the wrapped Nvim session.
 | 
			
		||||
---
 | 
			
		||||
--- When `code` is passed as a function, it is converted into Lua byte code.
 | 
			
		||||
---
 | 
			
		||||
--- Direct upvalues are copied over, however upvalues contained
 | 
			
		||||
--- within nested functions are not. Upvalues are also copied back when `code`
 | 
			
		||||
--- finishes executing. See `:help lua-upvalue`.
 | 
			
		||||
---
 | 
			
		||||
--- Only types which can be serialized can be transferred over, e.g:
 | 
			
		||||
--- `table`, `number`, `boolean`, `string`.
 | 
			
		||||
---
 | 
			
		||||
--- `code` runs with a different environment and thus will have a different global
 | 
			
		||||
--- environment. See `:help lua-environments`.
 | 
			
		||||
---
 | 
			
		||||
--- Example:
 | 
			
		||||
--- ```lua
 | 
			
		||||
--- local upvalue1 = 'upvalue1'
 | 
			
		||||
--- exec_lua(function(a, b, c)
 | 
			
		||||
---   print(upvalue1, a, b, c)
 | 
			
		||||
---   (function()
 | 
			
		||||
---     print(upvalue2)
 | 
			
		||||
---   end)()
 | 
			
		||||
--- end, 'a', 'b', 'c'
 | 
			
		||||
--- ```
 | 
			
		||||
--- Prints:
 | 
			
		||||
--- ```
 | 
			
		||||
--- upvalue1 a b c
 | 
			
		||||
--- nil
 | 
			
		||||
--- ```
 | 
			
		||||
---
 | 
			
		||||
--- Not supported:
 | 
			
		||||
--- ```lua
 | 
			
		||||
--- local a = vim.uv.new_timer()
 | 
			
		||||
--- exec_lua(function()
 | 
			
		||||
---   print(a) -- Error: a is of type 'userdata' which cannot be serialized.
 | 
			
		||||
--- end)
 | 
			
		||||
--- ```
 | 
			
		||||
--- @param code string|function
 | 
			
		||||
--- @param ... any
 | 
			
		||||
--- @return any
 | 
			
		||||
function M.exec_lua(code, ...)
 | 
			
		||||
  if type(code) == 'string' then
 | 
			
		||||
    return M.api.nvim_exec_lua(code, { ... })
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  assert(session)
 | 
			
		||||
 | 
			
		||||
  if not session.exec_lua_setup then
 | 
			
		||||
    M.api.nvim_exec_lua(
 | 
			
		||||
      [[
 | 
			
		||||
      _G.__test_exec_lua = {
 | 
			
		||||
        get_upvalues = loadstring((select(1,...))),
 | 
			
		||||
        set_upvalues = loadstring((select(2,...))),
 | 
			
		||||
        handler = loadstring((select(3,...)))
 | 
			
		||||
      }
 | 
			
		||||
      setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua })
 | 
			
		||||
    ]],
 | 
			
		||||
      { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) }
 | 
			
		||||
    )
 | 
			
		||||
    session.exec_lua_setup = true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  --- @type any[], table<string,any>
 | 
			
		||||
  local ret, upvalues = unpack(M.api.nvim_exec_lua(
 | 
			
		||||
    [[
 | 
			
		||||
      return {
 | 
			
		||||
        _G.__test_exec_lua:handler(...)
 | 
			
		||||
      }
 | 
			
		||||
    ]],
 | 
			
		||||
    {
 | 
			
		||||
      string.dump(code),
 | 
			
		||||
      get_upvalues(code),
 | 
			
		||||
      ...,
 | 
			
		||||
    }
 | 
			
		||||
  ))
 | 
			
		||||
 | 
			
		||||
  -- Update upvalues
 | 
			
		||||
  if next(upvalues) then
 | 
			
		||||
    local caller = debug.getinfo(2)
 | 
			
		||||
    local f = caller.func
 | 
			
		||||
    -- On PUC-Lua, if the function is a tail call, then func will be nil.
 | 
			
		||||
    -- In this case we need to use the current function.
 | 
			
		||||
    if not f then
 | 
			
		||||
      assert(caller.source == '=(tail call)')
 | 
			
		||||
      f = debug.getinfo(1).func
 | 
			
		||||
    end
 | 
			
		||||
    set_upvalues(f, upvalues)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  return unpack(ret, 1, table.maxn(ret))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function M.get_pathsep()
 | 
			
		||||
  return is_os('win') and '\\' or '/'
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -187,10 +187,10 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
    -- legacy syntax highlighting is used by default
 | 
			
		||||
    screen:expect(hl_grid_legacy_c)
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
      vim.treesitter.query.set('c', 'highlights', hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.treesitter.query.set('c', 'highlights', hl_query_c)
 | 
			
		||||
      vim.treesitter.start()
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
    end)
 | 
			
		||||
    -- treesitter highlighting is used
 | 
			
		||||
    screen:expect(hl_grid_ts_c)
 | 
			
		||||
 | 
			
		||||
@@ -238,11 +238,11 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
    ]],
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c')
 | 
			
		||||
      local highlighter = vim.treesitter.highlighter
 | 
			
		||||
      highlighter.new(parser, { queries = { c = hl_query } })
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
      highlighter.new(parser, { queries = { c = hl_query_c } })
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect(hl_grid_ts_c)
 | 
			
		||||
 | 
			
		||||
    feed('5Goc<esc>dd')
 | 
			
		||||
@@ -369,10 +369,10 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
 | 
			
		||||
  it('is updated with :sort', function()
 | 
			
		||||
    insert(test_text_c)
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c')
 | 
			
		||||
      vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } })
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
      vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
 | 
			
		||||
    end)
 | 
			
		||||
    screen:expect {
 | 
			
		||||
      grid = [[
 | 
			
		||||
        {3:int} width = {5:INT_MAX}, height = {5:INT_MAX};                         |
 | 
			
		||||
@@ -518,15 +518,15 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
 | 
			
		||||
    screen:expect { grid = injection_grid_c }
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c', {
 | 
			
		||||
        injections = {
 | 
			
		||||
          c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))',
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
      local highlighter = vim.treesitter.highlighter
 | 
			
		||||
      highlighter.new(parser, { queries = { c = hl_query } })
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
      highlighter.new(parser, { queries = { c = hl_query_c } })
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    screen:expect { grid = injection_grid_expected_c }
 | 
			
		||||
  end)
 | 
			
		||||
@@ -536,7 +536,7 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
 | 
			
		||||
    screen:expect { grid = injection_grid_c }
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.treesitter.language.register('c', 'foo')
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c', {
 | 
			
		||||
        injections = {
 | 
			
		||||
@@ -544,8 +544,8 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
      local highlighter = vim.treesitter.highlighter
 | 
			
		||||
      highlighter.new(parser, { queries = { c = hl_query } })
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
      highlighter.new(parser, { queries = { c = hl_query_c } })
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    screen:expect { grid = injection_grid_expected_c }
 | 
			
		||||
  end)
 | 
			
		||||
@@ -559,14 +559,14 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
                }
 | 
			
		||||
    ]])
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local injection_query =
 | 
			
		||||
        '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
 | 
			
		||||
      vim.treesitter.query.set('c', 'highlights', hl_query)
 | 
			
		||||
      vim.treesitter.query.set('c', 'highlights', hl_query_c)
 | 
			
		||||
      vim.treesitter.query.set('c', 'injections', injection_query)
 | 
			
		||||
 | 
			
		||||
      vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    screen:expect {
 | 
			
		||||
      grid = [[
 | 
			
		||||
@@ -586,10 +586,10 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
    insert(hl_text_c)
 | 
			
		||||
    feed('gg')
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c')
 | 
			
		||||
      vim.treesitter.highlighter.new(parser, { queries = { c = hl_query } })
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
      vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    screen:expect(hl_grid_ts_c)
 | 
			
		||||
 | 
			
		||||
@@ -629,14 +629,14 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
                }
 | 
			
		||||
    ]])
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(hl_query)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c')
 | 
			
		||||
      vim.treesitter.highlighter.new(parser, {
 | 
			
		||||
        queries = {
 | 
			
		||||
          c = hl_query .. '\n((translation_unit) @constant (#set! "priority" 101))\n',
 | 
			
		||||
          c = hl_query_c .. '\n((translation_unit) @constant (#set! "priority" 101))\n',
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
    end, hl_query_c)
 | 
			
		||||
    end)
 | 
			
		||||
    -- expect everything to have Constant highlight
 | 
			
		||||
    screen:expect {
 | 
			
		||||
      grid = [[
 | 
			
		||||
@@ -826,10 +826,10 @@ describe('treesitter highlighting (C)', function()
 | 
			
		||||
        declarator: (pointer_declarator) @variable.parameter)
 | 
			
		||||
    ]]
 | 
			
		||||
 | 
			
		||||
    exec_lua(function(query_str)
 | 
			
		||||
      vim.treesitter.query.set('c', 'highlights', query_str)
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.treesitter.query.set('c', 'highlights', query)
 | 
			
		||||
      vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
 | 
			
		||||
    end, query)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    screen:expect {
 | 
			
		||||
      grid = [[
 | 
			
		||||
 
 | 
			
		||||
@@ -156,10 +156,10 @@ describe('vim.treesitter.inspect_tree', function()
 | 
			
		||||
    eq('', n.api.nvim_get_vvar('errmsg'))
 | 
			
		||||
 | 
			
		||||
    -- close original tree window
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
       vim.api.nvim_set_current_win(tree_win_copy_1)
 | 
			
		||||
       vim.api.nvim_win_close(tree_win, false)
 | 
			
		||||
    ]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      vim.api.nvim_set_current_win(_G.tree_win_copy_1)
 | 
			
		||||
      vim.api.nvim_win_close(_G.tree_win, false)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    -- navigates correctly to the remaining source buffer window
 | 
			
		||||
    feed('<CR>')
 | 
			
		||||
 
 | 
			
		||||
@@ -166,10 +166,10 @@ describe('treesitter language API', function()
 | 
			
		||||
  it('retrieve an anonymous node given a range', function()
 | 
			
		||||
    insert([[vim.fn.input()]])
 | 
			
		||||
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      langtree = vim.treesitter.get_parser(0, "lua")
 | 
			
		||||
      node = langtree:node_for_range({0, 3, 0, 3})
 | 
			
		||||
    ]])
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      _G.langtree = vim.treesitter.get_parser(0, 'lua')
 | 
			
		||||
      _G.node = _G.langtree:node_for_range({ 0, 3, 0, 3 })
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq('.', exec_lua('return node:type()'))
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -58,15 +58,15 @@ describe('treesitter node API', function()
 | 
			
		||||
  it('get_node() with anonymous nodes included', function()
 | 
			
		||||
    insert([[print('test')]])
 | 
			
		||||
 | 
			
		||||
    exec_lua([[
 | 
			
		||||
      parser = vim.treesitter.get_parser(0, 'lua')
 | 
			
		||||
      tree = parser:parse()[1]
 | 
			
		||||
      node = vim.treesitter.get_node({
 | 
			
		||||
    exec_lua(function()
 | 
			
		||||
      _G.parser = vim.treesitter.get_parser(0, 'lua')
 | 
			
		||||
      _G.tree = _G.parser:parse()[1]
 | 
			
		||||
      _G.node = vim.treesitter.get_node({
 | 
			
		||||
        bufnr = 0,
 | 
			
		||||
        pos = { 0, 6 }, -- on the first apostrophe
 | 
			
		||||
        include_anonymous = true,
 | 
			
		||||
      })
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq("'", lua_eval('node:type()'))
 | 
			
		||||
    eq(false, lua_eval('node:named()'))
 | 
			
		||||
@@ -120,7 +120,7 @@ describe('treesitter node API', function()
 | 
			
		||||
 | 
			
		||||
    local len = exec_lua(function()
 | 
			
		||||
      local tree = vim.treesitter.get_parser(0, 'c'):parse()[1]
 | 
			
		||||
      local node = tree:root():child(0)
 | 
			
		||||
      local node = assert(tree:root():child(0))
 | 
			
		||||
      _G.children = node:named_children()
 | 
			
		||||
 | 
			
		||||
      return #_G.children
 | 
			
		||||
 
 | 
			
		||||
@@ -660,8 +660,8 @@ print()
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    local function run_query()
 | 
			
		||||
      return exec_lua(function(query_str)
 | 
			
		||||
        local query = vim.treesitter.query.parse('c', query_str)
 | 
			
		||||
      return exec_lua(function()
 | 
			
		||||
        local query = vim.treesitter.query.parse('c', query0)
 | 
			
		||||
        local parser = vim.treesitter.get_parser()
 | 
			
		||||
        local tree = parser:parse()[1]
 | 
			
		||||
        local res = {}
 | 
			
		||||
@@ -669,7 +669,7 @@ print()
 | 
			
		||||
          table.insert(res, { query.captures[id], node:range() })
 | 
			
		||||
        end
 | 
			
		||||
        return res
 | 
			
		||||
      end, query0)
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    eq({
 | 
			
		||||
@@ -707,15 +707,15 @@ print()
 | 
			
		||||
      ]]
 | 
			
		||||
    ]==]
 | 
			
		||||
 | 
			
		||||
    local r = exec_lua(function(src)
 | 
			
		||||
      local parser = vim.treesitter.get_string_parser(src, 'lua')
 | 
			
		||||
    local r = exec_lua(function()
 | 
			
		||||
      local parser = vim.treesitter.get_string_parser(source, 'lua')
 | 
			
		||||
      parser:parse(true)
 | 
			
		||||
      local ranges = {}
 | 
			
		||||
      parser:for_each_tree(function(tstree, tree)
 | 
			
		||||
        ranges[tree:lang()] = { tstree:root():range(true) }
 | 
			
		||||
      end)
 | 
			
		||||
      return ranges
 | 
			
		||||
    end, source)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq({
 | 
			
		||||
      lua = { 0, 6, 6, 16, 4, 438 },
 | 
			
		||||
@@ -727,14 +727,14 @@ print()
 | 
			
		||||
    -- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure
 | 
			
		||||
    -- add_bytes() produces the same result.
 | 
			
		||||
 | 
			
		||||
    local rb = exec_lua(function(r0, source0)
 | 
			
		||||
    local rb = exec_lua(function()
 | 
			
		||||
      local add_bytes = require('vim.treesitter._range').add_bytes
 | 
			
		||||
      for lang, range in pairs(r0) do
 | 
			
		||||
        r0[lang] = { range[1], range[2], range[4], range[5] }
 | 
			
		||||
        r0[lang] = add_bytes(source0, r0[lang])
 | 
			
		||||
      for lang, range in pairs(r) do
 | 
			
		||||
        r[lang] = { range[1], range[2], range[4], range[5] }
 | 
			
		||||
        r[lang] = add_bytes(source, r[lang])
 | 
			
		||||
      end
 | 
			
		||||
      return r0
 | 
			
		||||
    end, r, source)
 | 
			
		||||
      return r
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq(rb, r)
 | 
			
		||||
  end)
 | 
			
		||||
 
 | 
			
		||||
@@ -82,17 +82,17 @@ void ui_refresh(void)
 | 
			
		||||
    local long_query = test_query:rep(100)
 | 
			
		||||
    ---@return number
 | 
			
		||||
    local function q(_n)
 | 
			
		||||
      return exec_lua(function(query, n0)
 | 
			
		||||
      return exec_lua(function()
 | 
			
		||||
        local before = vim.api.nvim__stats().ts_query_parse_count
 | 
			
		||||
        collectgarbage('stop')
 | 
			
		||||
        for _ = 1, n0, 1 do
 | 
			
		||||
          vim.treesitter.query.parse('c', query, n0)
 | 
			
		||||
        for _ = 1, _n, 1 do
 | 
			
		||||
          vim.treesitter.query.parse('c', long_query, _n)
 | 
			
		||||
        end
 | 
			
		||||
        collectgarbage('restart')
 | 
			
		||||
        collectgarbage('collect')
 | 
			
		||||
        local after = vim.api.nvim__stats().ts_query_parse_count
 | 
			
		||||
        return after - before
 | 
			
		||||
      end, long_query, _n)
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    eq(1, q(1))
 | 
			
		||||
@@ -103,8 +103,8 @@ void ui_refresh(void)
 | 
			
		||||
  it('supports query and iter by capture (iter_captures)', function()
 | 
			
		||||
    insert(test_text)
 | 
			
		||||
 | 
			
		||||
    local res = exec_lua(function(test_query0)
 | 
			
		||||
      local cquery = vim.treesitter.query.parse('c', test_query0)
 | 
			
		||||
    local res = exec_lua(function()
 | 
			
		||||
      local cquery = vim.treesitter.query.parse('c', test_query)
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c')
 | 
			
		||||
      local tree = parser:parse()[1]
 | 
			
		||||
      local res = {}
 | 
			
		||||
@@ -113,7 +113,7 @@ void ui_refresh(void)
 | 
			
		||||
        table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() })
 | 
			
		||||
      end
 | 
			
		||||
      return res
 | 
			
		||||
    end, test_query)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq({
 | 
			
		||||
      { '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool
 | 
			
		||||
@@ -133,8 +133,8 @@ void ui_refresh(void)
 | 
			
		||||
    insert(test_text)
 | 
			
		||||
 | 
			
		||||
    ---@type table
 | 
			
		||||
    local res = exec_lua(function(test_query0)
 | 
			
		||||
      local cquery = vim.treesitter.query.parse('c', test_query0)
 | 
			
		||||
    local res = exec_lua(function()
 | 
			
		||||
      local cquery = vim.treesitter.query.parse('c', test_query)
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c')
 | 
			
		||||
      local tree = parser:parse()[1]
 | 
			
		||||
      local res = {}
 | 
			
		||||
@@ -149,7 +149,7 @@ void ui_refresh(void)
 | 
			
		||||
        table.insert(res, { pattern, mrepr })
 | 
			
		||||
      end
 | 
			
		||||
      return res
 | 
			
		||||
    end, test_query)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq({
 | 
			
		||||
      { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } },
 | 
			
		||||
@@ -449,7 +449,7 @@ void ui_refresh(void)
 | 
			
		||||
    local custom_query = '((identifier) @main (#is-main? @main))'
 | 
			
		||||
 | 
			
		||||
    do
 | 
			
		||||
      local res = exec_lua(function(custom_query0)
 | 
			
		||||
      local res = exec_lua(function()
 | 
			
		||||
        local query = vim.treesitter.query
 | 
			
		||||
 | 
			
		||||
        local function is_main(match, _pattern, bufnr, predicate)
 | 
			
		||||
@@ -466,7 +466,7 @@ void ui_refresh(void)
 | 
			
		||||
 | 
			
		||||
        query.add_predicate('is-main?', is_main)
 | 
			
		||||
 | 
			
		||||
        local query0 = query.parse('c', custom_query0)
 | 
			
		||||
        local query0 = query.parse('c', custom_query)
 | 
			
		||||
 | 
			
		||||
        local nodes = {}
 | 
			
		||||
        for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
 | 
			
		||||
@@ -474,14 +474,14 @@ void ui_refresh(void)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        return nodes
 | 
			
		||||
      end, custom_query)
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      eq({ { 0, 4, 0, 8 } }, res)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- Once with the old API. Remove this whole 'do' block in 0.12
 | 
			
		||||
    do
 | 
			
		||||
      local res = exec_lua(function(custom_query0)
 | 
			
		||||
      local res = exec_lua(function()
 | 
			
		||||
        local query = vim.treesitter.query
 | 
			
		||||
 | 
			
		||||
        local function is_main(match, _pattern, bufnr, predicate)
 | 
			
		||||
@@ -494,7 +494,7 @@ void ui_refresh(void)
 | 
			
		||||
 | 
			
		||||
        query.add_predicate('is-main?', is_main, { all = false, force = true })
 | 
			
		||||
 | 
			
		||||
        local query0 = query.parse('c', custom_query0)
 | 
			
		||||
        local query0 = query.parse('c', custom_query)
 | 
			
		||||
 | 
			
		||||
        local nodes = {}
 | 
			
		||||
        for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
 | 
			
		||||
@@ -502,7 +502,7 @@ void ui_refresh(void)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        return nodes
 | 
			
		||||
      end, custom_query)
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      -- Remove this 'do' block in 0.12
 | 
			
		||||
      eq(0, fn.has('nvim-0.12'))
 | 
			
		||||
@@ -538,15 +538,15 @@ void ui_refresh(void)
 | 
			
		||||
 | 
			
		||||
    local function test(input, query)
 | 
			
		||||
      api.nvim_buf_set_lines(0, 0, -1, true, vim.split(dedent(input), '\n'))
 | 
			
		||||
      return exec_lua(function(query_str)
 | 
			
		||||
      return exec_lua(function()
 | 
			
		||||
        local parser = vim.treesitter.get_parser(0, 'lua')
 | 
			
		||||
        local query0 = vim.treesitter.query.parse('lua', query_str)
 | 
			
		||||
        local query0 = vim.treesitter.query.parse('lua', query)
 | 
			
		||||
        local nodes = {}
 | 
			
		||||
        for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
 | 
			
		||||
          nodes[#nodes + 1] = { node:range() }
 | 
			
		||||
        end
 | 
			
		||||
        return nodes
 | 
			
		||||
      end, query)
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    eq(
 | 
			
		||||
@@ -641,8 +641,8 @@ void ui_refresh(void)
 | 
			
		||||
    eq(0, fn.has('nvim-0.12'))
 | 
			
		||||
 | 
			
		||||
    insert(test_text)
 | 
			
		||||
    local res = exec_lua(function(test_query0)
 | 
			
		||||
      local cquery = vim.treesitter.query.parse('c', test_query0)
 | 
			
		||||
    local res = exec_lua(function()
 | 
			
		||||
      local cquery = vim.treesitter.query.parse('c', test_query)
 | 
			
		||||
      local parser = vim.treesitter.get_parser(0, 'c')
 | 
			
		||||
      local tree = parser:parse()[1]
 | 
			
		||||
      local res = {}
 | 
			
		||||
@@ -654,7 +654,7 @@ void ui_refresh(void)
 | 
			
		||||
        table.insert(res, { pattern, mrepr })
 | 
			
		||||
      end
 | 
			
		||||
      return res
 | 
			
		||||
    end, test_query)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq({
 | 
			
		||||
      { 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } },
 | 
			
		||||
@@ -686,19 +686,19 @@ void ui_refresh(void)
 | 
			
		||||
      int bar = 13;
 | 
			
		||||
    ]]
 | 
			
		||||
 | 
			
		||||
    local ret = exec_lua(function(str)
 | 
			
		||||
      local parser = vim.treesitter.get_string_parser(str, 'c')
 | 
			
		||||
    local ret = exec_lua(function()
 | 
			
		||||
      local parser = vim.treesitter.get_string_parser(txt, 'c')
 | 
			
		||||
 | 
			
		||||
      local nodes = {}
 | 
			
		||||
      local query = vim.treesitter.query.parse('c', '((identifier) @foo)')
 | 
			
		||||
      local first_child = parser:parse()[1]:root():child(1)
 | 
			
		||||
      local first_child = assert(parser:parse()[1]:root():child(1))
 | 
			
		||||
 | 
			
		||||
      for _, node in query:iter_captures(first_child, str) do
 | 
			
		||||
      for _, node in query:iter_captures(first_child, txt) do
 | 
			
		||||
        table.insert(nodes, { node:range() })
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      return nodes
 | 
			
		||||
    end, txt)
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    eq({ { 1, 10, 1, 13 } }, ret)
 | 
			
		||||
  end)
 | 
			
		||||
@@ -801,8 +801,8 @@ void ui_refresh(void)
 | 
			
		||||
          (#eq? @function.name "foo"))
 | 
			
		||||
      ]]
 | 
			
		||||
 | 
			
		||||
      local result = exec_lua(function(query_str)
 | 
			
		||||
        local query0 = vim.treesitter.query.parse('c', query_str)
 | 
			
		||||
      local result = exec_lua(function()
 | 
			
		||||
        local query0 = vim.treesitter.query.parse('c', query)
 | 
			
		||||
        local match_preds = query0.match_preds
 | 
			
		||||
        local called = 0
 | 
			
		||||
        function query0:match_preds(...)
 | 
			
		||||
@@ -816,7 +816,7 @@ void ui_refresh(void)
 | 
			
		||||
          captures[#captures + 1] = id
 | 
			
		||||
        end
 | 
			
		||||
        return { called, captures }
 | 
			
		||||
      end, query)
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
      eq({ 2, { 1, 1, 2, 2 } }, result)
 | 
			
		||||
    end)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user