mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	feat(lsp): add tagfunc (#16103)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							36538417f0
						
					
				
				
					commit
					f940e7a5b9
				
			@@ -1587,6 +1587,13 @@ function lsp.formatexpr(opts)
 | 
			
		||||
  return 0
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Provides an interface between the built-in client and `tagfunc`
 | 
			
		||||
--
 | 
			
		||||
-- Used via `set tagfunc=v:lua.vim.lsp.tagfunc`
 | 
			
		||||
function lsp.tagfunc(...)
 | 
			
		||||
  return require('vim.lsp.tagfunc')(...)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
---Checks whether a client is stopped.
 | 
			
		||||
---
 | 
			
		||||
---@param client_id (Number)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										72
									
								
								runtime/lua/vim/lsp/tagfunc.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								runtime/lua/vim/lsp/tagfunc.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
local lsp = vim.lsp
 | 
			
		||||
local util = vim.lsp.util
 | 
			
		||||
 | 
			
		||||
local function mk_tag_item(name, range, uri, offset_encoding)
 | 
			
		||||
  local bufnr = vim.uri_to_bufnr(uri)
 | 
			
		||||
  -- This is get_line_byte_from_position is 0-indexed, call cursor expects a 1-indexed position
 | 
			
		||||
  local byte = util._get_line_byte_from_position(bufnr, range.start, offset_encoding) + 1
 | 
			
		||||
  return {
 | 
			
		||||
    name = name,
 | 
			
		||||
    filename = vim.uri_to_fname(uri),
 | 
			
		||||
    cmd = string.format('call cursor(%d, %d)|', range.start.line + 1, byte),
 | 
			
		||||
  }
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function query_definition(pattern)
 | 
			
		||||
  local params = lsp.util.make_position_params()
 | 
			
		||||
  local results_by_client, err = lsp.buf_request_sync(0, 'textDocument/definition', params, 1000)
 | 
			
		||||
  if err then
 | 
			
		||||
    return {}
 | 
			
		||||
  end
 | 
			
		||||
  local results = {}
 | 
			
		||||
  local add = function(range, uri, offset_encoding)
 | 
			
		||||
    table.insert(results, mk_tag_item(pattern, range, uri, offset_encoding))
 | 
			
		||||
  end
 | 
			
		||||
  for client_id, lsp_results in pairs(results_by_client) do
 | 
			
		||||
    local client = lsp.get_client_by_id(client_id)
 | 
			
		||||
    local result = lsp_results.result or {}
 | 
			
		||||
    if result.range then -- Location
 | 
			
		||||
      add(result.range, result.uri)
 | 
			
		||||
    else -- Location[] or LocationLink[]
 | 
			
		||||
      for _, item in pairs(result) do
 | 
			
		||||
        if item.range then -- Location
 | 
			
		||||
          add(item.range, item.uri, client.offset_encoding)
 | 
			
		||||
        else -- LocationLink
 | 
			
		||||
          add(item.targetSelectionRange, item.targetUri, client.offset_encoding)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  return results
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function query_workspace_symbols(pattern)
 | 
			
		||||
  local results_by_client, err = lsp.buf_request_sync(0, 'workspace/symbol', { query = pattern }, 1000)
 | 
			
		||||
  if err then
 | 
			
		||||
    return {}
 | 
			
		||||
  end
 | 
			
		||||
  local results = {}
 | 
			
		||||
  for client_id, symbols in pairs(results_by_client) do
 | 
			
		||||
    local client = lsp.get_client_by_id(client_id)
 | 
			
		||||
    for _, symbol in pairs(symbols.result or {}) do
 | 
			
		||||
      local loc = symbol.location
 | 
			
		||||
      local item = mk_tag_item(symbol.name, loc.range, loc.uri, client.offset_encoding)
 | 
			
		||||
      item.kind = lsp.protocol.SymbolKind[symbol.kind] or 'Unknown'
 | 
			
		||||
      table.insert(results, item)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  return results
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function tagfunc(pattern, flags)
 | 
			
		||||
  local matches
 | 
			
		||||
  if string.match(flags, 'c') then
 | 
			
		||||
    matches = query_definition(pattern)
 | 
			
		||||
  else
 | 
			
		||||
    matches = query_workspace_symbols(pattern)
 | 
			
		||||
  end
 | 
			
		||||
  -- fall back to tags if no matches
 | 
			
		||||
  return #matches > 0 and matches or vim.NIL
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return tagfunc
 | 
			
		||||
		Reference in New Issue
	
	Block a user