fix treesitter for C++. Add variable defination(C++, Go)

neovim_0_5
ray-x 3 years ago
parent fc37a3f9a2
commit 4e748eccab

@ -2,45 +2,57 @@
- Easy code navigation through LSP and 🌲🏡Treesitter symbols; view diagnostic errors.
- Combine LSP and treesitter parser together. Not only providing better highlight but also help you analysis symbol context
and scope.
- A plugin combine LSP and treesitter parser together. Not only providing a better highlight but also help you analyse symbol context effectively.
Here is an example
Here are examples
Following screen shot shows javascript call tree 🌲 of variable `browser` insides a closure. This feature is similar to incoming&outgoing calls from LSP. It is designed for the symbol analysis.
#### Example: Javascripts closure
The following screenshot shows javascript call tree 🌲 of variable `browser` insides a closure. This feature is similar to incoming&outgoing calls from LSP. It is designed for the symbol analysis.
![js_closure_call_tree](https://user-images.githubusercontent.com/1681295/119120589-cee23700-ba6f-11eb-95c5-b9ac8d445c31.jpg)
Explains:
- First line of floating windows shows there are 3 references for the symbol <span style="color:red"> *browser* </span> in closure.js
- The first reference of browser is an assigement, an emoji of 📝 indicates the value changed in this line. In many
cases, we search for reference to find out where the value changed.
Explanation:
- The first line of floating windows shows there are 3 references for the symbol <span style="color:red"> *browser* </span> in closure.js
- The first reference of browser is an assignment, an emoji 📝 indicates the value changed in this line. In many
cases, we search for references to find out where the value changed.
- The second reference of `browser` is inside function `displayName` and `displayName` sit inside `makeFunc`, So you
will see ` displayName{} <- makeFunc{}`
- The third similar to the second, as var browser is on the right side of '=', the value not changed in this line
and emoji is not shown.
#### Example: C++ defination
Another example for C++
![cpp_ref](https://user-images.githubusercontent.com/1681295/119215215-8bd7a080-bb0f-11eb-82fc-8cdf1955e6e7.jpg)
You may find that a 🦕 dinosaur(d) on the line of `Rectangle rect;` which means there is a defination (d for def) of rect in this line
#### Golang struct type
Struct type references in multiple Go ﳑ files
![go_reference](https://user-images.githubusercontent.com/1681295/119123823-54b3b180-ba73-11eb-8790-097601e10f6a.gif)
This feature can provide you info in which function/class/method the variable was referenced. It is handy for large
project where class/function defination is too long to fit into preview window. Also provides a birdview of where the
variable is referenced.
project where class/function definition is too long to fit into the preview window. Also provides a birdview of where the
variable is
- Referenced
- Modified
- Defined
- called
# Features:
- LSP easy setup. Support the most commonly used lsp clients setup. Dynamic lsp activation based on buffer type. This
also enable you handle workspace combine mix types of codes (e.g. Go + javascript + yml)
also enables you to handle workspace combine mixed types of codes (e.g. Go + javascript + yml)
- Out of box experience. 10 lines of minimum vimrc can turn your neovim into a full-featured LSP & Treesitter powered IDE
- Unorthodox UI with floating windows, navigator provides a visual way to manage and navigate through symbols, diagnostic errors, reference etc. Is covers
all features(handler) provided by LSP from commenly used search reference, to less commenly used search for interface
- Unorthodox UI with floating windows, navigator provides a visual way to manage and navigate through symbols, diagnostic errors, reference etc. It covers
all features(handler) provided by LSP from commonly used search reference, to less commonly used search for interface
implementation.
- Async request with lsp.buf_request for reference search
- Treesitter symbol search. It is handy for large filas (Some of LSP e.g. sumneko_lua, there is a 100kb file size limition?)
- Treesitter symbol search. It is handy for large files (Some of LSP e.g. sumneko_lua, there is a 100kb file size limition?)
- FZY search with Lua-JIT
@ -144,7 +156,7 @@ require.'navigator'.setup({
-- -- the on_attach will be called at end of navigator on_attach
-- end,
treesitter_call_tree = true, -- treesitter variable context
treesitter_analysis = true, -- treesitter variable context
sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server",
sumneko_binary = vim.fn.expand("$HOME") ..
"/github/sumneko/lua-language-server/bin/macOS/lua-language-server",
@ -164,6 +176,18 @@ require.'navigator'.setup({
})
```
The plugin can work with multiple LSP, e.g sqls+gopls+efm. But there are cases you may need to disable some of the
servers. (Prevent loading multiple LSP for same source code.) e.g. I saw strange behaviours when I use pyls+pyright+pyls_ms
together. If you have multiple similar LSP installed and have trouble with the plugin, please enable only one at a time.
To disable a LSP server, set `filetypes` to {} e.g.
```lua
require.'navigator'.setup({
pyls={filetype={}}
})
```
@ -177,7 +201,7 @@ require.'navigator'.setup({
The plugin can be loaded lazily (packer `opt = true` ), And it will check if optional plugins existance and load those plugins only if they existed.
The termianl will need to be able to output nerdfont and emoji correctly. I am using Kitty with nerdfont (Victor Mono).
The terminal will need to be able to output nerdfont and emoji correctly. I am using Kitty with nerdfont (Victor Mono).
## Usage
@ -185,11 +209,11 @@ Please refer to lua/navigator/lspclient/mapping.lua on key mappings. Should be a
- Use \<c-e\> or `:q!` to kill the floating window
- <up/down> (or \<c-n\>, \<c-p\>) to move
- \<c-o\> or \<CR\> to open location or apply code actions. Note: \<CR\> might be binded in insert mode by other plugins
- \<c-o\> or \<CR\> to open location or apply code actions. Note: \<CR\> might be bound in insert mode by other plugins
## Configuration
In `navigator.lua` there is a default configration. You can override the values by pass you own values
In `navigator.lua` there is a default configuration. You can override the values by passing your own values
e.g
@ -204,7 +228,7 @@ colorscheme: [aurora](https://github.com/ray-x/aurora)
### Reference
Pls check first part of README
Pls check the first part of README
### Document Symbol
@ -280,7 +304,7 @@ Improved signature help with current parameter highlighted
# Todo
- Early phase, bugs expected, PR and suggestions are welcome
- The project is in the early phase, bugs expected, PRs and suggestions are welcome
- Async (some of the requests is slow on large codebases and might be good to use co-rountine)
- More clients. I use go, python, js/ts, java, c/cpp, lua most of the time. Did not test other languages (e.g dart, swift etc)
- Configuration options

@ -13,7 +13,7 @@ _NgConfigValues = {
sumneko_binary = vim.fn.expand("$HOME") ..
"/github/sumneko/lua-language-server/bin/macOS/lua-language-server",
code_action_prompt = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
treesitter_call_tree = true, -- treesitter variable context
treesitter_analysis = true, -- treesitter variable context
lsp = {
format_on_save = true, -- set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
tsserver = {

@ -13,7 +13,7 @@ ts_nodes = {}
ts_nodes_time = {}
local ts_enabled, _ = pcall(require, "nvim-treesitter.locals")
local calltree_enabled = require"navigator".config_values().treesitter_call_tree
local TS_analysis_enabled = require"navigator".config_values().treesitter_analysis
-- extract symbol from range
local function get_symbol(text, range)
@ -24,8 +24,15 @@ local function get_symbol(text, range)
end
local function check_lhs(text, symbol)
local s = string.find(text, symbol)
local find = require'guihua.util'.word_find
local s = find(text, symbol)
local eq = string.find(text, '=') or 0
if not s or not eq then
return false
end
if s < eq then
log(symbol, "modified")
end
return s < eq
end
@ -136,7 +143,7 @@ function M.call_async(method, params, handler)
end
local function ts_functions(uri)
if not ts_enabled or not calltree_enabled then
if not ts_enabled or not TS_analysis_enabled then
lerr("ts not enabled")
return nil
end
@ -173,6 +180,32 @@ local function ts_functions(uri)
return funcs
end
local function ts_defination(uri, range)
if not ts_enabled or not TS_analysis_enabled then
lerr("ts not enabled")
return nil
end
local ts_def = require"navigator.treesitter".find_definition
local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock()
trace(ts_nodes)
local unload = false
if not api.nvim_buf_is_loaded(bufnr) then
log("! load buf !", uri, bufnr)
vim.fn.bufload(bufnr)
unload = true
end
local def_range = ts_def(range, bufnr)
if unload then
local cmd = string.format("bd %d", bufnr)
log(cmd)
-- vim.cmd(cmd) -- todo: not sure if it is needed
end
log(string.format(" ts def elapsed time: %.4f\n", os.clock() - x), def_range)
return def_range
end
local function find_ts_func_by_range(funcs, range)
if funcs == nil or range == nil then
return nil
@ -209,11 +242,30 @@ function M.locations_to_items(locations)
return i.uri < j.uri
end
end)
local uri_def = {}
for i, loc in ipairs(locations) do
local item = lsp.util.locations_to_items({loc})[1]
item.uri = locations[i].uri
local funcs = ts_functions(item.uri)
item.range = locations[i].range
if TS_analysis_enabled then
if uri_def[item.uri] == nil then
-- find def in file
local def = ts_defination(item.uri, item.range)
uri_def[item.uri] = def or {}
end
log(uri_def[item.uri], item.range)
local def = uri_def[item.uri]
if def.start and item.range then
if def.start.line == item.range.start.line then
log("ts def found")
item.definition = true
end
end
end
item.filename = assert(vim.uri_to_fname(item.uri))
local filename = item.filename:gsub(cwd .. "/", "./", 1)
item.display_filename = filename or item.filename
@ -224,6 +276,7 @@ function M.locations_to_items(locations)
item.symbol_name = get_symbol(item.text, item.range)
item.lhs = check_lhs(item.text, item.symbol_name)
end
trace(uri_def)
return items, width + 24 -- TODO handle long line?
end

@ -95,11 +95,16 @@ function M.prepare_for_render(items, opts)
item = clone(items[i])
item.text = require'navigator.util'.trim_and_pad(item.text)
item.text = string.format("%4i: %s", item.lnum, item.text)
local call_by = ""
local ts_report = ""
if item.lhs then
call_by = '📝 '
ts_report = '📝 '
end
if item.definition then
ts_report = ts_report .. '🦕 '
end
trace(ts_report)
item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '')
if item.call_by ~= nil and #item.call_by > 0 then
trace("call_by:", #item.call_by)
@ -109,29 +114,29 @@ function M.prepare_for_render(items, opts)
local endwise = '{}'
if value.type == 'method' or value.type == 'function' then
endwise = '()'
call_by = ''
ts_report = ts_report .. ''
end
if #call_by > 8 then
call_by = call_by .. ''
if #ts_report > 8 then
ts_report = ts_report .. ''
end
call_by = call_by .. value.kind .. txt .. endwise
ts_report = ts_report .. value.kind .. txt .. endwise
trace(item)
end
end
end
if #call_by > 1 then
space = get_pads(win_width, item.text, call_by)
if #space + #item.text + #call_by >= win_width then
if #item.text + #call_by > win_width then
log("exceeding", #item.text, #call_by, win_width)
if #ts_report > 1 then
space = get_pads(win_width, item.text, ts_report)
if #space + #item.text + #ts_report >= win_width then
if #item.text + #ts_report > win_width then
log("exceeding", #item.text, #ts_report, win_width)
space = ' '
else
local remain = win_width - #item.text - #call_by
local remain = win_width - #item.text - #ts_report
log("remain", remain)
space = string.rep(' ', remain)
end
end
item.text = item.text .. space .. call_by
item.text = item.text .. space .. ts_report
end
local tail = display_items[#display_items].text
if tail ~= item.text then -- deduplicate

@ -57,24 +57,31 @@ end
-- use lsp range to find def
function M.find_definition(range, bufnr)
if not range then
if not range or not range.start then
lerr("find_def incorrect range", range)
return
end
bufnr = bufnr or api.nvim_get_current_buf()
local cursor = {range.start.line, range.start.character} -- +1 or not?
local node_at_point = ts_utils.get_node_at_cursor()
local parser = parsers.get_parser(bufnr)
local symbolpos = {range.start.line, range.start.character} -- +1 or not?
local root = ts_utils.get_root_for_position(range.start.line, range.start.character, parser)
if not root then
return {}
end
local node_at_point = root:named_descendant_for_range(symbolpos[1], symbolpos[2], symbolpos[1],
symbolpos[2])
if not node_at_point then
lerr("no node at cursor")
return
return {}
end
local definition = locals.find_definition(node_at_point, bufnr)
log(definition)
return
log("def found:", definition, definition:range())
if definition then
local r, c = definition:range()
return {start = {line = r, character = c}}
end
return {}
end
--- Get definitions of bufnr (unique and sorted by order of appearance).
@ -137,6 +144,18 @@ local function get_scope(type, source)
if parent:type() == 'function_name_field' then
return parent:parent():parent(), true
end
-- for C++
local n = source
for i = 1, 4, 1 do
if n == nil or n:parent() == nil then
break
end
n = n:parent()
if n:type() == 'function_definition' then
return n, true
end
end
return parent, true
end
@ -151,8 +170,9 @@ local function get_scope(type, source)
trace(source, source:type())
return source, false
end
else -- M.fun1 = function() end
-- lets work up and see next node
else
-- M.fun1 = function() end
-- lets work up and see next node, lua
local n = source
for i = 1, 4, 1 do
if n == nil or n:parent() == nil then

Loading…
Cancel
Save