Compare commits

...

123 Commits

Author SHA1 Message Date
ray-x cd98ca2c5b update floating width 2 years ago
ray-x 451d761f76 features side panel for symbol reference 2 years ago
sp4ke 8278f71878
make sure merge luadev config from user (#229)
Co-authored-by: spike <spike@w530>
2 years ago
ray-x 443fd4d585 issue #228 codelens sign missing 2 years ago
ray-x 10fd76d6d0 default severity 2 years ago
ray-x 8d00282020 volar and diangnostic severity level check 2 years ago
ray-x 9afcd37854 issue #227 2 years ago
ray-x c70d032b08 mason setup 2 years ago
ray-x fb6d19ddf4 issue #226 add example for mason setup 2 years ago
ray-x af7fc7d649 some updates for mason 2 years ago
ray-x d8f19f6fc1 range_code_action deprecated in neovim 0.8 2 years ago
ray-x df7f4d7229 better format ts_context text 2 years ago
ray-x fb87a0b1b7 long line improvement 2 years ago
ray-x 927c464b70 optimize for go and ts_contex 2 years ago
ray-x e9a40aca40 diagnostic: show line diagnostic: offset the floating windows to first error pos 2 years ago
ray-x edee3e39c6 merge changes for treesitter symbole context 2 years ago
sp4ke a7886fc055
Fix keymap buffer (#223)
* apply key mapping to selected buffer only

* <help> filetype should not be handled by navigator

Co-authored-by: spike <spike@w530>
2 years ago
yyk de018d9ae3
Fix invalid buffer in defer fn. (#221) 2 years ago
ray-x ef0cee5bbd unit tests 2 years ago
ray-x ab2e383b20 unit tests 2 years ago
ray-x 1b262556c0 reuse telecsope color scheme 2 years ago
rayx b4ff1c43b9
Update codelens.lua 2 years ago
ray-x ebd88f5d09 re-order code action so null-ls is not the first to see 2 years ago
ray-x 28d245510f using neovim 0.7 API 2 years ago
ray-x 213b30950e the missing options for treesitter folding 2 years ago
ray-x f05d2ec142 lint, expand tab to space for treesitter folding 2 years ago
ray-x 9f151cf718 definition preview, show more contents and allow scroll 2 years ago
ray-x b131251ad8 send floating view result to quickfix; de-duplicate references 2 years ago
ray-x 8978bdb1e3 issue #219 missing end 2 years ago
ray-x ae251289b3 issue #218 range format operator 2 years ago
ray-x a9c223cc22 de-duplicate 2 years ago
ray-x 0ab4b02ff7 update on_attach 2 years ago
ray-x 6c0e286170 update readme for on_attach 2 years ago
ray-x f24a337f5d switch between buffer type 2 years ago
ray-x 3d87ed3b87 issue #217 README missing symbols 2 years ago
ray-x 5713f79265 clear autocmd #191 2 years ago
ray-x 01ef2ce1a1 typo highlight 2 years ago
ray-x 547f2bc15d doc highlight config options update 2 years ago
ray-x dc0b8504bb allow document_highlight to be configurable, update REWADME 2 years ago
ray-x 486085070d #191 cleanup 2 years ago
ray-x bc356d555f pipeline neovim 0.7.0 2 years ago
ray-x 5b5a946d73 add neovim 0.7.1 to pipeline 2 years ago
ray-x fca2fa5aaa some version of neovim does not support underline etc 2 years ago
rayx 49dbca889d
Update clients.lua 2 years ago
ray-x 861ae038dd underdouble is not supported by 0.7.x 2 years ago
ray-x 814b712e91 no longer nvim 0.6.x 2 years ago
ray-x dcc40278c5 use create_autocmd API; split clients.lua into 3 files 2 years ago
ray-x 6736293182 split sumneko 2 years ago
ray-x 10ef469286 issue #214 lsp_installer loading 2 years ago
ray-x 4775d43218 .gitignore 2 years ago
ray-x 89dd02c927 using neovim 0.7.0 api for autocmd 2 years ago
ray-x bbdf86a66e refactor highlight setup. it is for #216 and also using API from neovim 0.7 now 2 years ago
ray-x ed47d386e6 chore selene setup 2 years ago
ray-x 480824d3f3 lint does not support lua5.1 JIT ... 2 years ago
ray-x c3ef990390 lint 2 years ago
ray-x de5c88c766 lint pipeline 2 years ago
ray-x 348ab9dced mason support #215 2 years ago
ray-x 967fd32bae prevent autocmd being call in a loop 2 years ago
ray-x 4aef8dc5f2 dartls installer not working #212 2 years ago
ray-x 0de6c290cf issue #211 tsserver not working 2 years ago
ray-x 9aad2978dc resend filetype if lsp not ready 2 years ago
ray-x 49c3e5cd4d prevent compare number to bool. As the name for `html` LSP is `html` 2 years ago
ray-x 47545e03c0 default border hl to FloatBorder 2 years ago
ray-x e5d16e4488 renaming highight group from GHxxx to Guihuaxxx 2 years ago
ray-x 3d9a9582dd bugfix #206 diagnostic failure 2 years ago
rayx 05dfed9ed9
issue #171 multiple lsp server started (#205)
* issue #171 multiple lsp server started

* neovim 0.6.1
2 years ago
ray-x 05753da8db add deprecate message 2 years ago
ray-x 4623677b2a issue #204 update doc for the breaking changes 2 years ago
ray-x 85e3f6e045 Allow user pass the lua-dev setup into navigator 2 years ago
ray-x c30ccd07c9 add options for lsp.buf.format()
update keymap doc
2 years ago
ray-x 4c5d0e67d0 remove table nil handling 2 years ago
ray-x be6da35767 improve treesitter folding 2 years ago
ray-x f567f1b99c dedup definition for script languages 2 years ago
ray-x a93f7cb20f dedup reference results 2 years ago
ray-x 289f67013d indent fallback if treesitter not found 2 years ago
ray-x 56b00b83d5 diagnostic func failed to keymap 2 years ago
ray-x 3fe9a876c4 bugfix hover keymaps not mapped correctly 2 years ago
rayx acca6009e0
[Breaking] using vim.keymap.set, breaking changes (#200)
* using vim.keymap.set, breaking changes

* update keymaps

* doc updates
2 years ago
ray-x 792fd2831a fix github workflow 2 years ago
ray-x a225d18eaf new tests for hierarchy, refactor reference_spec test 2 years ago
ray-x 7d84a9f0c0 issue #201 vfn nil 2 years ago
ray-x 22e858f261 #195 update doc for rust-tool, make client/bufnr require fields for mapping.setup(opts) when calling from rust/clangd on_attach 2 years ago
ray-x edba3efd1e Calltree updates 2 years ago
ray-x 724d5f3439 add scope info in treesitter panel 2 years ago
ray-x 3dc8c02c39 add scope info in panel 2 years ago
ray-x 91d1366b65 update treesitter for 0.6.1 pipeline 2 years ago
ray-x d951a5fcd2 fix for test failure 2 years ago
ray-x 68eb18c310 offset for definition preview 2 years ago
ray-x 8d77c3ab1e bug fix for #166 not all items shown in listview. Also add flag allow control when the ts info will be added
update readme
2 years ago
ray-x 309afcd681 update pipeline for neovim 0.7.2 2 years ago
rayx 9f7bd6ebff
Feature/198 calltree (#199)
* refactor hierarchy.lua

* show side panel for hierarchy

* allow call hierarchy to fold and expand to show call tree

* update command maps
2 years ago
ray-x aba0d89745 remove traceback logs 2 years ago
ray-x c1b0694bef map incoming/outgoing calls handler 2 years ago
ray-x 9dee73010b optimize treesitter symbol tree 2 years ago
ray-x 1b3a02df3e symbol indent level for embedded struct 2 years ago
ray-x f856fa7033 issue #195 update doc for rust-tools and clang-extensions 2 years ago
rayx 1f6103ed95
Side panel (#197)
* add sidepanel

* revert some changes and fix nil indent level

* Add side panel; bugfix for ctags
2 years ago
ray-x 7bfd9157fe update TS fold 2 years ago
ray-x 48e35f4e56 hold ctags windows untils ctags cmd finished 2 years ago
ray-x 27442d2784 simpily codeaction and range_code_action keymapping and code 2 years ago
ray-x 3ad93531b5 unit tests for treesitter 2 years ago
ray-x c15bae89ab doc updates for rust-tools #195 2 years ago
ray-x 61a82559d6 add treesitter tests 2 years ago
ray-x f8985d7aa2 allow skip lsp clients setup 2 years ago
ray-x 516d643ffe lsp installer update issue #181 2 years ago
ray-x 6b4cfa3d59 symbol layout update 2 years ago
ray-x cce0e90544 gui listview updates, allow listview cover more spaces 2 years ago
rayx 2f35446fbe
issue #192 pylsp range missing (#193)
* issue #192 pylsp range missing
2 years ago
ray-x 1908ea5175 improve line rendering when trim long text 2 years ago
ray-x 6c3ee44729 bugfix workspace symbol from multiple lsp clients 2 years ago
ray-x 6e937e9019 workspace symbole search improvements. allows to show interactive search results in the symbol list. 2 years ago
ray-x 01801ba8fa change ts not load notify level 2 years ago
ray-x d0ab595b93 code action flicker 2 years ago
ray-x 3f49769abc lint all codes 2 years ago
ray-x 32ddd66dd2 fix for issue#191 2 years ago
ray-x feb780fb10 reloaded client when failed 2 years ago
ray-x ea2c207ec9 updates for client loading 2 years ago
ray-x b249d1680a handle same lsp started multiple times (esp for those take long time to start ) issue #171 2 years ago
ray-x 13c3dd4072 disable logs when debug is not on 2 years ago
ray-x a0eff2c5a3 Merge branch 'serverCapcities' 2 years ago
Michael Adler 2e96dcd327
fix(sumneko): fix incorrect usage of runtime.path (#189)
This is quite tricky to get right, because there are two ways for
sumneko to search for files, namely:

1. Lua.runtime.path

When using `require`, how to find the file based on the input name.
Setting this config to `?/init.lua` means that when you enter `require
'myfile'`, `${workspace}/myfile/init.lua` will be searched from the
loaded files.  if `runtime.pathStrict` is `false`,
`${workspace}/**/myfile/init.lua` will also be searched.  If you want to
load files outside the workspace, you need to set
`Lua.workspace.library` first.

2. Lua.workspace.library

In addition to the current workspace, which directories will load files
from. The files in these directories will be treated as externally
provided code libraries, and some features (such as renaming fields)
will not modify these files.

The crucial point is that `Lua.runtime.path` only applies to
the *current* workspace. Thus it makes no sense to add any absolute
directories here. Absolute directories must be added to
workspace.library, which is already the case. The default value provided
by sumneko is what you typically would expect, so I have switched to it.

References:

- 076dd3e5c4/locale/en-us/setting.lua (L5-L13)
- e62d964ff5/script/config/config.lua (L151)
2 years ago
Michael Adler ff4bcc6d83
doc(packer): depend on nvim-lspconfig (#188) 2 years ago
rayx a73fb38ef9
update resolved_capacities -> server_capacities (#185)
* update resolved_capacities

* format renaming

* remove comments

* remove mk_handler. update documentFormator

* bumpup test image to ubuntu 22.04

* add logs when neovim is lower than 0.8
2 years ago

@ -19,7 +19,7 @@ jobs:
manager: sudo snap
packages: go
- os: ubuntu-22.04
url: https://github.com/neovim/neovim/releases/download/v0.6.1/nvim-linux64.tar.gz
url: https://github.com/neovim/neovim/releases/download/v0.7.2/nvim-linux64.tar.gz
manager: sudo snap
packages: go
steps:

4
.gitignore vendored

@ -1,3 +1,3 @@
selene.toml
lua/navigator.lua.bak
tests/fixtures/tests
tests/fixtures/tests

@ -1,9 +1,14 @@
# Navigator
- Source code analysis and navigate tool
- Easy code navigation, view diagnostic errors, see relationships of functions, variables
- A plugin combines the power of LSP and 🌲🏡 Treesitter together. Not only provids a better highlight but also help you analyse symbol context effectively.
- ctags fuzzy search & build ctags symbols
-
- [![a short intro of navigator](https://user-images.githubusercontent.com/1681295/147378905-51eede5f-e36d-48f4-9799-ae562949babe.jpeg)](https://youtu.be/P1kd7Y8AatE)
Here are some examples
@ -67,11 +72,11 @@ variable is:
- Async request with lsp.buf_request for reference search
- Treesitter symbol search. It is handy for large files (Some of LSP e.g. sumneko_lua, there is a 100kb file size limitation?)
- Treesitter symbol search. It is handy for large files (Some of LSP e.g. sumneko_lua, there is a 100kb file size limitation?). Also as LSP trying to hide details behind, Treesitter allows you to access all AST semantics.
- FZY search with either native C (if gcc installed) or Lua-JIT
- LSP multiple symbol highlight/marker and hop between document references
- LSP multiple symbols highlight/marker and hop between document references
- Preview definination/references
@ -91,7 +96,11 @@ variable is:
- ccls call hierarchy (Non-standard `ccls/call` API) supports
- Syntax folding based on treesitter folding algorithm. (It behaves similar to vs-code)
- Syntax folding based on treesitter or LSP_fold folding algorithm. (It behaves similar to vs-code); dedicated comment folding.
- Treesitter symbols sidebar, LSP document symbole sidebar. Both with preview and folding
- Calltree: Display and expand Lsp incoming/outgoing calls hierarchy-tree with sidebar
- Fully support LSP CodeAction, CodeLens, CodeLens action. Help you improve code quality.
@ -101,6 +110,8 @@ variable is:
- Multigrid support (different font and detachable)
- Side panel (sidebar) and floating windows
# Why a new plugin
I'd like to go beyond what the system is offering.
@ -116,7 +127,7 @@ I'd like to go beyond what the system is offering.
# Install
Require nvim-0.6.1, nightly prefered
Require nvim-0.6.1 or above, nightly (0.8) prefered
You can remove your lspconfig setup and use this plugin.
The plugin depends on lspconfig and [guihua.lua](https://github.com/ray-x/guihua.lua), which provides GUI and fzy support(migrate from [romgrk's project](romgrk/fzy-lua-native)).
@ -127,14 +138,18 @@ Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
Plug 'ray-x/navigator.lua'
```
Note: Highly recommened: 'nvim-treesitter/nvim-treesitter'
Note: Highly recommend: 'nvim-treesitter/nvim-treesitter'
Packer
```lua
use {'ray-x/navigator.lua', requires = {'ray-x/guihua.lua', run = 'cd lua/fzy && make'}}
use({
'ray-x/navigator.lua',
requires = {
{ 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
{ 'neovim/nvim-lspconfig' },
},
})
```
## Setup
@ -242,11 +257,15 @@ require'navigator'.setup({
-- end,
-- The attach code will apply to all LSP clients
default_mapping = true, -- set to false if you will remap every key
keymaps = {{key = "gK", func = "declaration()"}}, -- a list of key maps
ts_fold = false, -- modified version of treesitter folding
default_mapping = true, -- set to false if you will remap every key or if you using old version of nvim-
keymaps = {{key = "gK", func = vim.lsp.declaration, desc = 'declaration'}}, -- a list of key maps
-- this kepmap gK will override "gD" mapping function declaration() in default kepmap
-- please check mapping.lua for all keymaps
treesitter_analysis = true, -- treesitter variable context
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis
treesitter_analysis_condense = true, -- condense form for treesitter analysis
-- this value prevent slow in large projects, e.g. found 100000 reference in a project
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil or 100 to disable it
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
@ -254,22 +273,30 @@ require'navigator'.setup({
signature_help_cfg = nil, -- if you would like to init ray-x/lsp_signature plugin in navigator, and pass in your own config to signature help
icons = {
-- Code action
code_action_icon = "🏏",
code_action_icon = "🏏", -- note: need terminal support, for those not support unicode, might crash
-- Diagnostics
diagnostic_head = '🐛',
diagnostic_head_severity_1 = "🈲",
-- refer to lua/navigator.lua for more icons setups
},
lsp_installer = false, -- set to true if you would like use the lsp installed by williamboman/nvim-lsp-installer
mason = false, -- set to true if you would like use the lsp installed by williamboman/mason
lsp = {
enable = true, -- skip lsp setup if disabled make sure add require('navigator.lspclient.mapping').setup() in you
-- own on_attach
code_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
code_lens_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
document_highlight = true, -- LSP reference highlight,
-- it might already supported by you setup, e.g. LunarVim
format_on_save = true, -- set to false to disable lsp code format on save (if you are using prettier/efm/formater etc)
format_options = {async=false}, -- async: disable by default, the option used in vim.lsp.buf.format({async={true|false}, name = 'xxx'})
disable_format_cap = {"sqls", "sumneko_lua", "gopls"}, -- a list of lsp disable format capacity (e.g. if you using efm or vim-codeformat etc), empty {} by default
-- If you using null-ls and want null-ls format your code
-- you should disable all other lsp and allow only null-ls.
disable_lsp = {'pylsd', 'sqlls'}, -- a list of lsp server disabled for your project, e.g. denols and tsserver you may
-- only want to enable one lsp server
--want to enable one lsp server at a time
-- to disable all default config and use your own lsp setup set
-- disable_lsp = 'all'
-- disable_lsp = 'all' and you may need to hook mapping.setup() in your on_attach
-- Default {}
diagnostic = {
underline = true,
@ -287,6 +314,11 @@ require'navigator'.setup({
filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetypes
},
ctags ={
cmd = 'ctags',
tagfile = 'tags',
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
},
gopls = { -- gopls setting
on_attach = function(client, bufnr) -- on_attach for gopls
-- your special on attach here
@ -298,6 +330,18 @@ require'navigator'.setup({
gopls = {gofumpt = false} -- disable gofumpt etc,
}
},
-- the lsp setup can be a function, .e.g
gopls = function()
local go = pcall(require, "go")
if go then
local cfg = require("go.lsp").config()
cfg.on_attach = function(client)
client.server_capabilities.documentFormattingProvider = false -- efm/null-ls
end
return cfg
end
end,
sumneko_lua = {
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",
@ -405,15 +449,17 @@ In `playground` folder, there is a `init.lua` and source code for you to play wi
| n | gd | definition |
| n | g0 | document symbol |
| n | \<C-]\> | go to definition (if multiple show listview) |
| n | gp | definition preview (Go to Preview) |
| n | gp | definition preview (show Preview) |
| n | \<C-LeftMouse\> | definition |
| n | g\<LeftMouse\> | implementation |
| n | \<Leader>gt | treesitter document symbol |
| n | \<Leader\>gT | treesitter symbol for all open buffers |
| n | \<Leader\> ct | ctags symbol search |
| n | \<Leader\> cg | ctags symbol generate |
| n | K | hover doc |
| n | \<Space\>ca | code action (when you see 🏏 ) |
| n | \<Space\>la | code lens action (when you see a codelens indicator) |
| v | \<Space\>cA | range code action (when you see 🏏 ) |
| v | \<Space\>ca | range code action (when you see 🏏 ) |
| n | \<Space\>rn | rename with floating window |
| n | \<Leader\>re | rename (lsp default) |
| n | \<Leader\>gi | hierarchy incoming calls |
@ -444,20 +490,21 @@ In `playground` folder, there is a `init.lua` and source code for you to play wi
| n | \<Enter\> | open preview file in nvim/Apply action |
| n | \<ESC\> | close listview of floating window |
| i/n | \<C-e\> | close listview of floating window |
| n | \<C-q\> | close listview and send results to quickfix |
| i/n | \<C-b\> | previous page in listview |
| i/n | \<C-f\> | next page in listview |
| i/n | \<C-s\> | save the modification to preview window to file |
### Colors/Highlight:
You can override default highlight GHListDark (listview) and GHTextViewDark (code view) and GHListHl (select item)
You can override default highlight GuihuaListDark (listview) and GuihuaTextViewDark (code view) and GuihuaListHl (select item)
e.g.
```vim
hi default GHTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GHListDark guifg=#e0d8f4 guibg=#103234
hi default GHListHl guifg=#e0d8f4 guibg=#404254
hi default GuihuaTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GuihuaListDark guifg=#e0d8f4 guibg=#103234
hi default GuihuaListHl guifg=#e0d8f4 guibg=#404254
```
There are other Lsp highlight been used in this plugin, e.g LspReferenceRead/Text/Write are used for document highlight,
@ -475,18 +522,109 @@ The plugin can be loaded lazily (packer `opt = true` ), And it will check if opt
The terminal will need to be able to output nerdfont and emoji correctly. I am using Kitty with nerdfont (Victor Mono).
## Integrat with lsp_installer (williamboman/nvim-lsp-installer)
## Integrat with mason (williamboman/mason.nvim) or lsp_installer (williamboman/nvim-lsp-installer, deprecated)
If you are using lsp_installer and would like to use the lsp servers installed by lsp_installer. Please set
If you are using mason or lsp_installer and would like to use the lsp servers installed by lsp_installer. Please set
```lua
lsp_installer = true
lsp_installer = true --lsp_installer users, deprecated
mason = true -- mason user
```
In the config. Also please setup the lsp server from installer setup with `server:setup{opts}`
Alternatively, Navigator can be used to startup the server installed by lsp-installer. Please do not call `server:setup{opts}` from lsp installer
lsp-installer example:
```lua
use({
'williamboman/nvim-lsp-installer',
config = function()
local lsp_installer = require('nvim-lsp-installer')
lsp_installer.setup{}
end,
})
use({
'ray-x/navigator.lua',
config = function()
require('navigator').setup({
lsp_installer = true,
})
end,
})
```
for mason
```lua
use("williamboman/mason.nvim")
use({
"williamboman/mason-lspconfig.nvim",
config = function()
require("mason").setup()
require("mason-lspconfig").setup({})
end,
})
use({
"ray-x/navigator.lua",
requires = {
{ "ray-x/guihua.lua", run = "cd lua/fzy && make" },
{ "neovim/nvim-lspconfig" },
{ "nvim-treesitter/nvim-treesitter" },
},
config = function()
require("navigator").setup({
mason = true,
})
end,
})
```
Another way to setup mason is disable navigator lsp setup and using mason setup handlers, pylsp for example
```lua
use("williamboman/mason.nvim")
use({
"williamboman/mason-lspconfig.nvim",
config = function()
require("mason").setup()
require("mason-lspconfig").setup_handlers({
["pylsp"] = function()
require("lspconfig").pylsp.setup({
on_attach = function(client, bufnr)
require("navigator.lspclient.mapping").setup({ client = client, bufnr = bufnr }) -- setup navigator keymaps here,
require("navigator.dochighlight").documentHighlight(bufnr)
require("navigator.codeAction").code_action_prompt(bufnr)
end,
})
end,
})
require("mason-lspconfig").setup({})
end,
})
use({
"navigator.lua",
requires = {
{ "ray-x/guihua.lua", run = "cd lua/fzy && make" },
{ "nvim-lspconfig" },
{ "nvim-treesitter/nvim-treesitter" },
},
config = function()
require("navigator").setup({
mason = true,
lsp = { disable_lsp = { "pylsp" } }, -- disable pylsp setup from navigator
})
end,
})
```
Please refer to [lsp_installer_config](https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
for more info
Alternatively, Navigator can be used to startup the server installed by lsp-installer.
as it will override the navigator setup
To start LSP installed by lsp_installer, please use following setups
@ -496,7 +634,9 @@ To start LSP installed by lsp_installer, please use following setups
require'navigator'.setup({
-- lsp_installer = false -- default value is false
lsp = {
tsserver = { cmd = {'your tsserver installed by lsp_installer'} }
tsserver = { cmd = {'your tsserver installed by lsp_installer or mason'} }
-- e.g. tsserver = { cmd = {'/home/username/.local/share/nvim/mason/packages/typescript-language-server/node_modules/typescript/bin/tsserver'} }
}
})
@ -511,6 +651,7 @@ require'navigator'.setup({
lsp = {
tsserver = {
cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" }
-- or mason: cmd = { "/Users/username/.local/share/nvim/mason/packages/pyright/node_modules/pyright/index.js", "--stdio"}
}
}
}
@ -550,6 +691,49 @@ You can delegate the lsp server setup to lsp_installer with `server:setup{opts}`
Here is an example [init_lsp_installer.lua](https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
### Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension)
There are lots of plugins provides lsp support
* go.nvim allow you either hook gopls from go.nvim or from navigator and it can export the lsp setup from go.nvim.
* rust-tools and clangd allow you to setup on_attach from config server
* [lua-dev](https://github.com/folke/lua-dev.nvim) Dev setup for init.lua and plugin development. Navigator can
extend lua setup with lua-dev.
Here is an example to setup rust with rust-tools
```lua
require'navigator'.setup({
lsp = {
disable_lsp = { "rust_analyzer", "clangd" }, -- will not run rust_analyzer setup from navigator
['lua-dev'] = { runtime_path=true } -- any non default lua-dev setups
},
})
require('rust-tools').setup({
server = {
on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here,
require("navigator.dochighlight").documentHighlight(bufnr)
require('navigator.codeAction').code_action_prompt(bufnr)
-- otherwise, you can define your own commands to call navigator functions
end,
}
})
require("clangd_extensions").setup {
server = {
on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here,
require("navigator.dochighlight").documentHighlight(bufnr)
require('navigator.codeAction').code_action_prompt(bufnr)
-- otherwise, you can define your own commands to call navigator functions
end,
}
}
```
## Usage
Please refer to lua/navigator/lspclient/mapping.lua on key mappings. Should be able to work out-of-box.
@ -576,7 +760,7 @@ Highlight I am using:
- LspReferenceRead, LspReferenceText and LspReferenceWrite are used for `autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()`
That is where you saw the current symbol been highlighted.
- GHListDark and GHTextViewDark is used for floating listvew and TextView. They are be based on current background
- GuihuaListDark and GuihuaTextViewDark is used for floating listvew and TextView. They are be based on current background
(Normal) and PmenuSel
- In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat
@ -589,6 +773,13 @@ You can override the above highlight to fit your current colorscheme
| ------------ | ------------------------- |
| LspToggleFmt | toggle lsp auto format |
| LspKeymaps | show LSP releated keymaps |
| Nctags {args} | show ctags symbols, args: -g regen ctags |
| LspRestart | reload lsp |
| LspToggleFmt | toggle lsp format |
| LspSymbols | document symbol in side panel |
| NRefPanel | show symbol reference in side panel |
| TSymobls | treesitter symbol in side panel |
| Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) |
## Screenshots
@ -604,6 +795,14 @@ Using treesitter and LSP to view the symbol definition
![image](https://user-images.githubusercontent.com/1681295/139771978-bbc970a5-be9f-42cf-8942-3477485bd89c.png)
### Sidebar, folding, outline
Treesitter outline and Diagnostics
<img width="708" alt="image" src="https://user-images.githubusercontent.com/1681295/174791609-0023e68f-f1f4-4335-9ea2-d2360e9f0bfd.png">
<img width="733" alt="image" src="https://user-images.githubusercontent.com/1681295/174804579-26f87fbf-426b-46d0-a7a3-a5aab69c032f.png">
Calltree (Expandable LSP call hierarchy)
<img width="769" alt="image" src="https://user-images.githubusercontent.com/1681295/176998572-e39fc968-4c8c-475d-b3b8-fb7991663646.png">
### GUI and multigrid support
You can load a different font size for floating win
@ -718,11 +917,14 @@ Codelens for C++/ccls. Symbol reference
### VS-code style folding with treesitter
Folding is using a hacked version of treesitter folding. (option: ts_fold)
#### folding function
![image](https://user-images.githubusercontent.com/1681295/148491596-6cd6c507-c157-4536-b8c4-dc969436763a.png)
#### folding comments
Multiline comments can be folded as it is treated as a block
![image](https://user-images.githubusercontent.com/1681295/148491845-5ffb18ea-f05d-4229-aec3-aa635b3de814.png)

@ -1,4 +1,4 @@
function! folding#foldexpr()
function! folding#ngfoldexpr()
" return luaeval(printf('require"navigator.foldinglsp".get_fold_indic(%d)', v:lnum))
return luaeval(printf('require"navigator.foldts".get_fold_indic(%d)', v:lnum))
endfunction

@ -18,10 +18,12 @@ CONTENTS *navigator-content
5.4.1. LSP clients.................................|navigator-lsp_clients|
5.4.1.1. Add your own servers.........|navigator-add_your_own_servers|
5.4.2. Disable a lsp client loading from navigator.|navigator-disable_a_lsp_client_loading_from_navigator|
5.4.3. Default keymaps.........................|navigator-default_keymaps|
5.4.4. Colors/Highlight:.....................|navigator-colors/highlight:|
5.4.3. Try it your self.......................|navigator-try_it_your_self|
5.4.4. Default keymaps.........................|navigator-default_keymaps|
5.4.5. Colors/Highlight:.....................|navigator-colors/highlight:|
5.5. Dependency.........................................|navigator-dependency|
5.6. Integration with lsp_installer (williamboman/nvim-lsp-installer).|navigator-integration_with_lsp_installer_(williamboman/nvim-lsp-installer)|
5.6. Integrat with lsp_installer (williamboman/nvim-lsp-installer).|navigator-integrat_with_lsp_installer_(williamboman/nvim-lsp-installer)|
5.6.1. Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension).|navigator-integration_with_other_lsp_plugins_(e.g._rust-tools,_go.nvim,_clangd_extension)|
5.7. Usage...................................................|navigator-usage|
5.8. Configuration...................................|navigator-configuration|
5.9. Highlight...........................................|navigator-highlight|
@ -29,10 +31,11 @@ CONTENTS *navigator-content
5.11. Screenshots......................................|navigator-screenshots|
5.11.1. Reference....................................|navigator-reference|
5.11.2. Definition preview..................|navigator-definition_preview|
5.11.3. GUI and multigrid support....|navigator-gui_and_multigrid_support|
5.11.4. Document Symbol........................|navigator-document_symbol|
5.11.5. Workspace Symbol......................|navigator-workspace_symbol|
5.11.6. highlight document symbol and jump between reference.|navigator-highlight_document_symbol_and_jump_between_reference|
5.11.3. Sidebar, folding, outline....|navigator-sidebar,_folding,_outline|
5.11.4. GUI and multigrid support....|navigator-gui_and_multigrid_support|
5.11.5. Document Symbol and navigate through the list.|navigator-document_symbol_and_navigate_through_the_list|
5.11.6. Workspace Symbol......................|navigator-workspace_symbol|
5.11.7. highlight document symbol and jump between reference.|navigator-highlight_document_symbol_and_jump_between_reference|
6. Current symbol highlight and jump backward/forward between symbols.|navigator-current_symbol_highlight_and_jump_backward/forward_between_symbols|
6.1. Diagnostic.....................................|navigator-diagnostic|
6.2. Edit in preview window.............|navigator-edit_in_preview_window|
@ -48,6 +51,9 @@ CONTENTS *navigator-content
6.11. Light bulb if codeAction available.|navigator-light_bulb_if_codeaction_available|
6.12. Codelens........................................|navigator-codelens|
6.13. Predefined LSP symbol nerdfont/emoji.|navigator-predefined_lsp_symbol_nerdfont/emoji|
6.14. VS-code style folding with treesitter.|navigator-vs-code_style_folding_with_treesitter|
6.14.1. folding function..................|navigator-folding_function|
6.14.2. folding comments..................|navigator-folding_comments|
7. Debug the plugin...................................|navigator-debug_the_plugin|
8. Break changes and known issues.......|navigator-break_changes_and_known_issues|
9. Todo...........................................................|navigator-todo|
@ -56,8 +62,14 @@ CONTENTS *navigator-content
================================================================================
NAVIGATOR *navigator-navigator*
* Source code analysis and navigate tool
* Easy code navigation, view diagnostic errors, see relationships of functions, variables
* A plugin combines the power of LSP and 🌲🏡 Treesitter together. Not only provids a better highlight but also help you analyse symbol context effectively.
* ctags fuzzy search & build ctags symbols
-
* [](https://youtu.be/P1kd7Y8AatE)
Here are some examples
@ -127,7 +139,8 @@ FEATURES: *navigator-features
* Optimize display (remove trailing bracket/space), display the caller of reference, de-duplicate lsp results (e.g reference
in the same line). Using treesitter for file preview highlighter etc
* ccls call hierarchy (Non-standard `ccls/call` API) supports
* Syntax folding based on treesitter folding algorithm. (It behaves similar to vs-code)
* Syntax folding based on treesitter or LSP_fold folding algorithm. (It behaves similar to vs-code); comment folding
* Treesitter symbols sidebar, LSP document symbole sidebar. Both with preview and folding
* Fully support LSP CodeAction, CodeLens, CodeLens action. Help you improve code quality.
* LRU cache for treesitter nodes
* Lazy loader friendly
@ -151,7 +164,7 @@ SIMILAR PROJECTS / SPECIAL MENTIONS: *navigator-similar_projects_/_special_menti
================================================================================
INSTALL *navigator-install*
Require nvim-0.6.1 or nightly
Require nvim-0.6.1 or above, nightly (0.8) prefered
You can remove your lspconfig setup and use this plugin.
The plugin depends on lspconfig and guihua.lua (https://github.com/ray-x/guihua.lua), which provides GUI and fzy support(migrate from romgrk's project (romgrk/fzy-lua-native)).
@ -161,11 +174,17 @@ The plugin depends on lspconfig and guihua.lua (https://github.com/ray-x/guihua.
Plug 'ray-x/navigator.lua'
<
Note: Highly recommened: 'nvim-treesitter/nvim-treesitter'
Note: Highly recommend: 'nvim-treesitter/nvim-treesitter'
Packer
>
use {'ray-x/navigator.lua', requires = {'ray-x/guihua.lua', run = 'cd lua/fzy && make'}}
use({
'ray-x/navigator.lua',
requires = {
{ 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
{ 'neovim/nvim-lspconfig' },
},
})
<
--------------------------------------------------------------------------------
@ -183,11 +202,11 @@ SAMPLE VIMRC TURNING YOUR NEOVIM INTO A FULL-FEATURED IDE *navigator-sample_vimr
Plug 'neovim/nvim-lspconfig'
Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
Plug 'ray-x/navigator.lua'
" Plug 'hrsh7th/nvim-compe' and other plugins you commenly use...
" Plug 'hrsh7th/nvim-cmp' and other plugins you commenly use...
" optional, if you need treesitter symbol support
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
call plug#end()
" No need for rquire('lspconfig'), navigator will configure it for you
" No need for require('lspconfig'), navigator will configure it for you
lua <<EOF
require'navigator'.setup()
EOF
@ -238,7 +257,7 @@ ALL CONFIGURE OPTIONS *navigator-all_configure_option
Nondefault configuration example:
>
require'navigator'.setup({
debug = false, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
debug = false, -- log output, set to true and log path: ~/.cache/nvim/gh.log
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
@ -258,6 +277,9 @@ Nondefault configuration example:
-- please check mapping.lua for all keymaps
treesitter_analysis = true, -- treesitter variable context
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil or 100 to disable it
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
-- setup here. if it is nil, navigator will not init signature help
signature_help_cfg = nil, -- if you would like to init ray-x/lsp_signature plugin in navigator, and pass in your own config to signature help
icons = {
-- Code action
code_action_icon = "🏏",
@ -268,23 +290,37 @@ Nondefault configuration example:
},
lsp_installer = false, -- set to true if you would like use the lsp installed by williamboman/nvim-lsp-installer
lsp = {
enable = true, -- skip lsp setup if disabled make sure add require('navigator.lspclient.mapping').setup() in you
-- own on_attach
code_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
code_lens_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
format_on_save = true, -- set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
format_on_save = true, -- set to false to disable lsp code format on save (if you are using prettier/efm/formater etc)
disable_format_cap = {"sqls", "sumneko_lua", "gopls"}, -- a list of lsp disable format capacity (e.g. if you using efm or vim-codeformat etc), empty {} by default
disable_lsp = {'pylsd', 'sqlls'}, -- a list of lsp server disabled for your project, e.g. denols and tsserver you may
-- only want to enable one lsp server
-- to disable all default config and use your own lsp setup set
-- disable_lsp = 'all'
-- Default {}
diagnostic = {
underline = true,
virtual_text = true, -- show virtual for diagnostic message
update_in_insert = false, -- update diagnostic message in insert mode
},
diagnostic_scrollbar_sign = {'▃', '▆', '█'}, -- experimental: diagnostic status in scroll bar area; set to false to disable the diagnostic sign,
-- for other style, set to {'╍', 'ﮆ'} or {'-', '='}
diagnostic_virtual_text = true, -- show virtual for diagnostic message
diagnostic_update_in_insert = false, -- update diagnostic message in insert mode
disply_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors, set to false if you want to
ignore it
tsserver = {
filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetypes
},
ctags ={
cmd = 'ctags',
tagfile = 'tags'
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number'
}
gopls = { -- gopls setting
on_attach = function(client, bufnr) -- on_attach for gopls
-- your special on attach here
@ -300,7 +336,8 @@ Nondefault configuration example:
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",
},
servers = {'cmake', 'ltex'}, -- by default empty, but if you whant navigator load e.g. `cmake` and `ltex` for you , you
servers = {'cmake', 'ltex'}, -- by default empty, and it should load all LSP clients avalible based on filetype
-- but if you whant navigator load e.g. `cmake` and `ltex` for you , you
-- can put them in the `servers` list and navigator will auto load them.
-- you could still specify the custom config like this
-- cmake = {filetypes = {'cmake', 'makefile'}, single_file_support = false},
@ -317,7 +354,8 @@ Built clients:
"jedi_language_server", "jdtls", "sumneko_lua", "vimls", "html", "jsonls", "solargraph", "cssls",
"yamlls", "clangd", "ccls", "sqls", "denols", "graphql", "dartls", "dotls",
"kotlin_language_server", "nimls", "intelephense", "vuels", "phpactor", "omnisharp",
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp"
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp", "elixirls",
"sourcekit", "fsautocomplete", "vls", "hls"
}
<
@ -347,12 +385,12 @@ ADD YOUR OWN SERVERS *navigator-add_your_own_server
Above servers covered a small part neovim lspconfig support, You can still use lspconfig to add and config servers not
in the list. If you would like to add a server not in the list, you can check this PR https://github.com/ray-x/navigator.lua/pull/107
Also, an option in setup:
Alternatively, update following option in setup(if you do not want a PR):
>
require'navigator'setup{lsp={servers={'cmake', 'lexls'}}}
<
Above example add cmake and lexls to the default server list
Above option add cmake and lexls to the default server list
DISABLE A LSP CLIENT LOADING FROM NAVIGATOR *navigator-disable_a_lsp_client_loading_from_navigator*
@ -375,11 +413,16 @@ Or:
})
<
TRY IT YOUR SELF *navigator-try_it_your_self*
In `playground` folder, there is a `init.lua` and source code for you to play with. Check playground/README.md (https://github.com/ray-x/navigator.lua/blob/master/playground/README.md) for more details
DEFAULT KEYMAPS *navigator-default_keymaps*
| mode | key | function |
| ---- | --------------- | ---------------------------------------------------------- |
| n | gr | show reference and context |
| n | gr | async references, definitions and context |
| n | <Leader>gr | show reference and context |
| i | <m-k> | signature help |
| n | <c-k> | signature help |
| n | gW | workspace symbol |
@ -390,18 +433,20 @@ DEFAULT KEYMAPS *navigator-default_keymap
| n | gp | definition preview (Go to Preview) |
| n | <C-LeftMouse> | definition |
| n | g<LeftMouse> | implementation |
| n | gT | treesitter document symbol |
| n | <Leader>gt | treesitter document symbol |
| n | <Leader>gT | treesitter symbol for all open buffers |
| n | <Leader> ct | ctags symbol search |
| n | <Leader> cg | ctags symbol generate |
| n | K | hover doc |
| n | <Space>ca | code action (when you see 🏏 ) |
| n | <Space>la | code lens action (when you see a codelens indicator) |
| v | <Space>cA | range code action (when you see 🏏 ) |
| v | <Space>ca | range code action (when you see 🏏 ) |
| n | <Space>rn | rename with floating window |
| n | <Leader>re | rename (lsp default) |
| n | <Leader>gi | hierarchy incoming calls |
| n | <Leader>go | hierarchy outgoing calls |
| n | gi | implementation |
| n | <Sapce> D | type definition |
| n | <Space> D | type definition |
| n | gL | show line diagnostic |
| n | gG | show diagnostic for all buffers |
| n | ]d | next diagnostic |
@ -409,9 +454,9 @@ DEFAULT KEYMAPS *navigator-default_keymap
| n | <Leader> dt | diagnostic toggle(enable/disable) |
| n | ]r | next treesitter reference/usage |
| n | [r | previous treesitter reference/usage |
| n | <Sapce> wa | add workspace folder |
| n | <Sapce> wr | remove workspace folder |
| n | <Sapce> wl | print workspace folder |
| n | <Space> wa | add workspace folder |
| n | <Space> wr | remove workspace folder |
| n | <Space> wl | print workspace folder |
| n | <Leader>k | toggle reference highlight |
| i/n | <C-p> | previous item in list |
| i/n | <C-n> | next item in list |
@ -432,13 +477,13 @@ DEFAULT KEYMAPS *navigator-default_keymap
COLORS/HIGHLIGHT: *navigator-colors/highlight:*
You can override default highlight GHListDark (listview) and GHTextViewDark (code view) and GHListHl (select item)
You can override default highlight GuihuaListDark (listview) and GuihuaTextViewDark (code view) and GuihuaListHl (select item)
e.g.
>
hi default GHTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GHListDark guifg=#e0d8f4 guibg=#103234
hi default GHListHl guifg=#e0d8f4 guibg=#404254
hi default GuihuaTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GuihuaListDark guifg=#e0d8f4 guibg=#103234
hi default GuihuaListHl guifg=#e0d8f4 guibg=#404254
<
There are other Lsp highlight been used in this plugin, e.g LspReferenceRead/Text/Write are used for document highlight,
@ -458,19 +503,43 @@ The plugin can be loaded lazily (packer `opt = true` ), And it will check if opt
The terminal will need to be able to output nerdfont and emoji correctly. I am using Kitty with nerdfont (Victor Mono).
--------------------------------------------------------------------------------
INTEGRATION WITH LSP_INSTALLER (WILLIAMBOMAN/NVIM-LSP-INSTALLER) *navigator-integration_with_lsp_installer_(williamboman/nvim-lsp-installer)*
INTEGRAT WITH LSP_INSTALLER (WILLIAMBOMAN/NVIM-LSP-INSTALLER) *navigator-integrat_with_lsp_installer_(williamboman/nvim-lsp-installer)*
If you'd like to only use the lsp servers installed by lsp_installer. Please set
If you are using lsp_installer and would like to use the lsp servers installed by lsp_installer. Please set
>
lsp_installer = true
<
In the config.
In the config. Also please setup the lsp server from installer setup with `server:setup{opts}`
example:
>
use({
'williamboman/nvim-lsp-installer',
config = function()
local lsp_installer = require('nvim-lsp-installer')
lsp_installer.setup{}
end,
})
use({
'ray-x/navigator.lua',
config = function()
require('navigator').setup({
debug = true,
lsp_installer = true,
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
})
end,
})
<
Navigator will startup the server installed by lsp-installer. Please do not call `server:setup{opts}` from lsp installer
Please refer to lsp_installer_config (https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
for more info
Alternatively, Navigator can be used to startup the server installed by lsp-installer.
as it will override the navigator setup
Also, could use following setups
To start LSP installed by lsp_installer, please use following setups
>
require'navigator'.setup({
-- lsp_installer = false -- default value is false
@ -482,7 +551,70 @@ Also, could use following setups
example cmd setup (mac) for pyright :
>
cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" }
require'navigator'.setup({
-- lsp_installer = false -- default value is false
lsp = {
tsserver = {
cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" }
}
}
}
<
The lsp servers installed by nvim-lsp-installer is in following dir
>
local path = require 'nvim-lsp-installer.path'
local install_root_dir = path.concat {vim.fn.stdpath 'data', 'lsp_servers'}
<
And you can setup binary full path to this: (e.g. with gopls)
`install_root_dir .. '/go/gopls'` So the config is
>
local path = require 'nvim-lsp-installer.path'
local install_root_dir = path.concat {vim.fn.stdpath 'data', 'lsp_servers'}
require'navigator'.setup({
-- lsp_installer = false -- default value is false
lsp = {
gopls = {
cmd = { install_root_dir .. '/go/gopls' }
}
}
}
<
Use lsp_installer configs
You can delegate the lsp server setup to lsp_installer with `server:setup{opts}`
Here is an example init_lsp_installer.lua (https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
INTEGRATION WITH OTHER LSP PLUGINS (E.G. RUST-TOOLS, GO.NVIM, CLANGD EXTENSION) *navigator-integration_with_other_lsp_plugins_(e.g._rust-tools,_go.nvim,_clangd_extension)*
There are lots of plugins provides lsp support
go.nvim allow you either hook gopls from go.nvim or from navigator and it can export the lsp setup from go.nvim.
rust-tools and clangd allow you to setup on_attach from config server
Here is an example to setup rust with rust-tools
>
require'navigator'.setup({
lsp = {
disable_lsp = { "rust_analyzer", "clangd" }, -- will not run rust_analyzer setup from navigator
}
})
require('rust-tools').setup({
server = {
on_attach = function(_, _)
require('navigator.lspclient.mapping').setup() -- setup navigator keymaps here,
-- otherwise, you can define your own commands to call navigator functions
end,
}
})
require("clangd_extensions").setup {
server = {
on_attach = function(_, _)
require('navigator.lspclient.mapping').setup() -- setup navigator keymaps here,
-- otherwise, you can define your own commands to call navigator functions
end,
}
}
<
--------------------------------------------------------------------------------
@ -512,7 +644,7 @@ Highlight I am using:
* LspReferenceRead, LspReferenceText and LspReferenceWrite are used for `autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()`
That is where you saw the current symbol been highlighted.
* GHListDark and GHTextViewDark is used for floating listvew and TextView. They are be based on current background
* GuihuaListDark and GuihuaTextViewDark is used for floating listvew and TextView. They are be based on current background
(Normal) and PmenuSel
* In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat
@ -521,10 +653,45 @@ You can override the above highlight to fit your current colorscheme
--------------------------------------------------------------------------------
COMMANDS *navigator-commands*
| command | function |
| ------------ | ---------------------- |
| LspToggleFmt | toggle lsp auto format |
| command | function |
| ------------ | ------------------------- |
| LspToggleFmt | toggle lsp auto format |
| LspKeymaps | show LSP releated keymaps |
| Nctags {args} | show ctags symbols, args: -g regen ctags |
| LspRestart | reload lsp |
| LspSymbols | document symbol in side panel |
| NRefPanel |symbol reference in side panel |
| TSymobls | treesitter symbol in side panel |
| Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) |
:LspToggleFmt *:LspToggleFmt*
Toggle lsp auto format.
:LspKeymaps *:LspKeymaps*
Show Lsp keymaps.
:Nctags [flags] *:Nctags*
Show ctags symbols.
[flags]:
-g regen ctags
:LspRestart *:LspRestart*
Restart Lsp.
:LspSymbols *:LspSymbols*
Lsp document symbol in side panel.
:TSSymbols *:TSSymbols*
Treesitter symbol in side panel.
:NRefPanel *:NRefPanel*
Symbol reference in side panel.
:Calltree [flags] *:Calltree*
Lsp call hierarchy call tree.
[flags]:
-i: incomming default
-o: outgoing
--------------------------------------------------------------------------------
SCREENSHOTS *navigator-screenshots*
@ -540,15 +707,27 @@ Using treesitter and LSP to view the symbol definition
SIDEBAR, FOLDING, OUTLINE *navigator-sidebar,_folding,_outline*
Treesitter outline and Diagnostics
GUI AND MULTIGRID SUPPORT *navigator-gui_and_multigrid_support*
You can load a different font size for floating win
DOCUMENT SYMBOL *navigator-document_symbol*
DOCUMENT SYMBOL AND NAVIGATE THROUGH THE LIST *navigator-document_symbol_and_navigate_through_the_list*
The key binding to navigate in the list.
* up and down key
* `<Ctrl-f/b>` for page up and down
* number key 1~9 go to the ith item.
* If there are loads of results, would be good to use fzy search prompt to filter out the result you are interested.
WORKSPACE SYMBOL *navigator-workspace_symbol*
@ -647,6 +826,16 @@ PREDEFINED LSP SYMBOL NERDFONT/EMOJI *navigator-predefined_lsp_symbol_nerdfont/e
VS-CODE STYLE FOLDING WITH TREESITTER *navigator-vs-code_style_folding_with_treesitter*
FOLDING FUNCTION *navigator-folding_function*
FOLDING COMMENTS *navigator-folding_comments*
================================================================================
DEBUG THE PLUGIN *navigator-debug_the_plugin*
@ -689,3 +878,6 @@ ERRORS AND BUG REPORTING *navigator-errors_and_bug_reportin
* Check console output
* Check `LspInfo` and treesitter status with `checkhealth`
* Turn on log and attach the log to your issue if possible you can remove any personal/company info in the log
* Submit Issue with minium vimrc. Please check playground/init.lua as a vimrc template. !!!Please DONOT use a packer vimrc
that installs everything to default folder!!! Also check this repo navigator bug report (https://github.com/fky2015/navigator.nvim-bug-report)

@ -1,11 +1,14 @@
local M = {}
local api = vim.api
local function warn(msg)
vim.api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {})
api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {})
end
local function info(msg)
vim.api.nvim_echo({ { 'Info: ' .. msg } }, true, {})
if _NgConfigValues.debug then
api.nvim_echo({ { 'Info: ' .. msg } }, true, {})
end
end
_NgConfigValues = {
@ -16,7 +19,7 @@ _NgConfigValues = {
preview_lines = 40, -- total lines in preview screen
preview_lines_before = 5, -- lines before the highlight line
default_mapping = true,
keymaps = {}, -- e.g keymaps={{key = "GR", func = "references()"}, } this replace gr default mapping
keymaps = {}, -- e.g keymaps={{key = "GR", func = vim.lsp.buf.references}, } this replace gr default mapping
external = nil, -- true: enable for goneovim multigrid otherwise false
border = 'single', -- border style, can be one of 'none', 'single', 'double', "shadow"
@ -28,11 +31,19 @@ _NgConfigValues = {
end,
ts_fold = false,
treesitter_analysis = true, -- treesitter variable context
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis
treesitter_analysis_condense = true, -- short format of function
transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil to disable it
lsp_signature_help = true, -- if you would like to hook ray-x/lsp_signature plugin in navigator
-- setup here. if it is nil, navigator will not init signature help
signature_help_cfg = { debug = false }, -- if you would like to init ray-x/lsp_signature plugin in navigator, pass in signature help
ctags = {
cmd = 'ctags',
tagfile = '.tags',
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
},
lsp = {
enable = true, -- if disabled make sure add require('navigator.lspclient.mapping').setup() in you on_attach
code_action = {
enable = true,
sign = true,
@ -40,6 +51,7 @@ _NgConfigValues = {
virtual_text = true,
virtual_text_icon = true,
},
document_highlight = true, -- highlight reference a symbol
code_lens_action = {
enable = true,
sign = true,
@ -54,6 +66,8 @@ _NgConfigValues = {
severity_sort = { reverse = true },
},
format_on_save = true, -- set to false to disasble lsp code format on save (if you are using prettier/efm/formater etc)
format_options = { async = false }, -- async: disable by default, I saw something unexpected
disable_nulls_codeaction_sign = true, -- do not show nulls codeactions (as it will alway has a valid action)
disable_format_cap = {}, -- a list of lsp disable file format (e.g. if you using efm or vim-codeformat etc), empty by default
disable_lsp = {}, -- a list of lsp server disabled for your project, e.g. denols and tsserver you may
-- only want to enable one lsp server
@ -67,6 +81,10 @@ _NgConfigValues = {
-- filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetype
},
['lua-dev'] = { -- navigator can use lua-dev settings to setup sumneko_lua
-- your setting for lua-dev here
-- navigator will setup lua-dev
},
sumneko_lua = {
-- sumneko_root_path = sumneko_root_path,
-- sumneko_binary = sumneko_binary,
@ -75,6 +93,7 @@ _NgConfigValues = {
servers = {}, -- you can add additional lsp server so navigator will load the default for you
},
lsp_installer = false, -- set to true if you would like use the lsp installed by williamboman/nvim-lsp-installer
mason = false, -- set to true if you would like use the lsp installed by williamboman/mason
icons = {
icons = true, -- set to false to use system default ( if you using a terminal does not have nerd/icon)
-- Code action
@ -97,6 +116,15 @@ _NgConfigValues = {
-- Values
value_changed = '📝',
value_definition = '🐶🍡', -- it is easier to see than 🦕
side_panel = {
section_separator = '',
line_num_left = '',
line_num_right = '',
inner_node = '├○',
outer_node = '╰○',
bracket_left = '',
bracket_right = '',
},
-- Treesitter
match_kinds = {
var = '', -- "👹", -- Vampaire
@ -107,18 +135,15 @@ _NgConfigValues = {
namespace = '🚀',
type = '',
field = '🏈',
module = '📦',
flag = '🎏',
},
treesitter_defult = '🌲',
doc_symbols = '',
},
}
vim.cmd("command! -nargs=0 LspLog lua require'navigator.lspclient.config'.open_lsp_log()")
vim.cmd("command! -nargs=0 LspRestart lua require'navigator.lspclient.config'.reload_lsp()")
vim.cmd("command! -nargs=0 LspToggleFmt lua require'navigator.lspclient.mapping'.toggle_lspformat()<CR>")
vim.cmd("command! -nargs=0 LspKeymaps lua require'navigator.lspclient.mapping'.get_keymaps_help()<CR>")
M.deprecated = function(cfg)
local warn = require('navigator.util').warn
if cfg.code_action_prompt then
warn('code_action_prompt moved to lsp.code_action')
end
@ -144,6 +169,11 @@ local extend_config = function(opts)
if next(opts) == nil then
return
end
if opts.debug then
_NgConfigValues.debug = opts.debug
end
-- enable logs
require('navigator.util').setup()
for key, value in pairs(opts) do
if _NgConfigValues[key] == nil then
warn(
@ -186,12 +216,12 @@ local extend_config = function(opts)
else
if _NgConfigValues[key][k] == nil then
if key == 'lsp' then
local lsp = require('navigator.lspclient.clients').lsp
local lsp = require('navigator.lspclient.servers')
if not vim.tbl_contains(lsp or {}, k) and k ~= 'efm' and k ~= 'null-ls' then
info(string.format('[] extend LSP support for %s ', k))
info(string.format('[] extend LSP support for %s %s ', key, k))
end
elseif key == 'keymaps' then
info('keymap override')
info('keymap override' .. vim.inspect(v))
-- skip key check and allow mapping to handle that
else
warn(string.format('[] Key %s %s not valid', key, k))
@ -221,7 +251,14 @@ M.setup = function(cfg)
cfg = cfg or {}
extend_config(cfg)
vim.cmd([[autocmd FileType,BufEnter * lua require'navigator.lspclient.clients'.on_filetype()]]) -- BufWinEnter BufNewFile,BufRead ?
local cmd_group = api.nvim_create_augroup('NGFtGroup', {})
api.nvim_create_autocmd({ 'FileType', 'BufEnter' }, {
group = cmd_group,
pattern = '*',
callback = function()
require('navigator.lspclient.clients').on_filetype()
end,
})
require('navigator.lazyloader').init()
require('navigator.lspclient.clients').setup(_NgConfigValues)
@ -231,7 +268,10 @@ M.setup = function(cfg)
require('navigator.implementation')
cfg.lsp = cfg.lsp or _NgConfigValues.lsp
require('navigator.diagnostics').config(cfg.lsp.diagnostic)
if _NgConfigValues.lsp.enable then
require('navigator.diagnostics').config(cfg.lsp.diagnostic)
end
if not _NgConfigValues.loaded then
_NgConfigValues.loaded = true
end
@ -246,7 +286,6 @@ M.setup = function(cfg)
local _start_client = vim.lsp.start_client
vim.lsp.start_client = function(lsp_config)
-- add highlight for Lspxxx
require('navigator.dochighlight').documentHighlight()
require('navigator.lspclient.highlight').add_highlight()
require('navigator.lspclient.highlight').diagnositc_config_sign()
-- require('navigator.lspclient.mapping').setup()

@ -51,7 +51,7 @@ end
local call_hierarchy_handler_from = partial(call_hierarchy_handler, 'from')
local call_hierarchy_handler_to = partial(call_hierarchy_handler, 'to')
local function incoming_calls_handler(bang, err, result, ctx, cfg)
local function incoming_calls_handler(_, err, result, ctx, cfg)
local bufnr = vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
@ -61,7 +61,7 @@ local function incoming_calls_handler(bang, err, result, ctx, cfg)
gui.new_list_view({ items = results, ft = ft or 'cpp', api = '' })
end
-- err, method, result, client_id, bufnr
local function outgoing_calls_handler(bang, err, result, ctx, cfg)
local function outgoing_calls_handler(_, err, result, ctx, cfg)
local results = call_hierarchy_handler_to(err, result, ctx, cfg, 'Outgoing calls not found')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')

@ -2,7 +2,7 @@ local util = require('navigator.util')
local log = util.log
local trace = util.trace
local code_action = {}
local gui = require('navigator.gui')
-- local gui = require('navigator.gui')
local config = require('navigator').config_values()
local api = vim.api
@ -52,20 +52,24 @@ local function _update_sign(line)
if code_action[winid] == nil then
code_action[winid] = {}
end
if code_action[winid].lightbulb_line ~= 0 then
-- only show code action on the current line, remove all others
if code_action[winid].lightbulb_line and code_action[winid].lightbulb_line > 0 then
vim.fn.sign_unplace(sign_group, { id = code_action[winid].lightbulb_line, buffer = '%' })
log('sign removed', line)
end
if line then
-- log("updatasign", line, sign_group, sign_name)
vim.fn.sign_place(
local id = vim.fn.sign_place(
line,
sign_group,
sign_name,
'%',
{ lnum = line + 1, priority = config.lsp.code_action.sign_priority }
)
code_action[winid].lightbulb_line = line
code_action[winid].lightbulb_line = id
log('sign updated', id)
end
end
@ -74,6 +78,14 @@ local need_check_diagnostic = { ['python'] = true }
function code_action:render_action_virtual_text(line, diagnostics)
return function(err, actions, context)
trace(actions, context)
if context and context.client_id then
local cname = vim.lsp.get_active_clients({ id = context.client_id })[1].name
if cname == 'null-ls' and _NgConfigValues.lsp.disable_nulls_codeaction_sign then
return
end
end
-- if nul-ls enabled, some of the lsp may not send valid code action,
if actions == nil or type(actions) ~= 'table' or vim.tbl_isempty(actions) then
-- no actions cleanup
if config.lsp.code_action.virtual_text then
@ -84,12 +96,13 @@ function code_action:render_action_virtual_text(line, diagnostics)
end
else
trace(err, line, diagnostics, actions, context)
if config.lsp.code_action.sign then
if need_check_diagnostic[vim.bo.filetype] then
if next(diagnostics) == nil then
-- no diagnostic, no code action sign..
_update_sign(nil)
else
-- no diagnostic, no code action sign..
_update_sign(line)
end
else
@ -139,9 +152,13 @@ local code_action_req = function(_call_back_fn, diagnostics)
end
local function sort_select(action_tuples, opts, on_user_choice)
-- table.sort(action_tuples, function(a, b)
-- return a[1] > b[1]
-- end)
if action_tuples ~= nil and action_tuples[1][2] ~= nil and action_tuples[1][2].command then
table.sort(action_tuples, function(a, b)
return a[1] > b[1]
end)
end
trace(action_tuples)
require('guihua.gui').select(action_tuples, opts, on_user_choice)
end
@ -149,8 +166,6 @@ code_action.code_action = function()
local original_select = vim.ui.select
vim.ui.select = sort_select
log('codeaction')
vim.lsp.buf.code_action()
vim.defer_fn(function()
vim.ui.select = original_select
@ -160,19 +175,32 @@ end
code_action.range_code_action = function(startpos, endpos)
local context = {}
context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
local params = util.make_given_range_params(startpos, endpos)
local bufnr = vim.api.nvim_get_current_buf()
startpos = startpos or api.nvim_buf_get_mark(bufnr, '<')
endpos = endpos or api.nvim_buf_get_mark(bufnr, '>')
log(startpos, endpos)
local params = vim.lsp.util.make_given_range_params(startpos, endpos)
params.context = context
local original_select = vim.ui.select
vim.ui.select = require('guihua.gui').select
vim.lsp.buf.range_code_action(context, startpos, endpos)
local original_input = vim.ui.input
vim.ui.input = require('guihua.input').input
if vim.fn.has('nvim-0.8') then
vim.lsp.buf.code_action({context=context ,range={start = startpos, ['end'] = endpos}})
else
vim.lsp.buf.range_code_action(context, startpos, endpos)
end
vim.defer_fn(function()
vim.ui.select = original_select
vim.ui.input = original_input
end, 1000)
end
code_action.code_action_prompt = function()
code_action.code_action_prompt = function(bufnr)
if special_buffers[vim.bo.filetype] then
log('skip buffer', vim.bo.filetype)
return

@ -5,10 +5,9 @@ local codelens = require('vim.lsp.codelens')
local log = require('navigator.util').log
local trace = require('navigator.util').trace
-- trace = log
local lsphelper = require('navigator.lspwrapper')
local api = vim.api
local gui = require('navigator.gui')
local M = {}
local config = require('navigator').config_values()
@ -62,24 +61,19 @@ local codelens_hdlr = function(err, result, ctx, cfg)
end
end
function M.setup()
vim.cmd('highlight! link LspCodeLens LspDiagnosticsHint')
vim.cmd('highlight! link LspCodeLensText LspDiagnosticsInformation')
vim.cmd('highlight! link LspCodeLensTextSign LspDiagnosticsSignInformation')
vim.cmd('highlight! link LspCodeLensTextSeparator Boolean')
vim.cmd('augroup navigator.codelenses')
vim.cmd(' autocmd!')
vim.cmd("autocmd BufEnter,CursorHold,InsertLeave <buffer> lua require('navigator.codelens').refresh()")
vim.cmd('augroup end')
local on_codelens = vim.lsp.handlers['textDocument/codeLens']
vim.lsp.handlers['textDocument/codeLens'] = function(err, result, ctx, cfg)
-- trace(err, result, ctx.client_id, ctx.bufnr, cfg or {})
cfg = cfg or {}
ctx = ctx or { bufnr = vim.api.nvim_get_current_buf() }
on_codelens(err, result, ctx, cfg)
codelens_hdlr(err, result, ctx, cfg)
end
function M.setup(bufnr)
log('setup for ****** ', bufnr)
vim.api.nvim_set_hl(0, 'LspCodeLens', { link = 'DiagnosticsHint', default = true })
vim.api.nvim_set_hl(0, 'LspCodeLensText', { link = 'DiagnosticsInformation', default = true })
vim.api.nvim_set_hl(0, 'LspCodeLensSign', { link = 'DiagnosticsInformation', default = true })
vim.api.nvim_set_hl(0, 'LspCodeLensSeparator', { link = 'Boolean', default = true })
vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI', 'InsertLeave' }, {
group = vim.api.nvim_create_augroup('nv__codelenses', {}),
buffer = bufnr or vim.api.nvim_win_get_buf(),
callback = function()
require('navigator.codelens').refresh()
end,
})
end
M.lsp_clients = {}
@ -92,7 +86,7 @@ function M.refresh()
if not lsphelper.check_capabilities('codeLensProvider') then
return
end
vim.lsp.codelens.refresh()
M.inline()
end
local virtual_types_ns = api.nvim_create_namespace('ng_virtual_types')
@ -107,12 +101,13 @@ function M.run_action()
local original_select = vim.ui.select
vim.ui.select = require('guihua.gui').select
log('codeaction')
log('codelens action')
codelens.run()
vim.defer_fn(function()
vim.ui.select = original_select
end, 1000)
end
M.inline = function()
@ -130,42 +125,20 @@ M.inline = function()
local bufnr = api.nvim_get_current_buf()
local parameter = lsp.util.make_position_params()
local response = lsp.buf_request_sync(bufnr, 'textDocument/codeLens', parameter)
-- Clear previous highlighting
api.nvim_buf_clear_namespace(bufnr, virtual_types_ns, 0, -1)
if response then
log(response)
for _, v in ipairs(response) do
if v == nil or v.result == nil then
return
end -- no response
for _, vv in pairs(v.result) do
local start_line = -1
for _, vvv in pairs(vv.range) do
start_line = tonumber(vvv.line)
end
local cmd = vv.command
local msg = _NgConfigValues.icons.code_action_icon .. ' '
if cmd then
local txt = cmd.title or ''
txt = txt .. ' ' .. (cmd.command or '') .. ' '
msg = msg .. txt .. ' '
end
log(msg)
api.nvim_buf_set_extmark(bufnr, virtual_types_ns, start_line, -1, {
virt_text = { { msg, 'LspCodeLensText' } },
virt_text_pos = 'overlay',
hl_mode = 'combine',
})
end
local on_codelens = vim.lsp.handlers['textDocument/codeLens']
lsp.buf_request(bufnr, 'textDocument/codeLens', parameter, function(err, response, ctx, _)
-- Clear previous highlighting
api.nvim_buf_clear_namespace(bufnr, virtual_types_ns, 0, -1)
if response then
trace(response)
on_codelens(err, response, ctx, _)
codelens_hdlr (err, response, ctx, _)
end
-- else
-- api.nvim_command("echohl WarningMsg | echo 'VirtualTypes: No response' | echohl None")
end
end)
end
return M

@ -0,0 +1,177 @@
local type_to_lspkind = { c = 5, m = 7, f = 6, s = 5 }
local util = require('navigator.util')
local log = util.log
local sep = util.path_sep()
local vfn = vim.fn
local cur_dir = vfn.getcwd()
-- convert ctags line to lsp entry
local function entry_to_item(entry)
local item = {}
item.name, item.filename, item.line, item.remain = string.match(entry, '(.*)\t(.*)\t(%d+);(.*)')
local type = 'combine'
item.remain = item.remain or ''
if item.remain:sub(1, 1) == [["]] then
type = 'number'
end
if item.name == nil or item.filename == nil then
return
end
if type == 'combine' then
-- '/^type ServerResponse struct {$/;"\ts\tpackage:client'
item.inline, item.type, item.containerName, item.ref = string.match(item.remain, '/^(.*)$/;"\t(%a)\t(.+)')
else
-- '"\tm\tstruct:store.Customer\ttyperef:typename:string'
item.type, item.containerName, item.ref = string.match(item.remain, '"\t(%a)\t(.+)')
end
item.kind = type_to_lspkind[item.type] or 13
item.lnum = tonumber(item.line) - 1
item.location = {
uri = 'file://' .. cur_dir .. sep .. item.filename,
range = {
start = { line = item.lnum, character = 0 },
['end'] = { line = item.lnum, character = 0 },
},
}
item.uri = 'file://' .. cur_dir .. sep .. item.filename
item.range = {
start = { line = item.lnum, character = 0 },
['end'] = { line = item.lnum, character = 0 },
}
-- item.detail = (item.containerName or '') .. (item.ref or '')
-- item.text = '[' .. kind .. ']' .. item.name .. ' ' .. item.detail
if item.lnum == nil then
vim.notify('incorrect ctags format, need run ctag with "-excmd=number|combine" option')
end
item.remain = nil
return item
end
local function ctags_gen()
local cmd = 'ctags' -- -x -n -u -f - ' .. vfn.expand('%:p')
local output = _NgConfigValues.ctags.tagfile
-- rm file first
util.rm_file(output)
local options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number '
if _NgConfigValues.ctags then
cmd = _NgConfigValues.ctags.cmd
options = _NgConfigValues.ctags.options or options
end
local lang = vim.o.ft
options = options .. '--language=' .. lang
cmd = cmd .. ' ' .. options
cmd = string.format('%s -f %s %s --language=%s', cmd, output, options, lang)
cmd = vim.split(cmd, ' ')
log(cmd)
vfn.jobstart(cmd, {
on_stdout = function(_, _, _)
vim.notify('ctags completed')
end,
on_exit = function(_, data, _) -- id, data, event
-- log(vim.inspect(data) .. "exit")
if data and data ~= 0 then
return vim.notify(cmd .. ' failed ' .. tostring(data), vim.lsp.log_levels.ERROR)
else
vim.notify('ctags generated')
end
end,
})
end
local symbols_to_items = require('navigator.lspwrapper').symbols_to_items
local function ctags_symbols()
local height = _NgConfigValues.height or 0.4
local width = _NgConfigValues.width or 0.7
height = math.floor(height * vfn.winheight('%'))
width = math.floor(vim.api.nvim_get_option('columns') * width)
local items = {}
local ctags_file = _NgConfigValues.ctags.tagfile
if not util.file_exists(ctags_file) then
ctags_gen()
vim.cmd('sleep 200m')
end
local cnts = util.io_read(ctags_file)
if cnts == nil then
return vim.notify('ctags file ' .. ctags_file .. ' not found')
end
cnts = vfn.split(cnts, '\n')
for _, value in pairs(cnts) do
local it = entry_to_item(value)
if it then
table.insert(items, it)
end
end
cnts = nil
local ft = vim.o.ft
local result = symbols_to_items(items)
if next(result) == nil then
return vim.notify('no symbols found')
end
log(result[1])
local opt = {
api = '',
ft = ft,
bg = 'GuihuaListDark',
data = result,
items = result,
enter = true,
loc = 'top_center',
transparency = 50,
prompt = true,
rawdata = true,
rect = { height = height, pos_x = 0, pos_y = 0, width = width },
}
require('navigator.gui').new_list_view(opt)
end
-- gen_ctags()
local function ctags(...)
local gen = select(1, ...)
log(gen)
if gen == '-g' then
ctags_gen()
vim.cmd('sleep 200m')
ctags_symbols()
else
ctags_symbols()
end
end
local function testitem()
local e = [[ServerResponse internal/clients/server.go /^type ServerResponse struct {$/;" s package:client]]
local ecombine = [[ServerResponse internal/clients/server.go 5;/^type ServerResponse struct {$/;" s package:client]]
local enumber = [[CustomerID internal/store/models.go 17;" m struct:store.Customer typeref:typename:string]]
local enumber2 = [[CustomerDescription internal/controllers/customer.go 27;" c package:controllers]]
local enumber3 = [[add_servers lua/navigator/lspclient/clients.lua 680;" f]]
local i = entry_to_item(ecombine)
print(vim.inspect(i))
i = entry_to_item(enumber)
print(vim.inspect(i))
i = entry_to_item(enumber2)
print(vim.inspect(i))
i = entry_to_item(enumber3)
print(vim.inspect(i))
i = entry_to_item(e)
print(vim.inspect(i))
end
-- testitem()
-- gen_ctags()
-- ctags_symbols()
return {
ctags_gen = ctags_gen,
ctags = ctags,
ctags_symbols = ctags_symbols,
}

@ -3,6 +3,7 @@ local lsphelper = require('navigator.lspwrapper')
local locations_to_items = lsphelper.locations_to_items
local gui = require('navigator.gui')
local log = util.log
local trace = util.trace
local TextView = require('guihua.textview')
-- callback for lsp definition, implementation and declaration handler
local definition_hdlr = function(err, locations, ctx, _)
@ -21,6 +22,10 @@ local definition_hdlr = function(err, locations, ctx, _)
end
local oe = require('navigator.util').encoding(ctx.client_id)
locations = util.dedup(locations)
log(locations)
log("found " .. #locations .. " locations")
if vim.tbl_islist(locations) then
if #locations > 1 then
local items = locations_to_items(locations)
@ -69,7 +74,7 @@ local function def_preview(timeout_ms)
local row = range.start.line
-- in case there are comments
row = math.max(row - 3, 1)
local delta = range.start.line - row + 1
local delta = range.start.line - row + 3
local uri = data[1].uri or data[1].targetUri
if not uri then
return
@ -80,19 +85,27 @@ local function def_preview(timeout_ms)
end
local ok, parsers = pcall(require, 'nvim-treesitter.parsers')
local lines_num = 12
-- TODO: 32/64 should be an option
local lines_num = 64
if range['end'] ~= nil then
lines_num = math.max(lines_num, range['end'].line - range.start.line + 4)
end
if ok then
local ts = require('navigator.treesitter')
local root = parsers.get_parser(bufnr)
log(range)
if ts == nil then
return
end
local def_node = ts.get_node_at_pos({ range['start'].line, range['start'].character }, root)
local sr, _, er, _ = ts.get_node_scope(def_node)
log(sr, er)
lines_num = math.max(lines_num, er - sr + 3) -- comments etc
lines_num = math.max(lines_num, er - sr + 5) -- comments etc
end
-- TODO: 12 should be an option
-- TODO: 32 should be an option
local definition = vim.api.nvim_buf_get_lines(bufnr, row, range['end'].line + lines_num, false)
local def_line = vim.api.nvim_buf_get_lines(bufnr, range.start.line, range.start.line + 1, false)
for _ = 1, math.min(3, #definition), 1 do
@ -104,8 +117,9 @@ local function def_preview(timeout_ms)
end
end
local width = 40
local maxwidth = math.floor(vim.fn.winwidth(0) * 4 / 5)
for key, value in pairs(definition) do
local maxwidth = math.floor( vim.api.nvim_get_option('columns') * 0.8)
for _, value in pairs(definition) do
-- log(key, value, width)
width = math.max(width, #value + 4)
width = math.min(maxwidth, width)
@ -118,7 +132,7 @@ local function def_preview(timeout_ms)
relative = 'cursor',
style = 'minimal',
ft = filetype,
rect = { width = width, height = #definition + 3 },
rect = { width = width, height = math.min(#definition + 3, 16), pos_y = 2 }, -- TODO: 16 hardcoded
data = definition,
enter = true,
border = _NgConfigValues.border or 'shadow',
@ -143,7 +157,7 @@ local def = function()
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _bufnr)
-- if client.resolved_capabilities.goto_definition then
if client.server_capabilities.definitionProvider then
client.request('textDocument/definition', ref_params, definition_hdlr, _bufnr)

@ -2,7 +2,6 @@ local gui = require('navigator.gui')
local diagnostic_list = {}
local diagnostic = vim.diagnostic or vim.lsp.diagnostic
-- local hide = diagnostic.hide or diagnostic.clear
_NG_VT_DIAG_NS = vim.api.nvim_create_namespace('navigator_lua_diag')
local util = require('navigator.util')
local log = util.log
local trace = require('guihua.log').trace
@ -11,6 +10,8 @@ local error = util.error
local path_sep = require('navigator.util').path_sep()
local path_cur = require('navigator.util').path_cur()
local empty = util.empty
local api = vim.api
_NG_VT_DIAG_NS = api.nvim_create_namespace('navigator_lua_diag')
if not util.nvim_0_6_1() then
util.warn('Navigator 0.4+ only support nvim-0.6+, please use Navigator 0.3.x or a newer version of neovim')
@ -27,24 +28,7 @@ if vim.diagnostic then
}
end
local diagnostic_cfg = {
-- Enable underline, use default values
underline = _NgConfigValues.lsp.diagnostic.underline,
-- Enable virtual
-- Use a function to dynamically turn signs off
-- and on, using buffer local variables
signs = true,
update_in_insert = _NgConfigValues.lsp.diagnostic.update_in_insert or false,
severity_sort = _NgConfigValues.lsp.diagnostic.severity_sort,
float = {
focusable = false,
style = 'minimal',
border = 'rounded',
source = 'always',
header = '',
prefix = '',
},
}
local diagnostic_cfg
local function get_count(bufnr, level)
if vim.diagnostic ~= nil then
@ -74,15 +58,18 @@ local function error_marker(result, ctx, config)
if bufnr == nil then
bufnr = vim.uri_to_bufnr(result.uri)
end
local fname = vim.api.nvim_buf_get_name(bufnr)
local success, fname = pcall(api.nvim_buf_get_name, bufnr)
if not success then
return
end
local uri = vim.uri_from_fname(fname)
if uri ~= result.uri then
log('not same buf', ctx, result.uri, bufnr, vim.fn.bufnr())
return
end
if not vim.api.nvim_buf_is_loaded(bufnr) then
log('buf not loaded', bufnr)
if not api.nvim_buf_is_loaded(bufnr) then
trace('buf not loaded', bufnr)
return
end
@ -93,7 +80,7 @@ local function error_marker(result, ctx, config)
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then
log('great no errors')
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
end
return
end
@ -101,12 +88,12 @@ local function error_marker(result, ctx, config)
-- total line num of current buffer
-- local winid = vim.fn.win_getid(vim.fn.winnr())
-- local winid = vim.api.nvim_get_current_win()
local total_num = vim.api.nvim_buf_line_count(bufnr)
-- local winid = api.nvim_get_current_win()
local total_num = api.nvim_buf_line_count(bufnr)
-- local total_num = vim.fn.getbufinfo(vim.fn.winbufnr(winid))[1].linecount
-- window size of current buffer
local stats = vim.api.nvim_list_uis()[1]
local stats = api.nvim_list_uis()[1]
-- local wwidth = stats.width;
local wheight = stats.height
@ -114,7 +101,7 @@ local function error_marker(result, ctx, config)
return
end
if _NG_VT_DIAG_NS == nil then
_NG_VT_DIAG_NS = vim.api.nvim_create_namespace('navigator_lua_diag')
_NG_VT_DIAG_NS = api.nvim_create_namespace('navigator_lua_diag')
end
local pos = {}
@ -156,7 +143,7 @@ local function error_marker(result, ctx, config)
end
if not vim.tbl_isempty(pos) then
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
end
for _, s in pairs(pos) do
local hl = 'ErrorMsg'
@ -177,7 +164,7 @@ local function error_marker(result, ctx, config)
end
trace('add pos', s, bufnr)
vim.api.nvim_buf_set_extmark(
api.nvim_buf_set_extmark(
bufnr,
_NG_VT_DIAG_NS,
l,
@ -201,9 +188,9 @@ local diag_hdlr = function(err, result, ctx, config)
return
end
local mode = vim.api.nvim_get_mode().mode
local mode = api.nvim_get_mode().mode
if mode ~= 'n' and config.update_in_insert == false then
log('skip sign update in insert mode')
trace('skip sign update in insert mode')
end
local cwd = vim.loop.cwd()
local ft = vim.bo.filetype
@ -239,14 +226,18 @@ local diag_hdlr = function(err, result, ctx, config)
item.uri = uri
-- trace(item)
local head = _NgConfigValues.icons.diagnostic_head
if v.severity == 1 then
head = _NgConfigValues.icons.diagnostic_head_severity_1
end
if v.severity == 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_2
end
if v.severity > 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_3
if v.severity then
if v.severity == 1 then
head = _NgConfigValues.icons.diagnostic_head_severity_1
end
if v.severity == 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_2
end
if v.severity > 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_3
end
else
v.severity = 2
end
if v.relatedInformation and v.relatedInformation[1] then
local info = v.relatedInformation[1]
@ -259,7 +250,7 @@ local diag_hdlr = function(err, result, ctx, config)
end
end
local bufnr1 = vim.uri_to_bufnr(uri)
local loaded = vim.api.nvim_buf_is_loaded(bufnr1)
local loaded = api.nvim_buf_is_loaded(bufnr1)
if _NgConfigValues.diagnostic_load_files then
-- print('load buffers')
if not loaded then
@ -267,7 +258,7 @@ local diag_hdlr = function(err, result, ctx, config)
end
local pos = v.range.start
local row = pos.line
local line = (vim.api.nvim_buf_get_lines(bufnr1, row, row + 1, false) or { '' })[1]
local line = (api.nvim_buf_get_lines(bufnr1, row, row + 1, false) or { '' })[1]
if line ~= nil then
item.text = head .. line .. _NgConfigValues.icons.diagnostic_head_description .. v.message
else
@ -301,35 +292,67 @@ local diag_hdlr = function(err, result, ctx, config)
marker(result, ctx, config)
else
trace('great, no diag errors')
vim.api.nvim_buf_clear_namespace(0, _NG_VT_DIAG_NS, 0, -1)
api.nvim_buf_clear_namespace(0, _NG_VT_DIAG_NS, 0, -1)
_NG_VT_DIAG_NS = nil
end
end
local diag_hdlr_async = function()
local debounce = require('navigator.debounce').debounce_trailing
return debounce(100, diag_hdlr)
end
-- local diag_hdlr_async = function()
-- local debounce = require('navigator.debounce').debounce_trailing
-- return debounce(100, diag_hdlr)
-- end
local M = {}
diagnostic_cfg.virtual_text = _NgConfigValues.lsp.diagnostic.virtual_text
if type(_NgConfigValues.lsp.diagnostic.virtual_text) == 'table' then
diagnostic_cfg.virtual_text.prefix = _NgConfigValues.icons.diagnostic_virtual_text
function M.setup()
if diagnostic_cfg ~= nil and diagnostic_cfg.float ~= nil then
return
end
diagnostic_cfg = {
-- Enable underline, use default values
underline = _NgConfigValues.lsp.diagnostic.underline,
-- Enable virtual
-- Use a function to dynamically turn signs off
-- and on, using buffer local variables
signs = true,
update_in_insert = _NgConfigValues.lsp.diagnostic.update_in_insert or false,
severity_sort = _NgConfigValues.lsp.diagnostic.severity_sort,
float = {
focusable = false,
style = 'minimal',
border = 'rounded',
source = 'always',
header = '',
prefix = '',
},
}
diagnostic_cfg.virtual_text = _NgConfigValues.lsp.diagnostic.virtual_text
if type(_NgConfigValues.lsp.diagnostic.virtual_text) == 'table' then
diagnostic_cfg.virtual_text.prefix = _NgConfigValues.icons.diagnostic_virtual_text
end
-- vim.lsp.handlers["textDocument/publishDiagnostics"]
M.diagnostic_handler = vim.lsp.with(diag_hdlr, diagnostic_cfg)
vim.diagnostic.config(diagnostic_cfg)
if _NgConfigValues.lsp.diagnostic_scrollbar_sign then
api.nvim_create_autocmd({ 'WinScrolled' }, {
group = api.nvim_create_augroup('NGWinScrolledGroup', {}),
pattern = '*',
callback = function()
require('navigator.diagnostics').update_err_marker()
end,
})
end
end
-- vim.lsp.handlers["textDocument/publishDiagnostics"]
M.diagnostic_handler = vim.lsp.with(diag_hdlr, diagnostic_cfg)
vim.diagnostic.config(diagnostic_cfg)
local function clear_diag_VT(bufnr) -- important for clearing out when no more errors
bufnr = bufnr or vim.api.nvim_get_current_buf()
bufnr = bufnr or api.nvim_get_current_buf()
log(bufnr, _NG_VT_DIAG_NS)
if _NG_VT_DIAG_NS == nil then
return
end
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
_NG_VT_DIAG_NS = nil
end
@ -350,8 +373,6 @@ end
M.show_buf_diagnostics = function()
if diagnostic_list[vim.bo.filetype] ~= nil then
-- log(diagnostic_list[vim.bo.filetype])
-- vim.fn.setqflist({}, " ", {title = "LSP", items = diagnostic_list[vim.bo.filetype]})
local results = diagnostic_list[vim.bo.filetype]
local display_items = {}
for _, client_items in pairs(results) do
@ -368,17 +389,20 @@ M.show_buf_diagnostics = function()
api = _NgConfigValues.icons.diagnostic_file .. _NgConfigValues.icons.diagnostic_head .. ' Diagnostic ',
enable_preview_edit = true,
})
if listview == nil then
return log('nil listview')
end
trace('new buffer', listview.bufnr)
if listview.bufnr then
vim.api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1)
api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1)
end
end
end
end
-- set loc list win
M.set_diag_loclist = function()
local bufnr = vim.api.nvim_get_current_buf()
M.set_diag_loclist = function(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if diag_cnt == 0 then
log('great, no errors!')
@ -398,7 +422,7 @@ M.set_diag_loclist = function()
if diagnostic.set_loclist then
diagnostic.set_loclist(cfg)
else
cfg.namespaces = diagnostic.get_namespace(nil)
cfg.namespaces = diagnostic.get_namespaces()
diagnostic.setloclist(cfg)
end
else
@ -414,7 +438,7 @@ function M.update_err_marker()
-- nothing to update
return
end
local bufnr = vim.api.nvim_get_current_buf()
local bufnr = api.nvim_get_current_buf()
local diag_cnt = get_count(bufnr, [[Error]])
+ get_count(bufnr, [[Warning]])
@ -423,12 +447,12 @@ function M.update_err_marker()
-- redraw
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
trace('no errors')
return
end
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
local errors = diagnostic.get(bufnr)
if #errors == 0 then
trace('no errors', errors)
@ -442,34 +466,84 @@ function M.update_err_marker()
marker(result, { bufnr = bufnr, method = 'textDocument/publishDiagnostics' })
end
if _NgConfigValues.lsp.diagnostic_scrollbar_sign then
vim.cmd([[autocmd WinScrolled * lua require'navigator.diagnostics'.update_err_marker()]])
end
function M.get_line_diagnostic()
local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1
return diagnostic.get(vim.api.nvim_get_current_buf(), { lnum = lnum })
local lnum = api.nvim_win_get_cursor(0)[1] - 1
local diags = diagnostic.get(api.nvim_get_current_buf(), { lnum = lnum })
table.sort(diags, function(diag1, diag2)
return diag1.severity < diag2.severity
end)
return diags
end
function M.show_diagnostics(pos)
local bufnr = vim.api.nvim_get_current_buf()
local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1
local opt = { border = 'single' }
if diagnostic.open_float and type(diagnostic.open_float) == 'function' then
local bufnr = api.nvim_get_current_buf()
local lnum, col = unpack(api.nvim_win_get_cursor(0))
lnum = lnum - 1
local opt = { border = 'single', severity_sort = true }
if pos ~= nil and type(pos) == 'number' then
opt.scope = 'buffer'
else
if pos == true then
opt.scope = 'cursor'
else
opt.scope = 'line'
end
diagnostic.open_float(bufnr, opt)
else
-- deprecated
diagnostic.show_line_diagnostics(opt, bufnr, lnum)
end
local diags = M.get_line_diagnostic()
if diags == nil or next(diags) == nil then
return
end
local diag1 = diags[1]
opt.offset_x = -1 * (col - diag1.col)
diagnostic.open_float(bufnr, opt)
end
function M.treesitter_and_diag_panel()
local Panel = require('guihua.panel')
local ft = vim.bo.filetype
local results = diagnostic_list[ft]
log(diagnostic_list, ft)
local bufnr = api.nvim_get_current_buf()
local p = Panel:new({
header = 'treesitter',
render = function(b)
log('render for ', bufnr, b)
return require('navigator.treesitter').all_ts_nodes(b)
end,
})
p:add_section({
header = 'diagnostic',
render = function(buf)
log(buf, diagnostic)
if diagnostic_list[ft] ~= nil then
local display_items = {}
for _, client_items in pairs(results) do
for _, items in pairs(client_items) do
for _, it in pairs(items) do
log(it)
table.insert(display_items, it)
end
end
end
return display_items
else
return {}
end
end,
})
p:open(true)
end
function M.config(cfg)
M.setup()
cfg = cfg or {}
log('diag config', cfg)
local default_cfg = {
underline = true,
virtual_text = true,

@ -145,7 +145,6 @@ local handle_document_highlight = function(_, result, ctx)
return
end
if type(result) ~= 'table' or vim.fn.empty(result) == 1 then
log('clear up', result)
vim.lsp.util.buf_clear_references(ctx.bufnr)
return
end
@ -205,29 +204,45 @@ local function cmd_nohl()
end
end
_G.nav_doc_hl = function()
local bufnr = vim.api.nvim_get_current_buf()
local nav_doc_hl = function(bufnr)
trace('nav_doc_hl', bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, bufnr)
if client.server_capabilities.documentHighlightProvider then
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _)
if client.server_capabilities.documentHighlightProvider == true then
trace('sending doc highlight', client.name, bufnr)
client.request('textDocument/documentHighlight', ref_params, handle_document_highlight, bufnr)
end
end)
end
local function documentHighlight()
api.nvim_exec(
[[
augroup lsp_document_highlight
autocmd! * <buffer>
autocmd CursorHold,CursorHoldI <buffer> lua nav_doc_hl()
autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
augroup END
]],
false
)
local function documentHighlight(bufnr)
bufnr = bufnr or api.nvim_get_current_buf()
if _NgConfigValues.lsp.document_highlight == true then
local group_name = string.format('%s%d', 'NGHiGroup', bufnr)
local cmd_group = api.nvim_create_augroup(group_name, {})
api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
group = cmd_group,
buffer = bufnr,
desc = 'document highlight',
callback = function()
require('navigator.dochighlight').nav_doc_hl(bufnr)
end,
})
api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, {
group = cmd_group,
buffer = bufnr,
desc = 'clear document highlight',
callback = function()
vim.lsp.util.buf_clear_references(bufnr)
end,
})
end
vim.lsp.handlers['textDocument/documentHighlight'] = function(err, result, ctx)
local bufnr = ctx.bufnr or api.nvim_get_current_buf()
local buffer = ctx.bufnr or api.nvim_get_current_buf()
if err then
vim.notify(err, vim.lsp.log_levels.ERROR)
return
@ -236,19 +251,18 @@ local function documentHighlight()
return
end
trace('dochl', result)
bufnr = bufnr or 0
if type(result) ~= 'table' then
vim.lsp.util.buf_clear_references(bufnr)
vim.lsp.util.buf_clear_references(buffer)
return
end
local client_id = ctx.client_id
vim.lsp.util.buf_clear_references(bufnr)
vim.lsp.util.buf_highlight_references(bufnr, result, util.encoding(client_id))
vim.lsp.util.buf_clear_references(buffer)
vim.lsp.util.buf_highlight_references(buffer, result, util.encoding(client_id))
table.sort(result, function(a, b)
return before(a.range, b.range)
end)
references[bufnr] = result
add_locs(bufnr, result)
references[buffer] = result
add_locs(buffer, result)
end
end
@ -258,5 +272,6 @@ return {
handle_document_highlight = handle_document_highlight,
hi_symbol = hi_symbol,
nohl = nohl,
nav_doc_hl = nav_doc_hl,
cmd_nohl = cmd_nohl,
}

@ -28,19 +28,14 @@ function M.on_attach()
end
function M.setup_plugin()
api.nvim_command('augroup FoldingCommand')
api.nvim_command('autocmd! * <buffer>')
api.nvim_command("autocmd BufEnter <buffer> lua require'navigator.foldlsp'.update_folds()")
api.nvim_command("autocmd BufWritePost <buffer> lua require'navigator.foldlsp'.update_folds()")
api.nvim_command('augroup end')
-- vim.cmd([[
--
-- function! folding_nvim#foldexpr()
-- return luaeval(printf('require"navigator.foldlsp".get_fold_indic(%d)', v:lnum))
-- endfunction
--
-- ]])
local cmd_group = api.nvim_create_augroup('NGFoldGroup', {})
api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost' }, {
group = cmd_group,
pattern = '*',
callback = function()
require('navigator.foldlsp').update_folds()
end,
})
local clients = vim.lsp.buf_get_clients(0)
@ -56,7 +51,6 @@ function M.setup_plugin()
M.active_folding_clients[client_id] = server_supports_folding
end
end
-- print(vim.inspect(M.active_folding_clients))
end
function M.update_folds()
@ -87,7 +81,7 @@ function M.debug_folds()
end
end
M.fold_handler = function(err, result, ctx, config)
M.fold_handler = function(err, result, ctx, _)
-- params: err, method, result, client_id, bufnr
-- XXX: handle err?
if err or result == nil or #result == 0 then

@ -17,35 +17,51 @@ function M.on_attach()
-- M.update_folds()
end
function _G.custom_fold_text()
function NG_custom_fold_text()
local line = vim.fn.getline(vim.v.foldstart)
local line_count = vim.v.foldend - vim.v.foldstart + 1
-- log("" .. line .. " // " .. line_count .. " lines")
return '' .. line .. ': ' .. line_count .. ' lines'
local ss, se = line:find('^%s*')
local spaces = line:sub(ss, se)
local tabspace = string.rep(' ', vim.o.tabstop)
spaces = spaces:gsub('\t', tabspace)
line = line:gsub('^%s*(.-)%s*$', '%1')
return spaces .. '' .. line .. ': ' .. line_count .. ' lines'
end
vim.opt.foldtext = _G.custom_fold_text()
vim.opt.foldtext = NG_custom_fold_text()
vim.opt.fillchars = { eob = '-', fold = ' ' }
vim.opt.viewoptions:remove('options')
function M.setup_fold()
if not parsers.has_parser() then
vim.notify('treesitter folding not enabled for current file', vim.lsp.log_levels.WARN)
return
end
log('setup treesitter folding')
api.nvim_command('augroup FoldingCommand')
api.nvim_command('autocmd! * <buffer>')
api.nvim_command('augroup end')
vim.opt.foldtext = 'v:lua.custom_fold_text()'
vim.opt.foldtext = 'v:lua.NG_custom_fold_text()'
vim.opt.fillchars = { eob = '-', fold = ' ' }
vim.opt.viewoptions:remove('options')
local current_window = api.nvim_get_current_win()
if not parsers.has_parser() then
api.nvim_win_set_option(current_window, 'foldmethod', 'indent')
log('fallback to indent folding')
return
end
log('setup treesitter folding')
api.nvim_win_set_option(current_window, 'foldmethod', 'expr')
api.nvim_win_set_option(current_window, 'foldexpr', 'folding#foldexpr()')
api.nvim_win_set_option(current_window, 'foldexpr', 'folding#ngfoldexpr()')
end
local function get_fold_level(levels, lnum)
local prev_l = levels[lnum]
local prev_ln
if prev_l:find('>') then
prev_ln = tonumber(prev_l:sub(2))
else
prev_ln = tonumber(prev_l)
end
return prev_ln
end
-- This is cached on buf tick to avoid computing that multiple times
@ -103,27 +119,39 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
prev_stop = stop
end
end
trace(start_counts)
trace(stop_counts)
local levels = {}
local current_level = 0
-- We now have the list of fold opening and closing, fill the gaps and mark where fold start
local pre_node
for lnum = 0, api.nvim_buf_line_count(bufnr) do
local node, _ = get_node_at_line(lnum + 1)
-- log(lnum, node:type())
local comment = node:type() == 'comment'
local next_node, _ = get_node_at_line(lnum + 1)
local next_comment = node and node:type() == 'comment'
local last_trimmed_level = trim_level(current_level)
current_level = current_level + (start_counts[lnum] or 0)
local trimmed_level = trim_level(current_level)
current_level = current_level - (stop_counts[lnum] or 0)
local next_trimmed_level = trim_level(current_level)
local current_level2 = current_level - (stop_counts[lnum] or 0)
local next_trimmed_level = trim_level(current_level2)
trace(lnum, node:type(), node, last_trimmed_level, trimmed_level, next_trimmed_level)
if comment then
if lnum == 0 or levels[lnum] == tostring(trimmed_level) then
levels[lnum + 1] = '>' .. tostring(trimmed_level + 1) -- allow comment fold independtly
else
levels[lnum + 1] = tostring(trimmed_level + 1) -- allow comment fold independtly
trace('comment node', trimmed_level)
-- if trimmed_level == 0 then
-- trimmed_level = 1
-- end
levels[lnum + 1] = tostring(trimmed_level + 2)
if pre_node and pre_node:type() ~= 'comment' then
levels[lnum + 1] = '>' .. tostring(trimmed_level + 2)
end
if next_node and next_node:type() ~= 'comment' then
levels[lnum + 1] = tostring(trimmed_level + 1)
end
else
-- Determine if it's the start/end of a fold
@ -134,28 +162,59 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
-- ( \n ( \n ) \n ( \n ) \n )
-- If it did have such a mechansim, (trimmed_level - last_trimmed_level)
-- would be the correct number of starts to pass on.
levels[lnum + 1] = tostring(trimmed_level)
if trimmed_level - last_trimmed_level > 0 then
levels[lnum + 1] = tostring(trimmed_level) -- hack
levels[lnum + 2] = '>' .. tostring(trimmed_level + 1) -- dirty hack
elseif trimmed_level - next_trimmed_level > 0 then
if levels[lnum + 1] ~= '>' .. tostring(trimmed_level) then
levels[lnum + 1] = tostring(trimmed_level) -- hack do not fold current line as it is first in fold range
end
levels[lnum + 2] = '>' .. tostring(trimmed_level + 1) -- dirty hack fold start from next line
trace('fold start')
elseif trimmed_level - next_trimmed_level > 0 then -- last line in fold range
-- Ending marks tend to confuse vim more than it helps, particularly when
-- the fold level changes by at least 2; we can uncomment this if
-- vim's behavior gets fixed.
if lnum ~= 0 then
levels[lnum] = tostring(trimmed_level + 1)
trace('fold end')
if levels[lnum + 1] then
trace('already set reset as fold is ending', levels[lnum + 1])
levels[lnum + 1] = tostring(trimmed_level + 1)
else
local prev_ln = get_fold_level(levels, lnum) - 1
if prev_ln == 0 then
prev_ln = 1
end
levels[lnum + 1] = tostring(prev_ln)
end
levels[lnum + 1] = tostring(trimmed_level)
-- levels[lnum + 1] = tostring(trimmed_level + 1)
-- else
current_level = current_level - 1
else
-- if levels[lnum + 1] == nil then
levels[lnum + 1] = tostring(trimmed_level + 1)
-- end
trace('same')
if pre_node and pre_node:type() == 'comment' then
local prev_ln = get_fold_level(levels, lnum) - 1
levels[lnum + 1] = tostring(prev_ln)
else
local n = math.max(trimmed_level, 1)
if lnum > 1 then
if levels[lnum + 1] then
trace('already set', levels[lnum + 1])
else
local prev_l = levels[lnum]
if prev_l:find('>') then
levels[lnum + 1] = prev_l:sub(2)
else
levels[lnum + 1] = prev_l
end
end
else
levels[lnum + 1] = tostring(n)
end
end
end
trace(levels)
end
pre_node = node
end
trace(levels)
return levels
end)
@ -166,7 +225,7 @@ function M.get_fold_indic(lnum)
local buf = api.nvim_get_current_buf()
local shown = false
for i = 1, vim.fn.tabpagenr('$') do
for key, value in pairs(vim.fn.tabpagebuflist(i)) do
for _, value in pairs(vim.fn.tabpagebuflist(i)) do
if value == buf then
shown = true
end
@ -177,7 +236,7 @@ function M.get_fold_indic(lnum)
end
local levels = folds_levels(buf) or {}
-- log(lnum, levels[lnum]) -- TODO: comment it out in master
-- trace(lnum, levels[lnum]) -- TODO: comment it out in master
return levels[lnum] or '0'
end

@ -1,7 +1,8 @@
-- https://github.com/wention/dotfiles/blob/master/.config/nvim/lua/config/lsp.lua
-- https://github.com/lukas-reineke/dotfiles/blob/master/vim/lua/lsp/handlers.lua
return {
format_hdl = function(err, result, ctx, cfg) -- FIXME: bufnr is nil
format_hdl = function(err, result, ctx, _) -- FIXME: bufnr is nil
if err ~= nil or result == nil then
return
end
@ -31,4 +32,18 @@ return {
end
end, 100)
end,
range_format = function()
local old_func = vim.go.operatorfunc
_G.op_func_formatting = function()
print('formatting range')
local start = vim.api.nvim_buf_get_mark(0, '[')
local finish = vim.api.nvim_buf_get_mark(0, ']')
print(vim.inspect(start), vim.inspect(finish))
vim.lsp.buf.range_formatting({}, start, finish)
vim.go.operatorfunc = old_func
_G.op_func_formatting = nil
end
vim.go.operatorfunc = 'v:lua.op_func_formatting'
vim.api.nvim_feedkeys('g@', 'n', false)
end,
}

@ -1,6 +1,6 @@
local M = {}
local ListView = require('guihua.listview')
local TextView = require('guihua.textview')
-- local ListView = require('guihua.listview')
-- local TextView = require('guihua.textview')
local util = require('navigator.util')
local log = util.log
local trace = require('navigator.util').trace
@ -8,7 +8,7 @@ local api = vim.api
local active_list_view -- only one listview at a time
function M.new_list_view(opts)
log(opts)
-- log(opts)
local config = require('navigator').config_values()
if active_list_view ~= nil then
@ -16,47 +16,55 @@ function M.new_list_view(opts)
local winnr = active_list_view.win
local bufnr = active_list_view.buf
if bufnr and vim.api.nvim_buf_is_valid(bufnr) and winnr and vim.api.nvim_win_is_valid(winnr) then
if bufnr and api.nvim_buf_is_valid(bufnr) and winnr and api.nvim_win_is_valid(winnr) then
log('list view already present')
return active_list_view
end
end
local items = opts.items
opts.min_width = opts.min_width or 0.3
opts.min_height = opts.min_height or 0.3
opts.height_ratio = config.height
opts.width_ratio = config.width
opts.preview_height_ratio = _NgConfigValues.preview_height or 0.3
opts.preview_lines = _NgConfigValues.preview_lines
opts.height_ratio = opts.height or config.height
opts.width_ratio = opts.height or config.width
opts.preview_height_ratio = opts.preview_height or config.preview_height
opts.preview_lines = config.preview_lines
if opts.rawdata then
opts.data = items
else
opts.data = require('navigator.render').prepare_for_render(items, opts)
end
opts.border = _NgConfigValues.border or 'shadow'
opts.border = config.border or 'shadow'
if vim.fn.hlID('TelescopePromptBorder') > 0 then
opts.border_hl = 'TelescopePromptBorder'
opts.list_hl = 'TelescopeNormal'
opts.bg_hl = 'TelescopePreviewNormal'
opts.sel_hl = 'TelescopeSelection'
else
opts.border_hl = 'FloatBorder'
opts.bg_hl = 'NormalFloat'
opts.list_hl = 'NormalFloat'
opts.sel_hl = 'PmenuSel'
end
if not items or vim.tbl_isempty(items) then
log('empty data return')
return
end
opts.transparency = _NgConfigValues.transparency
if #items >= _NgConfigValues.lines_show_prompt then
opts.transparency = config.transparency
if #items >= config.lines_show_prompt then
opts.prompt = true
end
opts.external = _NgConfigValues.external
opts.preview_lines_before = 3
trace(opts)
opts.external = config.external
opts.preview_lines_before = 4
if _NgConfigValues.debug then
local logopts = { items = {}, data = {} }
logopts = vim.tbl_deep_extend('keep', logopts, opts)
log(logopts)
end
active_list_view = require('guihua.gui').new_list_view(opts)
return active_list_view
end
function M.select(items, opts, on_choice)
return
end
return M
-- Doc

@ -8,100 +8,305 @@ local lsphelper = require('navigator.lspwrapper')
local path_sep = require('navigator.util').path_sep()
local path_cur = require('navigator.util').path_cur()
local cwd = vim.loop.cwd()
local in_method = 'callHierarchy/incomingCalls'
local out_method = 'callHierarchy/outgoingCalls'
local lsp_method = { to = out_method, from = in_method }
local panel_method = { to = out_method, from = in_method }
local M = {}
local function call_hierarchy_handler(direction, err, result, ctx, cfg, error_message)
local outgoing_calls_handler
local incoming_calls_handler
local hierarchy_handler
local call_hierarchy
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then
return
end
if #call_hierarchy_items == 1 then
return call_hierarchy_items[1]
end
local items = {}
for i, item in pairs(call_hierarchy_items) do
local entry = item.detail or item.name
table.insert(items, string.format('%d. %s', i, entry))
end
local choice = vim.fn.inputlist(items)
if choice < 1 or choice > #items then
return
end
return choice
end
-- convert lsp result to navigator items
local function call_hierarchy_result_procesor(direction, err, result, ctx, config)
math.randomseed(os.clock() * 100000000000)
trace(direction, err, ctx, config)
trace(result)
if not result then
vim.notify('No call hierarchy items found', vim.lsp.log_levels.WARN)
return
end
trace('call_hierarchy', result)
-- trace('call_hierarchy', result)
local bufnr = vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
local bufnr = ctx.bufnr or vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use call hierarchy')
if err ~= nil then
log('dir', direction, 'result', result, 'err', err, ctx)
vim.notify('ERROR: ' .. error_message, vim.lsp.log_levels.WARN)
vim.notify('ERROR: ' .. err, vim.lsp.log_levels.WARN)
return
end
local items = {}
local items = ctx.items or {}
for _, call_hierarchy_call in pairs(result) do
local call_hierarchy_item = call_hierarchy_call[direction]
local kind = ''
local kind = ''
for _, call_hierarchy_result in pairs(result) do
local call_hierarchy_item = call_hierarchy_result[direction]
if call_hierarchy_item.kind then
kind = require('navigator.lspclient.lspkind').symbol_kind(call_hierarchy_item.kind) .. ' '
end
-- for _, range in pairs(call_hierarchy_call.fromRanges) do
range = call_hierarchy_item.range or call_hierarchy_item.selectionRange
local filename = assert(vim.uri_to_fname(call_hierarchy_item.uri))
local display_filename = filename:gsub(cwd .. path_sep, path_cur, 1)
call_hierarchy_item.detail = call_hierarchy_item.detail or ''
call_hierarchy_item.detail = call_hierarchy_item.detail:gsub('\n', '')
trace(range, call_hierarchy_item)
call_hierarchy_item.detail = string.gsub(call_hierarchy_item.detail, '\n', '')
trace(call_hierarchy_item)
local disp_item = {
uri = call_hierarchy_item.uri,
local disp_item = vim.tbl_deep_extend('force', {}, call_hierarchy_item)
disp_item = vim.tbl_deep_extend('force', disp_item, {
filename = filename,
display_filename = display_filename,
indent_level = ctx.depth or 1,
method = lsp_method[direction],
node_text = call_hierarchy_item.name,
type = kind,
id = math.random(1, 100000),
text = kind .. call_hierarchy_item.name .. '' .. call_hierarchy_item.detail,
range = range,
lnum = range.start.line + 1,
col = range.start.character,
}
lnum = call_hierarchy_item.selectionRange.start.line + 1,
col = call_hierarchy_item.selectionRange.start.character,
})
table.insert(items, disp_item)
-- end
end
trace(items)
return items
end
local call_hierarchy_handler_from = partial(call_hierarchy_handler, 'from')
local call_hierarchy_handler_to = partial(call_hierarchy_handler, 'to')
local call_hierarchy_handler_from = partial(call_hierarchy_result_procesor, 'from')
local call_hierarchy_handler_to = partial(call_hierarchy_result_procesor, 'to')
local function incoming_calls_handler(bang, err, result, ctx, cfg)
local bufnr = vim.api.nvim_get_current_buf()
-- the handler that deal all lsp request
hierarchy_handler = function(dir, handler, show, api, err, result, ctx, cfg)
trace(dir, handler, api, show, err, result, ctx, cfg)
ctx = ctx or {} -- can be nil if it is async call
cfg = cfg or {}
local opts = ctx.opts or {}
vim.validate({ handler = { handler, 'function' }, show = { show, 'function' }, api = { api, 'string' } })
local bufnr = ctx.bufnr or vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp hierarchy')
local results = call_hierarchy_handler_from(err, result, ctx, cfg, 'Incoming calls not found')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft')
gui.new_list_view({ items = results, ft = ft, api = '' })
local results = handler(err, result, ctx, cfg, 'Incoming calls not found')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or vim.api.nvim_get_current_buf(), 'ft')
if ctx.no_show then
return results
end
-- local panel = args.panel
-- local items = args.items
-- local parent_node = args.node
-- local section_id = args.section_id or 1
local show_args = {
items = results,
ft = ft,
api = api,
bufnr = bufnr,
panel = opts.panel,
parent_node = opts.parent_node,
}
local win = show(show_args)
return results, win
end
local make_params = function(uri, pos)
return {
textDocument = {
uri = uri,
},
position = pos,
}
end
local function outgoing_calls_handler(bang, err, result, ctx, cfg)
local results = call_hierarchy_handler_to(err, result, ctx, cfg, 'Outgoing calls not found')
local function display_panel(args)
-- args = {items=results, ft=ft, api=api}
log(args)
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft')
gui.new_list_view({ items = results, ft = ft, api = '' })
-- fzf_locations(bang, "", "Outgoing Calls", results, false)
local Panel = require('guihua.panel')
local bufnr = args.bufnr or vim.api.nvim_get_current_buf()
-- local ft = args.ft or vim.api.nvim_buf_get_option(bufnr, 'buftype')
local items = args.items
local p = Panel:new({
header = args.header or 'Call Hierarchy',
render = function(buf)
log(buf)
return items
end,
fold = function(panel, node)
if node.expanded ~= nil then
node.expanded = not node.expanded
vim.cmd('normal! za')
else
expand(panel, node)
node.expanded = true
end
log('fold')
return node
end,
})
p:open(true)
end
function M.incoming_calls(bang, opts)
local bufnr = vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp hierarchy')
if not lsphelper.check_capabilities('callHierarchyProvider') then
return
local function expand_item(args)
-- args = {items=results, ft=ft, api=api}
print('dispaly panel')
trace(args, args.parent_node)
local panel = args.panel
local items = args.items
local parent_node = args.parent_node
local section_id = args.section_id or 1
local sect
local sectid = 1
for i, s in pairs(panel.sections) do
if s.id == section_id then
sectid = i
break
end
end
sect = panel.sections[sectid]
for i, node in pairs(sect.nodes) do
if node.id == parent_node.id then
for j in ipairs(items) do
items[j].indent_level = parent_node.indent_level + 1
table.insert(sect.nodes, i + j, args.items[j])
end
sect.nodes[i].expanded = true
sect.nodes[i].expandable = false
break
end
end
trace(panel.sections[sectid])
-- render the panel again
panel:redraw(false)
end
incoming_calls_handler = util.partial4(
hierarchy_handler,
'from',
call_hierarchy_handler_from,
gui.new_list_view,
''
)
outgoing_calls_handler = util.partial4(hierarchy_handler, 'to', call_hierarchy_handler_to, gui.new_list_view, '')
local incoming_calls_panel = util.partial4(
hierarchy_handler,
'from',
call_hierarchy_handler_from,
display_panel,
''
)
local outgoing_calls_panel = util.partial4(hierarchy_handler, 'to', call_hierarchy_handler_to, display_panel, '')
local incoming_calls_expand = util.partial4(hierarchy_handler, 'from', call_hierarchy_handler_from, expand_item, '')
local outgoing_calls_expand = util.partial4(hierarchy_handler, 'to', call_hierarchy_handler_to, expand_item, '')
function expand(panel, node)
trace(panel, node)
local params = make_params(node.uri, {
line = node.range.start.line,
character = node.range.start.character,
})
local handler = incoming_calls_expand
if node.api == out_method then
handler = outgoing_calls_expand
end
local params = vim.lsp.util.make_position_params()
lsphelper.call_sync('callHierarchy/incomingCalls', params, opts, partial(incoming_calls_handler, bang))
local bufnr = vim.uri_to_bufnr(node.uri)
call_hierarchy(node.method, {
params = params,
panel = panel,
parent_node = node,
handler = handler,
bufnr = bufnr,
})
end
function M.outgoing_calls(bang, opts)
local bufnr = vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
if not lsphelper.check_capabilities('callHierarchyProvider') then
return
local request = vim.lsp.buf_request
-- call_hierarchy with floating window
call_hierarchy = function(method, opts)
trace(method, opts)
opts = opts or {}
local params = opts.params or vim.lsp.util.make_position_params()
local bufnr = opts.bufnr
local handler = function(err, result, ctx, cfg)
ctx.opts = opts
return opts.handler(err, result, ctx, cfg)
end
-- log(opts, params)
return request(
bufnr,
'textDocument/prepareCallHierarchy',
params,
vim.lsp.with(function(err, result, ctx)
if err then
vim.notify(err.message, vim.log.levels.WARN)
return
end
local call_hierarchy_item = pick_call_hierarchy_item(result)
local client = vim.lsp.get_client_by_id(ctx.client_id)
if client then
trace('result', result, 'items', call_hierarchy_item, method, ctx, client.name)
client.request(method, {
item = call_hierarchy_item,
args = {
method = method,
},
}, handler, ctx.bufnr)
else
vim.notify(string.format('Client with id=%d stopped', ctx.client_id), vim.log.levels.WARN)
end
end, { direction = method, depth = opts.depth })
)
end
function M.incoming_calls(opts)
call_hierarchy(in_method, opts)
end
local params = vim.lsp.util.make_position_params()
lsphelper.call_sync('callHierarchy/outgoingCalls', params, opts, partial(outgoing_calls_handler, bang))
function M.outgoing_calls(opts)
call_hierarchy(out_method, opts)
end
M.incoming_calls_call = partial(M.incoming_calls, 0)
M.outgoing_calls_call = partial(M.outgoing_calls, 0)
function M.incoming_calls_panel(opts)
opts = vim.tbl_extend('force', { handler = incoming_calls_panel }, opts or {})
call_hierarchy(in_method, opts)
end
function M.outgoing_calls_panel(opts)
opts = vim.tbl_extend('force', { handler = outgoing_calls_panel }, opts or {})
call_hierarchy(out_method, opts)
end
M.incoming_calls_handler = partial(incoming_calls_handler, 0)
M.outgoing_calls_handler = partial(outgoing_calls_handler, 0)
M.incoming_calls_handler = incoming_calls_handler
M.outgoing_calls_handler = outgoing_calls_handler
-- for testing
M._call_hierarchy = call_hierarchy
function M.calltree(args)
if args == '-o' then
return M.outgoing_calls_panel()
end
M.incoming_calls_panel()
end
return M

@ -2,12 +2,12 @@ local util = require('navigator.util')
local lsphelper = require('navigator.lspwrapper')
local gui = require('navigator.gui')
local M = {}
local location = require('guihua.location')
-- local location = require('guihua.location')
local partial = util.partial
local locations_to_items = lsphelper.locations_to_items
local log = util.log
-- dataformat should be same as reference
local function location_handler(err, locations, ctx, cfg, msg)
local function location_handler(err, locations, ctx, _, msg)
if err ~= nil then
vim.notify('ERROR: ' .. tostring(err) .. ' ' .. msg, vim.lsp.log_levels.WARN)
return
@ -15,7 +15,7 @@ local function location_handler(err, locations, ctx, cfg, msg)
return locations_to_items(locations, ctx)
end
local function implementation_handler(bang, err, result, ctx, cfg)
local function implementation_handler(_, err, result, ctx, cfg)
local results = location_handler(err, result, ctx, cfg, 'Implementation not found')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft')
gui.new_list_view({ items = results, ft = ft, api = 'Implementation' })

@ -1,7 +1,6 @@
return {
init = function()
local loader = nil
local packer_plugins = packer_plugins or nil -- suppress warnings
local log = require('navigator.util').log
-- packer only
if packer_plugins ~= nil then -- packer install
@ -22,9 +21,15 @@ return {
loader(plugin)
end
end
else
loader = function(plugin)
local cmd = 'packadd ' .. plugin
vim.cmd(cmd)
end
end
if _NgConfigValues.lsp_installer == true then
vim.cmd('packadd nvim-lsp-installer')
local has_lspinst, lspinst = pcall(require, 'nvim-lsp-installer')
log('lsp_installer installed', has_lspinst)
if has_lspinst then
@ -45,13 +50,13 @@ return {
end,
load = function(plugin_name, path)
local loader = nil
local packer_plugins = packer_plugins or nil -- suppress warnings
packer_plugins = packer_plugins or nil -- suppress warnings
-- packer only
if packer_plugins ~= nil then -- packer install
local lazy_plugins = {}
lazy_plugins[plugin_name] = path
loader = require('packer').loader
for plugin, url in pairs(lazy_plugins) do
for plugin, _ in pairs(lazy_plugins) do
if packer_plugins[plugin] and packer_plugins[plugin].loaded == false then
-- log("loading ", plugin)
pcall(loader, plugin)

@ -4,7 +4,7 @@ local lsp = require('vim.lsp')
local util = require('navigator.util')
local log = util.log
local trace = util.trace
_NG_Attached = {}
local M = {}
M.on_attach = function(client, bufnr)
@ -23,6 +23,7 @@ M.on_attach = function(client, bufnr)
log('attaching: ', bufnr, client.name, uri)
trace(client)
_NG_Attached[client.name] = true
-- add highlight for Lspxxx
require('navigator.lspclient.highlight').add_highlight()
@ -34,10 +35,17 @@ M.on_attach = function(client, bufnr)
bufnr = bufnr,
})
if client.server_capabilities.documentHighlightProvider then
require('navigator.dochighlight').documentHighlight()
if client.server_capabilities.documentHighlightProvider == true then
trace('attaching doc highlight: ', bufnr, client.name)
vim.defer_fn(function()
require('navigator.dochighlight').documentHighlight(bufnr)
end, 50) -- allow a bit time for it to settle down
else
log('skip doc highlight: ', bufnr, client.name)
end
require('navigator.lspclient.lspkind').init()
local config = require('navigator').config_values()
@ -60,9 +68,15 @@ M.on_attach = function(client, bufnr)
end
if _NgConfigValues.lsp.code_action.enable then
if client.server_capabilities.codeActionProvider then
if client.server_capabilities.codeActionProvider and client.name ~= 'null-ls' then
log('code action enabled for client', client.server_capabilities.codeActionProvider)
vim.cmd([[autocmd CursorHold,CursorHoldI <buffer> lua require'navigator.codeAction'.code_action_prompt()]])
api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
group = api.nvim_create_augroup('NGCodeActGroup_'..tostring(bufnr), {}),
buffer = bufnr,
callback = function()
require('navigator.codeAction').code_action_prompt(bufnr)
end,
})
end
end
end

@ -1,14 +1,13 @@
-- todo allow config passed in
local util = require('navigator.util')
local log = util.log
local trace = util.trace
local uv = vim.loop
local empty = util.empty
local warn = util.warn
local ng_util = require('navigator.util')
local log = ng_util.log
local trace = ng_util.trace
local empty = ng_util.empty
local warn = ng_util.warn
local vfn = vim.fn
_NG_Loaded = {}
_LoadedFiletypes = {}
local loader = nil
packer_plugins = packer_plugins or nil -- suppress warnings
-- packer only
@ -26,7 +25,26 @@ end
local util = lspconfig.util
local config = require('navigator').config_values()
local disabled_ft = {
'NvimTree',
'guihua',
'clap_input',
'clap_spinner',
'vista',
'vista_kind',
'TelescopePrompt',
'guihua_rust',
'csv',
'txt',
'defx',
'packer',
'gitcommit',
'windline',
'notify',
'nofile',
'help',
'',
}
-- local cap = vim.lsp.protocol.make_client_capabilities()
local on_attach = require('navigator.lspclient.attach').on_attach
-- gopls["ui.completion.usePlaceholders"] = true
@ -47,326 +65,45 @@ local luadevcfg = {
}
local luadev = {}
local user_luadev = _NgConfigValues.lsp['lua-dev']
if user_luadev then
luadev = vim.tbl_deep_extend('force', luadev, user_luadev)
end
require('navigator.lazyloader').load('lua-dev.nvim', 'folke/lua-dev.nvim')
local ok, l = pcall(require, 'lua-dev')
if ok and l then
luadev = l.setup(luadevcfg)
if _NgConfigValues.lsp_installer then
require('navigator.lazyloader').load('nvim-lsp-installer', 'williamboman/nvim-lsp-installer')
end
local path = vim.split(package.path, ';')
table.insert(path, 'lua/?.lua')
table.insert(path, 'lua/?/init.lua')
local function add(lib)
for _, p in pairs(vim.fn.expand(lib, false, true)) do
p = vim.loop.fs_realpath(p)
if p then
library[p] = true
end
end
end
-- add runtime
add('$VIMRUNTIME')
-- add your config
-- local home = vim.fn.expand("$HOME")
add(vim.fn.stdpath('config'))
-- add plugins it may be very slow to add all in path
-- if vim.fn.isdirectory(home .. "/.config/share/nvim/site/pack/packer") then
-- add(home .. "/.local/share/nvim/site/pack/packer/opt/*")
-- add(home .. "/.local/share/nvim/site/pack/packer/start/*")
-- end
library[vim.fn.expand('$VIMRUNTIME/lua')] = true
library[vim.fn.expand('$VIMRUNTIME/lua/vim')] = true
library[vim.fn.expand('$VIMRUNTIME/lua/vim/lsp')] = true
-- [vim.fn.expand("~/repos/nvim/lua")] = true
-- TODO remove onece PR #944 merged to lspconfig
local path_sep = require('navigator.util').path_sep()
local strip_dir_pat = path_sep .. '([^' .. path_sep .. ']+)$'
local strip_sep_pat = path_sep .. '$'
local dirname = function(pathname)
if not pathname or #pathname == 0 then
return
end
local result = pathname:gsub(strip_sep_pat, ''):gsub(strip_dir_pat, '')
if #result == 0 then
return '/'
end
return result
if _NgConfigValues.mason then
require('navigator.lazyloader').load('mason.nvim', 'williamboman/mason.nvim')
require('navigator.lazyloader').load('mason-lspconfig.nvim', 'williamboman/mason-lspconfig.nvim')
end
-- TODO end
local setups = {
clojure_lsp = {
root_dir = function(fname)
return util.root_pattern('deps.edn', 'build.boot', 'project.clj', 'shadow-cljs.edn', 'bb.edn', '.git')(fname)
or util.path.dirname(fname)
end,
on_attach = on_attach,
filetypes = { 'clojure', 'edn' },
message_level = vim.lsp.protocol.MessageType.error,
cmd = { 'clojure-lsp' },
},
elixirls = {
on_attach = on_attach,
filetypes = { 'elixir', 'eelixir' },
cmd = { 'elixir-ls' },
message_level = vim.lsp.protocol.MessageType.error,
settings = {
elixirLS = {
dialyzerEnabled = true,
fetchDeps = false,
},
},
root_dir = function(fname)
return util.root_pattern('mix.exs', '.git')(fname) or util.path.dirname(fname)
end,
},
gopls = {
on_attach = on_attach,
-- capabilities = cap,
filetypes = { 'go', 'gomod', 'gohtmltmpl', 'gotexttmpl' },
message_level = vim.lsp.protocol.MessageType.Error,
cmd = {
'gopls', -- share the gopls instance if there is one already
'-remote=auto', --[[ debug options ]] --
-- "-logfile=auto",
-- "-debug=:0",
'-remote.debug=:0',
-- "-rpc.trace",
},
flags = { allow_incremental_sync = true, debounce_text_changes = 1000 },
settings = {
gopls = {
-- more settings: https://github.com/golang/tools/blob/master/gopls/doc/settings.md
-- flags = {allow_incremental_sync = true, debounce_text_changes = 500},
-- not supported
analyses = { unusedparams = true, unreachable = false },
codelenses = {
generate = true, -- show the `go generate` lens.
gc_details = true, -- // Show a code lens toggling the display of gc's choices.
test = true,
tidy = true,
},
usePlaceholders = true,
completeUnimported = true,
staticcheck = true,
matcher = 'fuzzy',
diagnosticsDelay = '500ms',
experimentalWatchedFileDelay = '1000ms',
symbolMatcher = 'fuzzy',
gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils
buildFlags = { '-tags', 'integration' },
-- buildFlags = {"-tags", "functional"}
},
},
root_dir = function(fname)
return util.root_pattern('go.mod', '.git')(fname) or dirname(fname) -- util.path.dirname(fname)
end,
},
clangd = {
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
cmd = {
'clangd',
'--background-index',
'--suggest-missing-includes',
'--clang-tidy',
'--header-insertion=iwyu',
'--clang-tidy-checks=-*,llvm-*,clang-analyzer-*',
'--cross-file-rename',
},
filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
on_attach = function(client, bufnr)
client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
or true
on_attach(client, bufnr)
end,
},
rust_analyzer = {
root_dir = function(fname)
return util.root_pattern('Cargo.toml', 'rust-project.json', '.git')(fname) or util.path.dirname(fname)
end,
filetypes = { 'rust' },
message_level = vim.lsp.protocol.MessageType.error,
on_attach = on_attach,
settings = {
['rust-analyzer'] = {
assist = { importMergeBehavior = 'last', importPrefix = 'by_self' },
cargo = { loadOutDirsFromCheck = true },
procMacro = { enable = true },
},
},
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
},
sqls = {
filetypes = { 'sql' },
on_attach = function(client, bufnr)
client.server_capabilities.executeCommandProvider = client.server_capabilities.documentFormattingProvider or true
highlight.diagnositc_config_sign()
require('sqls').setup({ picker = 'telescope' }) -- or default
end,
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
cmd = { 'sqls', '-config', '$HOME/.config/sqls/config.yml' },
-- alterantively:
-- connections = {
-- {
-- driver = 'postgresql',
-- datasourcename = 'host=127.0.0.1 port=5432 user=postgres password=password dbname=user_db sslmode=disable',
-- },
-- },
},
},
sumneko_lua = {
cmd = { 'lua-language-server' },
filetypes = { 'lua' },
on_attach = on_attach,
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
version = 'LuaJIT',
-- Setup your lua path
path = vim.split(package.path, ';'),
},
diagnostics = {
enable = true,
-- Get the language server to recognize the `vim` global
globals = { 'vim', 'describe', 'it', 'before_each', 'after_each', 'teardown', 'pending' },
},
completion = { callSnippet = 'Both' },
workspace = {
-- Make the server aware of Neovim runtime files
library = library,
maxPreload = 2000,
preloadFileSize = 40000,
},
telemetry = { enable = false },
},
},
on_new_config = function(cfg, root)
local libs = vim.tbl_deep_extend('force', {}, library)
libs[root] = nil
cfg.settings.Lua.workspace.library = libs
return cfg
end,
},
pyright = {
on_attach = on_attach,
cmd = { 'pyright-langserver', '--stdio' },
filetypes = { 'python' },
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
python = {
formatting = { provider = 'black' },
analysis = {
autoSearchPaths = true,
useLibraryCodeForTypes = true,
diagnosticMode = 'workspace',
},
},
},
},
ccls = {
on_attach = on_attach,
init_options = {
compilationDatabaseDirectory = 'build',
root_dir = [[ util.root_pattern("compile_commands.json", "compile_flags.txt", "CMakeLists.txt", "Makefile", ".git") or util.path.dirname ]],
index = { threads = 2 },
clang = { excludeArgs = { '-frounding-math' } },
},
flags = { allow_incremental_sync = true },
},
jdtls = {
settings = {
java = { signatureHelp = { enabled = true }, contentProvider = { preferred = 'fernflower' } },
},
},
omnisharp = {
cmd = { 'omnisharp', '--languageserver', '--hostPID', tostring(vim.fn.getpid()) },
},
terraformls = {
filetypes = { 'terraform', 'tf' },
},
sourcekit = {
cmd = { 'sourcekit-lsp' },
filetypes = { 'swift' }, -- This is recommended if you have separate settings for clangd.
},
}
setups.sumneko_lua = vim.tbl_deep_extend('force', luadev, setups.sumneko_lua)
local servers = {
'angularls',
'gopls',
'tsserver',
'flow',
'bashls',
'dockerls',
'julials',
'pylsp',
'pyright',
'jedi_language_server',
'jdtls',
'sumneko_lua',
'vimls',
'html',
'jsonls',
'solargraph',
'cssls',
'yamlls',
'clangd',
'ccls',
'sqls',
'denols',
'graphql',
'dartls',
'dotls',
'kotlin_language_server',
'nimls',
'intelephense',
'vuels',
'phpactor',
'omnisharp',
'r_language_server',
'rust_analyzer',
'terraformls',
'svelte',
'texlab',
'clojure_lsp',
'elixirls',
'sourcekit',
'fsautocomplete',
'vls',
'hls',
'tflint',
'terraform_lsp',
}
local setups = require('navigator.lspclient.clients_default').defaults()
local servers = require('navigator.lspclient.servers')
local lsp_installer_servers = {}
local has_lspinst = false
local has_mason = false
if config.lsp_installer == true then
has_lspinst, _ = pcall(require, 'nvim-lsp-installer')
if has_lspinst then
local srvs = require('nvim-lsp-installer.servers').get_installed_servers()
log('lsp_installered servers', srvs)
if #srvs > 0 then
lsp_installer_servers = srvs
end
has_lspinst, _ = pcall(require, 'nvim-lsp-installer')
if has_lspinst then
local srvs = require('nvim-lsp-installer.servers').get_installed_servers()
if #srvs > 0 then
lsp_installer_servers = srvs
end
end
has_mason, _ = pcall(require, 'mason-lspconfig')
if has_mason then
local srvs=require'mason-lspconfig'.get_installed_servers()
if #srvs > 0 then
lsp_installer_servers = srvs
end
log(lsp_installer_servers)
end
log("lsp_installer:", lsp_installer_servers)
if config.lsp.disable_lsp == 'all' then
config.lsp.disable_lsp = servers
end
@ -376,11 +113,9 @@ local ng_default_cfg = {
flags = { allow_incremental_sync = true, debounce_text_changes = 1000 },
}
local configs = {}
-- check and load based on file type
local function load_cfg(ft, client, cfg, loaded)
log(ft, client, loaded)
local function load_cfg(ft, client, cfg, loaded, starting)
log(ft, client, loaded, starting)
trace(cfg)
if lspconfig[client] == nil then
log('not supported by nvim', client)
@ -389,6 +124,7 @@ local function load_cfg(ft, client, cfg, loaded)
local lspft = lspconfig[client].document_config.default_config.filetypes
local additional_ft = setups[client] and setups[client].filetypes or {}
local bufnr = vim.api.nvim_get_current_buf()
local cmd = cfg.cmd
vim.list_extend(lspft, additional_ft)
@ -404,19 +140,46 @@ local function load_cfg(ft, client, cfg, loaded)
end
trace('lsp for client', client, cfg)
if cmd == nil or #cmd == 0 or vim.fn.executable(cmd[1]) == 0 then
log('lsp not installed for client', client, cmd)
if cmd == nil or #cmd == 0 or vfn.executable(cmd[1]) == 0 then
log('lsp not installed for client', client, cmd, "fallback")
return
end
if _NG_Loaded == nil then
return log('_NG_Loaded not set')
end
for _, c in pairs(loaded) do
if client == c then
for k, c in pairs(loaded) do
if client == k then
-- loaded
trace(client, 'already been loaded for', ft, loaded)
log(client, 'already been loaded for', ft, loaded, c)
if not _NG_Loaded[bufnr] or _NG_Loaded[bufnr] < 4 then
log('doautocmd filetype')
vim.defer_fn(function()
vim.cmd('doautocmd FileType')
_NG_Loaded[bufnr] = (_NG_Loaded[bufnr] or 0 ) + 1
end, 100)
return
end
end
end
local clients = vim.lsp.buf_get_clients(0)
for _, c in pairs(clients or {}) do
log("lsp start up in progress client", client, c.name)
if c.name == client then
_NG_Loaded[bufnr] = 100
return
end
end
if starting and (starting.cnt or 0) > 0 then
log("lsp start up in progress", starting)
return vim.defer_fn(function()
load_cfg(ft, client, cfg, loaded, { cnt = starting.cnt - 1 })
end,
200)
end
if lspconfig[client] == nil then
error('client ' .. client .. ' not supported')
return
@ -426,8 +189,27 @@ local function load_cfg(ft, client, cfg, loaded)
log('lspconfig setup')
-- log(lspconfig.available_servers())
-- force reload with config
lspconfig[client].setup(cfg)
log(client, 'loading for', ft)
-- lets have a guard here
if not _NG_Loaded[client] then
log(client, 'loading for', ft, cfg)
log(lspconfig[client])
lspconfig[client].setup(cfg)
_NG_Loaded[client] = true
vim.defer_fn(function()
log('send filetype event')
vim.cmd([[doautocmd Filetype]])
_NG_Loaded[bufnr] = (_NG_Loaded[bufnr] or 0 )+ 1
end, 400)
else
log('send filetype event')
if not _NG_Loaded[bufnr] or _NG_Loaded[bufnr] < 4 then
log('doautocmd filetype')
vim.defer_fn(function()
vim.cmd('doautocmd FileType')
_NG_Loaded[bufnr] = (_NG_Loaded[bufnr] or 0 ) + 1
end, 100)
end
end
end
-- need to verify the lsp server is up
end
@ -445,13 +227,12 @@ local function setup_fmt(client, enabled)
client.server_capabilities.documentFormattingProvider = false
else
client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
or enabled
or enabled
end
end
local function update_capabilities()
trace(vim.o.ft, 'lsp startup')
local loaded = {}
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
capabilities.textDocument.completion.completionItem.preselectSupport = true
@ -468,26 +249,27 @@ local function update_capabilities()
end
-- run setup for lsp clients
local loaded = {}
local function lsp_startup(ft, retry, user_lsp_opts)
retry = retry or false
local clients = vim.lsp.get_active_clients() or {}
local loaded = {}
local path_sep = require('navigator.util').path_sep()
local capabilities = update_capabilities()
for _, client in ipairs(clients) do
if client ~= nil then
table.insert(loaded, client.name)
end
end
for _, lspclient in ipairs(servers) do
local clients = vim.lsp.get_active_clients() or {}
for _, client in ipairs(clients) do
if client ~= nil then
loaded[client.name] = client.id
end
end
-- check should load lsp
if type(lspclient) == 'table' then
if lspclient.name then
lspclient = lspclient.name
else
warn('incorrect set for lspclient', vim.inspect(lspclient))
warn('incorrect set for lspclient' .. vim.inspect(lspclient))
goto continue
end
end
@ -504,17 +286,12 @@ local function lsp_startup(ft, retry, user_lsp_opts)
end
end
if _NG_Loaded[lspclient] then
log('client loaded', lspclient)
end
if vim.tbl_contains(config.lsp.disable_lsp or {}, lspclient) then
log('disable lsp', lspclient)
goto continue
end
local default_config = {}
log(lspclient)
if lspconfig[lspclient] == nil then
vim.notify(
'lspclient' .. vim.inspect(lspclient) .. 'no longer support by lspconfig, please submit an issue',
@ -544,8 +321,9 @@ local function lsp_startup(ft, retry, user_lsp_opts)
local disable_fmt = false
log(lspclient)
-- if user provides override values
cfg.capabilities = capabilities
-- cfg.capabilities = capabilities
log(lspclient, config.lsp.disable_format_cap)
if vim.tbl_contains(config.lsp.disable_format_cap or {}, lspclient) then
log('fileformat disabled for ', lspclient)
@ -556,9 +334,9 @@ local function lsp_startup(ft, retry, user_lsp_opts)
if user_lsp_opts[lspclient] ~= nil then
-- log(lsp_opts[lspclient], cfg)
cfg = vim.tbl_deep_extend('force', cfg, user_lsp_opts[lspclient])
if config.combined_attach == nil then
setup_fmt(client, enable_fmt)
end
-- if config.combined_attach == nil then
-- setup_fmt(client, enable_fmt)
-- end
if config.combined_attach == 'mine' then
if config.on_attach == nil then
error('on attach not provided')
@ -627,24 +405,77 @@ local function lsp_startup(ft, retry, user_lsp_opts)
if has_lspinst and _NgConfigValues.lsp_installer then
local installed, installer_cfg = require('nvim-lsp-installer.servers').get_server(lspconfig[lspclient].name)
log('lsp installer server config' .. lspconfig[lspclient].name, installer_cfg)
log('lsp installer server config ' .. lspconfig[lspclient].name, installer_cfg)
if installed and installer_cfg then
log('options', installer_cfg:get_default_options())
-- if cfg.cmd / {lsp_server_name, arg} not present or lsp_server_name is not in PATH
if vim.fn.empty(cfg.cmd) == 1 or vim.fn.executable(cfg.cmd[1] or '') == 0 then
cfg.cmd = { installer_cfg.root_dir .. path_sep .. installer_cfg.name }
local paths = installer_cfg:get_default_options().cmd_env and installer_cfg:get_default_options().cmd_env.PATH
if not paths then
-- for some reason lspinstaller does not install the binary, check default PATH
log('lsp installer does not install the lsp in its path, fallback')
return load_cfg(ft, lspclient, cfg, loaded)
end
paths = vim.split(paths, ':')
if vfn.empty(cfg.cmd) == 1 then
cfg.cmd = { installer_cfg.name }
end
if vfn.executable(cfg.cmd[1]) == 0 then
for _, path in ipairs(paths) do
log(path)
if vfn.isdirectory(path) == 1 and string.find(path, installer_cfg.root_dir) then
cfg.cmd[1] = path .. path_sep .. cfg.cmd[1]
log(cfg.cmd)
break
end
end
log('update cmd', cfg.cmd)
else
log('cmd installed', cfg.cmd)
end
end
end
if has_mason and _NgConfigValues.mason then
local servers = require'mason-lspconfig'.get_installed_servers()
if not vim.tbl_contains(servers, lspconfig[lspclient].name) then
log('mason server not installed', lspconfig[lspclient].name)
-- return
end
local pkg_name = require "mason-lspconfig.mappings.server".lspconfig_to_package[lspconfig[lspclient].name]
local pkg = require "mason-registry".get_package(pkg_name)
log('lsp installer server config ' .. lspconfig[lspclient].name, pkg)
if pkg then
local path = pkg:get_install_path()
if not path then
-- for some reason lspinstaller does not install the binary, check default PATH
log('lsp installer does not install the lsp in its path, fallback')
return load_cfg(ft, lspclient, cfg, loaded)
end
cfg.cmd = cfg.cmd or {}
cfg.cmd[1] = table.concat({vfn.stdpath('data'), 'mason', 'bin', pkg.name}, path_sep)
if vfn.executable(cfg.cmd[1]) == 0 then
log('failed to find cmd', cfg.cmd[1], "fallback")
return load_cfg(ft, lspclient, cfg, loaded)
else
log('cmd installed', cfg.cmd)
end
end
end
if vim.fn.executable(cfg.cmd[1]) == 0 then
if vfn.executable(cfg.cmd[1]) == 0 then
log('lsp server not installed in path ' .. lspclient .. vim.inspect(cfg.cmd), vim.lsp.log_levels.WARN)
end
load_cfg(ft, lspclient, cfg, loaded)
if _NG_Loaded[lspclient] then
log('client loaded ?', lspclient, _NG_Loaded[lspclient])
end
local starting = {}
if _NG_Loaded[lspclient] == true then
starting = { cnt = 1 }
end
_NG_Loaded[lspclient] = true
load_cfg(ft, lspclient, cfg, loaded, starting)
-- load_cfg(ft, lspclient, {}, loaded)
::continue::
end
@ -659,7 +490,7 @@ local function lsp_startup(ft, retry, user_lsp_opts)
end, 1000)
log('null-ls loading')
_NG_Loaded['null-ls'] = true
configs['null-ls'] = cfg
setups['null-ls'] = cfg
end
end
@ -678,7 +509,7 @@ local function lsp_startup(ft, retry, user_lsp_opts)
lspconfig.efm.setup(cfg)
log('efm loading')
_NG_Loaded['efm'] = true
configs['efm'] = cfg
setups['efm'] = cfg
end
end
@ -704,13 +535,21 @@ local function get_cfg(client)
end
end
local function ft_disabled(ft)
for i = 1, #disabled_ft do
if ft == disabled_ft[i] then
return true
end
end
end
local function setup(user_opts, cnt)
user_opts = user_opts or {}
local ft = vim.bo.filetype
local bufnr = user_opts.bufnr or vim.api.nvim_get_current_buf()
if ft == '' then
if ft == '' or ft == nil then
log('nil filetype, callback')
local ext = vim.fn.expand('%:e')
local ext = vfn.expand('%:e')
if ext ~= '' then
cnt = cnt or 0
local opts = vim.deepcopy(user_opts)
@ -727,6 +566,7 @@ local function setup(user_opts, cnt)
return
else
log('no filetype, no ext return')
return
end
end
local uri = vim.uri_from_bufnr(bufnr)
@ -739,27 +579,10 @@ local function setup(user_opts, cnt)
log('navigator was loaded for ft', ft, bufnr)
return
end
local disable_ft = {
'NvimTree',
'guihua',
'clap_input',
'clap_spinner',
'vista',
'vista_kind',
'TelescopePrompt',
'guihua_rust',
'csv',
'txt',
'defx',
'packer',
'gitcommit',
'windline',
}
for i = 1, #disable_ft do
if ft == disable_ft[i] then
trace('navigator disabled for ft or it is loaded', ft)
return
end
if ft_disabled(ft) then
trace('navigator disabled for ft or it is loaded', ft)
return
end
if _NgConfigValues.lsp.servers then
add_servers(_NgConfigValues.lsp.servers)
@ -779,10 +602,10 @@ local function setup(user_opts, cnt)
user_opts = vim.tbl_extend('keep', user_opts, config) -- incase setup was triggered from autocmd
log(user_opts)
log('running lsp setup', ft, bufnr)
local retry = true
log('loading for ft ', ft, uri, user_opts)
log('loading for ft ', ft, uri)
highlight.diagnositc_config_sign()
highlight.add_highlight()
local lsp_opts = user_opts.lsp or {}
@ -806,7 +629,7 @@ local function setup(user_opts, cnt)
--- if code lens enabled
if _NgConfigValues.lsp.code_lens_action.enable then
require('navigator.codelens').setup()
require('navigator.codelens').setup(bufnr)
end
-- _LoadedFiletypes[ft .. tostring(bufnr)] = true -- may prevent lsp config when reboot lsp
@ -821,17 +644,40 @@ local function on_filetype()
return
end
if uri == 'file://' or uri == 'file:///' then
log('skip loading for ft ', ft, uri)
trace('skip loading for ft ', ft, uri)
return
end
log (_NG_Loaded)
if _NG_Loaded[bufnr] and type(_NG_Loaded[bufnr]) == 'number' and _NG_Loaded[bufnr] > 1 then
log('navigator was loaded for ft', ft, bufnr)
return
end
-- on_filetype should only be trigger only once for each bufnr
if _NG_Loaded[bufnr] ~= nil and type(_NG_Loaded[bufnr] == 'number') then
_NG_Loaded[bufnr] = _NG_Loaded[bufnr] + 1 -- do not hook and trigger filetype event multiple times
end
if _NG_Loaded[bufnr] == true then
_NG_Loaded[bufnr] = 1 -- record the count
end
-- as setup will send filetype event as well
log(uri)
local wids = vim.fn.win_findbuf(bufnr)
local wids = vfn.win_findbuf(bufnr)
if empty(wids) then
log('buf not shown return')
end
setup({ bufnr = bufnr })
_NG_Loaded[bufnr] = 1
end
return { setup = setup, get_cfg = get_cfg, lsp = servers, add_servers = add_servers, on_filetype = on_filetype }
return {
setup = setup,
get_cfg = get_cfg,
add_servers = add_servers,
on_filetype = on_filetype,
disabled_ft = disabled_ft,
ft_disabled = ft_disabled,
}

@ -0,0 +1,191 @@
local M = {}
local vfn = vim.fn
M.defaults = function()
local has_lsp, lspconfig = pcall(require, 'lspconfig')
local highlight = require('navigator.lspclient.highlight')
if not has_lsp then
return {
setup = function()
vim.notify('loading lsp config failed LSP may not working correctly', vim.lsp.log_levels.WARN)
end,
}
end
local util = lspconfig.util
local on_attach = require('navigator.lspclient.attach').on_attach
local setups = {
clojure_lsp = {
root_dir = function(fname)
return util.root_pattern('deps.edn', 'build.boot', 'project.clj', 'shadow-cljs.edn', 'bb.edn', '.git')(fname)
or util.path.dirname(fname)
end,
on_attach = on_attach,
filetypes = { 'clojure', 'edn' },
message_level = vim.lsp.protocol.MessageType.error,
cmd = { 'clojure-lsp' },
},
elixirls = {
on_attach = on_attach,
filetypes = { 'elixir', 'eelixir' },
cmd = { 'elixir-ls' },
message_level = vim.lsp.protocol.MessageType.error,
settings = {
elixirLS = {
dialyzerEnabled = true,
fetchDeps = false,
},
},
root_dir = function(fname)
return util.root_pattern('mix.exs', '.git')(fname) or util.path.dirname(fname)
end,
},
gopls = {
on_attach = on_attach,
-- capabilities = cap,
filetypes = { 'go', 'gomod', 'gohtmltmpl', 'gotexttmpl' },
message_level = vim.lsp.protocol.MessageType.Error,
cmd = {
'gopls', -- share the gopls instance if there is one already
'-remote=auto', --[[ debug options ]] --
-- "-logfile=auto",
-- "-debug=:0",
'-remote.debug=:0',
-- "-rpc.trace",
},
flags = { allow_incremental_sync = true, debounce_text_changes = 1000 },
settings = {
gopls = {
-- more settings: https://github.com/golang/tools/blob/master/gopls/doc/settings.md
-- flags = {allow_incremental_sync = true, debounce_text_changes = 500},
-- not supported
analyses = { unusedparams = true, unreachable = false },
codelenses = {
generate = true, -- show the `go generate` lens.
gc_details = true, -- // Show a code lens toggling the display of gc's choices.
test = true,
tidy = true,
},
usePlaceholders = true,
completeUnimported = true,
staticcheck = true,
matcher = 'fuzzy',
diagnosticsDelay = '500ms',
experimentalWatchedFileDelay = '1000ms',
symbolMatcher = 'fuzzy',
gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils
buildFlags = { '-tags', 'integration' },
-- buildFlags = {"-tags", "functional"}
},
},
root_dir = function(fname)
return util.root_pattern('go.mod', '.git')(fname) or dirname(fname) -- util.path.dirname(fname)
end,
},
clangd = {
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
cmd = {
'clangd',
'--background-index',
'--suggest-missing-includes',
'--clang-tidy',
'--header-insertion=iwyu',
'--clang-tidy-checks=-*,llvm-*,clang-analyzer-*',
'--cross-file-rename',
},
filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
on_attach = function(client, bufnr)
client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
or true
on_attach(client, bufnr)
end,
},
rust_analyzer = {
root_dir = function(fname)
return util.root_pattern('Cargo.toml', 'rust-project.json', '.git')(fname) or util.path.dirname(fname)
end,
filetypes = { 'rust' },
message_level = vim.lsp.protocol.MessageType.error,
on_attach = on_attach,
settings = {
['rust-analyzer'] = {
assist = { importMergeBehavior = 'last', importPrefix = 'by_self' },
cargo = { loadOutDirsFromCheck = true },
procMacro = { enable = true },
},
},
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
},
sqls = {
filetypes = { 'sql' },
on_attach = function(client, _)
client.server_capabilities.executeCommandProvider = client.server_capabilities.documentFormattingProvider
or true
highlight.diagnositc_config_sign()
require('sqls').setup({ picker = 'telescope' }) -- or default
end,
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
cmd = { 'sqls', '-config', '$HOME/.config/sqls/config.yml' },
-- alterantively:
-- connections = {
-- {
-- driver = 'postgresql',
-- datasourcename = 'host=127.0.0.1 port=5432 user=postgres password=password dbname=user_db sslmode=disable',
-- },
-- },
},
},
pyright = {
on_attach = on_attach,
cmd = { 'pyright-langserver', '--stdio' },
filetypes = { 'python' },
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
python = {
formatting = { provider = 'black' },
analysis = {
autoSearchPaths = true,
useLibraryCodeForTypes = true,
diagnosticMode = 'workspace',
},
},
},
},
ccls = {
on_attach = on_attach,
init_options = {
compilationDatabaseDirectory = 'build',
root_dir = [[ util.root_pattern("compile_commands.json", "compile_flags.txt", "CMakeLists.txt", "Makefile", ".git") or util.path.dirname ]],
index = { threads = 2 },
clang = { excludeArgs = { '-frounding-math' } },
},
flags = { allow_incremental_sync = true },
},
jdtls = {
settings = {
java = { signatureHelp = { enabled = true }, contentProvider = { preferred = 'fernflower' } },
},
},
omnisharp = {
cmd = { 'omnisharp', '--languageserver', '--hostPID', tostring(vfn.getpid()) },
},
terraformls = {
filetypes = { 'terraform', 'tf' },
},
sourcekit = {
cmd = { 'sourcekit-lsp' },
filetypes = { 'swift' }, -- This is recommended if you have separate settings for clangd.
},
}
setups.sumneko_lua = require('navigator.lspclient.sumneko_lua').sumneko_lua()
return setups
end
return M

@ -1,6 +1,4 @@
local lsp = require("vim.lsp")
M = {}
local M = {}
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true

@ -1,8 +1,9 @@
local M = {}
local log = require('navigator.util').log
-- local log = require('navigator.util').log
local api = vim.api
local cmd_group = api.nvim_create_augroup('NGHiGroup', {})
-- lsp sign          ﮻         ﯭ        ﳀ  
function M.diagnositc_config_sign()
if M.configed then
@ -31,35 +32,41 @@ function M.diagnositc_config_sign()
M.configed = true
end
local colors = {
{ '#aefe00', '#aede00', '#aebe00', '#4e7efe' },
{ '#ff00e0', '#df00e0', '#af00e0', '#fedefe' },
{ '#1000ef', '#2000df', '#2000cf', '#f0f040' },
{ '#d8a8a3', '#c8a8a3', '#b8a8a3', '#4e2c33' },
{ '#ffa724', '#efa024', '#dfa724', '#0040ff' },
{ '#afdc2b', '#09dc4b', '#08d04b', '#ef4f8f' },
}
function M.add_highlight()
-- lsp system default
api.nvim_command('hi! link DiagnosticUnderlineError SpellBad')
api.nvim_command('hi! link DiagnosticUnderlineWarning SpellRare')
api.nvim_command('hi! link DiagnosticUnderlineInformation SpellRare')
api.nvim_command('hi! link DiagnosticUnderlineHint SpellRare')
api.nvim_command('hi def link NGPreviewTitle Title')
local colors = {
{ '#aefe00', '#aede00', '#aebe00', '#4e7efe' },
{ '#ff00e0', '#df00e0', '#af00e0', '#fedefe' },
{ '#1000ef', '#2000df', '#2000cf', '#f0f040' },
{ '#d8a8a3', '#c8a8a3', '#b8a8a3', '#4e2c33' },
{ '#ffa724', '#efa024', '#dfa724', '#0040ff' },
{ '#afdc2b', '#09dc4b', '#08d04b', '#ef4f8f' },
}
api.nvim_set_hl(0, 'DiagnosticUnderlineError', { link = 'SpellBad', default = true })
api.nvim_set_hl(0, 'DiagnosticUnderlineWarning', { link = 'SpellRare', default = true })
api.nvim_set_hl(0, 'DiagnosticUnderlineInformation', { link = 'SpellRare', default = true })
api.nvim_set_hl(0, 'DiagnosticUnderlineHint', { link = 'SpellRare', default = true })
api.nvim_set_hl(0, 'NGPreviewTitle', { link = 'Title', default = true })
api.nvim_set_hl(0, 'LspReferenceRead', { default = true, link = 'IncSearch'})
api.nvim_set_hl(0, 'LspReferenceText', { default = true, link = 'Visual'})
api.nvim_set_hl( 0, 'LspReferenceWrite', { default = true, link = 'Search'})
for i = 1, #colors do
for j = 1, 3 do
local cmd = string.format('hi! default NGHiReference_%i_%i guibg=%s guifg=%s ', i, j, colors[i][j], colors[i][4])
vim.cmd(cmd)
local hlg = string.format('NGHiReference_%i_%i', i, j) -- , colors[i][j], colors[i][4]
api.nvim_set_hl(0, hlg, { fg = colors[i][j], bg = colors[i][4], default = true })
end
end
vim.cmd([[
autocmd ColorScheme * |
hi default LspReferenceRead cterm=bold gui=Bold ctermbg=yellow guifg=yellow guibg=purple4 |
hi default LspReferenceText cterm=bold gui=Bold ctermbg=red guifg=SlateBlue guibg=MidnightBlue |
hi default LspReferenceWrite cterm=bold gui=Bold,Italic ctermbg=red guifg=DarkSlateBlue guibg=MistyRose
]])
end
api.nvim_create_autocmd('ColorScheme', {
group = cmd_group,
pattern = '*',
callback = function()
M.add_highlight()
end,
})
return M

@ -1,78 +1,135 @@
local kind_symbols = {
Text = "",
Method = "ƒ",
Function = "",
Constructor = "",
Field = "",
Variable = "",
Class = "",
Interface = "",
Module = "",
Property = "",
Unit = "",
Value = "",
Enum = "",
Keyword = "",
Snippet = "",
Color = "",
File = "",
Reference = "",
Folder = "",
EnumMember = "",
Constant = "",
Struct = "",
Event = "",
Operator = "",
TypeParameter = "",
Default = ""
Text = '',
Method = 'ƒ',
Function = '',
Constructor = '',
Field = '',
Variable = '',
Class = '',
Interface = '',
Module = '',
Property = '',
Unit = '',
Value = '',
Enum = '',
Keyword = '',
Snippet = '',
Color = '',
File = '',
Reference = '',
Folder = '',
EnumMember = '',
Constant = '',
Struct = '',
Event = '',
Operator = '',
TypeParameter = '',
Default = '',
}
local CompletionItemKind = {
"", "𝔉 ", "", "", "", "", "", "", "", "", "", "", "𝕰 ", "",
"", "", "", "", "", "", "", "", "", "", "", ""
'',
'𝔉 ',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'𝕰 ',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
}
-- A symbol kind.
local SymbolKind = {
File = 1,
Module = 2,
Namespace = 3,
Package = 4,
Class = 5,
Method = 6,
Property = 7,
Field = 8,
Constructor = 9,
Enum = 10,
Interface = 11,
Function = 12,
Variable = 13,
Constant = 14,
String = 15,
Number = 16,
Boolean = 17,
Array = 18,
Object = 19,
Key = 20,
Null = 21,
EnumMember = 22,
Struct = 23,
Event = 24,
Operator = 25,
TypeParameter = 26
}
-- local SymbolKind = {
-- File = 1,
-- Module = 2,
-- Namespace = 3,
-- Package = 4,
-- Class = 5,
-- Method = 6,
-- Property = 7,
-- Field = 8,
-- Constructor = 9,
-- Enum = 10,
-- Interface = 11,
-- Function = 12,
-- Variable = 13,
-- Constant = 14,
-- String = 15,
-- Number = 16,
-- Boolean = 17,
-- Array = 18,
-- Object = 19,
-- Key = 20,
-- Null = 21,
-- EnumMember = 22,
-- Struct = 23,
-- Event = 24,
-- Operator = 25,
-- TypeParameter = 26
-- }
local SymbolItemKind = {
"", "", "", "", "", "ƒ ", "", "", "", "𝕰 ", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", ""
'',
'',
'',
'',
'',
'ƒ ',
'',
'',
'',
'𝕰 ',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
}
local lspkind = {}
function lspkind.comp_kind(kind) return CompletionItemKind[kind] or "" end
function lspkind.comp_kind(kind)
return CompletionItemKind[kind] or ''
end
function lspkind.symbol_kind(kind) return SymbolItemKind[kind] or "" end
function lspkind.symbol_kind(kind)
return SymbolItemKind[kind] or ''
end
function lspkind.cmp_kind(kind) return kind_symbols[kind] or "" end
function lspkind.cmp_kind(kind)
return kind_symbols[kind] or ''
end
function lspkind.init() require('vim.lsp.protocol').CompletionItemKind = CompletionItemKind end
function lspkind.init()
require('vim.lsp.protocol').CompletionItemKind = CompletionItemKind
end
return lspkind

@ -1,13 +1,7 @@
local util = require('navigator.util')
local log = util.log
local trace = util.trace
local event_hdlrs = {
{ ev = 'BufWritePre', func = [[require "navigator.diagnostics".set_diag_loclist()]] },
{ ev = 'CursorHold', func = 'document_highlight()' },
{ ev = 'CursorHoldI', func = 'document_highlight()' },
{ ev = 'CursorMoved', func = 'clear_references()' },
}
local api = vim.api
if vim.lsp.buf.format == nil then
vim.lsp.buf.format = vim.lsp.buf.formatting
@ -21,44 +15,60 @@ local single = { '╭', '─', '╮', '│', '╯', '─', '╰', '│' }
-- TODO https://github.com/neovim/neovim/pull/16591 use vimkeymap.set/del
-- LuaFormatter off
local key_maps = {
{ key = 'gr', func = "require('navigator.reference').async_ref()" },
{ key = '<Leader>gr', func = "require('navigator.reference').reference()" }, -- reference deprecated
{ mode = 'i', key = '<M-k>', func = 'signature_help()' },
{ key = '<c-k>', func = 'signature_help()' },
{ key = 'g0', func = "require('navigator.symbols').document_symbols()" },
{ key = 'gW', func = "require('navigator.workspace').workspace_symbol()" },
{ key = '<c-]>', func = "require('navigator.definition').definition()" },
{ key = 'gd', func = "require('navigator.definition').definition()" },
{ key = 'gD', func = "declaration({ border = 'rounded', max_width = 80 })" },
{ key = 'gp', func = "require('navigator.definition').definition_preview()" },
{ key = '<Leader>gt', func = "require('navigator.treesitter').buf_ts()" },
{ key = '<Leader>gT', func = "require('navigator.treesitter').bufs_ts()" },
{ key = 'K', func = 'hover({ popup_opts = { border = single, max_width = 80 }})' },
{ key = '<Space>ca', mode = 'n', func = "require('navigator.codeAction').code_action()" },
{ key = '<Space>cA', mode = 'v', func = 'range_code_action()' },
{ key = 'gr', func = require('navigator.reference').async_ref, desc = 'async_ref' },
{ key = '<Leader>gr', func = require('navigator.reference').reference, desc = 'reference' }, -- reference deprecated
{ mode = 'i', key = '<M-k>', func = vim.lsp.signature_help, desc = 'signature_help' },
{ key = '<c-k>', func = vim.lsp.buf.signature_help, desc = 'signature_help' },
{ key = 'g0', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' },
{ key = 'gW', func = require('navigator.workspace').workspace_symbol_live, desc = 'workspace_symbol_live' },
{ key = '<c-]>', func = require('navigator.definition').definition, desc = 'definition' },
{ key = 'gd', func = require('navigator.definition').definition, desc = 'definition' },
{ key = 'gD', func = vim.lsp.buf.declaration, desc = 'declaration' },
{ key = 'gp', func = require('navigator.definition').definition_preview, desc = 'definition_preview' },
{ key = '<Leader>gt', func = require('navigator.treesitter').buf_ts, desc = 'buf_ts' },
{ key = '<Leader>gT', func = require('navigator.treesitter').bufs_ts, desc = 'bufs_ts' },
{ key = '<Leader>ct', func = require('navigator.ctags').ctags, desc = 'ctags' },
{ key = 'K', func = vim.lsp.buf.hover, desc = 'hover' },
{ key = '<Space>ca', mode = 'n', func = require('navigator.codeAction').code_action, desc = 'code_action' },
{
key = '<Space>ca',
mode = 'v',
func = require('navigator.codeAction').range_code_action,
desc = 'range_code_action',
},
-- { key = '<Leader>re', func = 'rename()' },
{ key = '<Space>rn', func = "require('navigator.rename').rename()" },
{ key = '<Leader>gi', func = 'incoming_calls()' },
{ key = '<Leader>go', func = 'outgoing_calls()' },
{ key = 'gi', func = 'implementation()' },
{ key = '<Space>D', func = 'type_definition()' },
{ key = 'gL', func = "require('navigator.diagnostics').show_diagnostics()" },
{ key = 'gG', func = "require('navigator.diagnostics').show_buf_diagnostics()" },
{ key = '<Leader>dt', func = "require('navigator.diagnostics').toggle_diagnostics()" },
{ key = ']d', func = "diagnostic.goto_next({ border = 'rounded', max_width = 80})" },
{ key = '[d', func = "diagnostic.goto_prev({ border = 'rounded', max_width = 80})" },
{ key = ']O', func = 'diagnostic.set_loclist()' },
{ key = ']r', func = "require('navigator.treesitter').goto_next_usage()" },
{ key = '[r', func = "require('navigator.treesitter').goto_previous_usage()" },
{ key = '<C-LeftMouse>', func = 'definition()' },
{ key = 'g<LeftMouse>', func = 'implementation()' },
{ key = '<Leader>k', func = "require('navigator.dochighlight').hi_symbol()" },
{ key = '<Space>wa', func = "require('navigator.workspace').add_workspace_folder()" },
{ key = '<Space>wr', func = "require('navigator.workspace').remove_workspace_folder()" },
{ key = '<Space>ff', func = 'format({async = true})', mode = 'n' },
{ key = '<Space>ff', func = 'range_formatting()', mode = 'v' },
{ key = '<Space>wl', func = "require('navigator.workspace').list_workspace_folders()" },
{ key = '<Space>la', mode = 'n', func = "require('navigator.codelens').run_action()" },
{ key = '<Space>rn', func = require('navigator.rename').rename, desc = 'rename' },
{ key = '<Leader>gi', func = vim.lsp.buf.incoming_calls, desc = 'incoming_calls' },
{ key = '<Leader>go', func = vim.lsp.buf.outgoing_calls, desc = 'outgoing_calls' },
{ key = 'gi', func = vim.lsp.buf.implementation, desc = 'implementation' },
{ key = '<Space>D', func = vim.lsp.buf.type_definition, desc = 'type_definition' },
{ key = 'gL', func = require('navigator.diagnostics').show_diagnostics, desc = 'show_diagnostics' },
{ key = 'gG', func = require('navigator.diagnostics').show_buf_diagnostics, desc = 'show_buf_diagnostics' },
{ key = '<Leader>dt', func = require('navigator.diagnostics').toggle_diagnostics, desc = 'toggle_diagnostics' },
{ key = ']d', func = vim.diagnostic.goto_next, desc = 'next diagnostics' },
{ key = '[d', func = vim.diagnostic.goto_prev, desc = 'prev diagnostics' },
{ key = ']O', func = vim.diagnostic.set_loclist, desc = 'diagnostics set loclist' },
{ key = ']r', func = require('navigator.treesitter').goto_next_usage, desc = 'goto_next_usage' },
{ key = '[r', func = require('navigator.treesitter').goto_previous_usage, desc = 'goto_previous_usage' },
{ key = '<C-LeftMouse>', func = vim.lsp.buf.definition, desc = 'definition' },
{ key = 'g<LeftMouse>', func = vim.lsp.buf.implementation, desc = 'implementation' },
{ key = '<Leader>k', func = require('navigator.dochighlight').hi_symbol, desc = 'hi_symbol' },
{ key = '<Space>wa', func = require('navigator.workspace').add_workspace_folder, desc = 'add_workspace_folder' },
{
key = '<Space>wr',
func = require('navigator.workspace').remove_workspace_folder,
desc = 'remove_workspace_folder',
},
{ key = '<Space>ff', func = vim.lsp.buf.format, mode = 'n', desc = 'format' },
{ key = '<Space>ff', func = vim.lsp.buf.range_formatting, mode = 'v', desc = 'range format' },
{
key = '<Space>gm',
func = require('navigator.formatting').range_format,
mode = 'n',
desc = 'range format operator e.g gmip',
},
{ key = '<Space>wl', func = require('navigator.workspace').list_workspace_folders, desc = 'list_workspace_folders' },
{ key = '<Space>la', mode = 'n', func = require('navigator.codelens').run_action, desc = 'run code lens action' },
}
local key_maps_help = {}
@ -66,8 +76,8 @@ local key_maps_help = {}
local M = {}
local ccls_mappings = {
{ key = '<Leader>gi', func = "require('navigator.cclshierarchy').incoming_calls()" },
{ key = '<Leader>go', func = "require('navigator.cclshierarchy').outgoing_calls()" },
{ key = '<Leader>gi', func = require('navigator.cclshierarchy').incoming_calls, desc = 'incoming_calls' },
{ key = '<Leader>go', func = require('navigator.cclshierarchy').outgoing_calls, desc = 'outgoing_calls' },
}
local check_cap = function(opts)
@ -104,24 +114,52 @@ local check_cap = function(opts)
return fmt, rfmt, ccls
end
local function set_mapping(user_opts)
local function set_cmds(_)
local commands = {
[[command! -nargs=* Nctags lua require("navigator.ctags").ctags(<f-args>)]],
"command! -nargs=0 LspLog lua require'navigator.lspclient.config'.open_lsp_log()",
"command! -nargs=0 LspRestart lua require'navigator.lspclient.config'.reload_lsp()",
"command! -nargs=0 LspToggleFmt lua require'navigator.lspclient.mapping'.toggle_lspformat()<CR>",
"command! -nargs=0 LspKeymaps lua require'navigator.lspclient.mapping'.get_keymaps_help()<CR>",
"command! -nargs=0 LspSymbols lua require'navigator.symbols'.side_panel()<CR>",
"command! -nargs=0 TSymbols lua require'navigator.treesitter'.side_panel()<CR>",
"command! -nargs=0 NRefPanel lua require'navigator.reference'.side_panel()<CR>",
"command! -nargs=* Calltree lua require'navigator.hierarchy'.calltree(<f-args>)<CR>",
}
for _, value in pairs(commands) do
vim.cmd(value)
end
end
-- should works for both 1)attach from known lsp client or from a disabled lsp client
-- executed in on_attach context
local function set_mapping(lsp_attach_info)
local opts = { noremap = true, silent = true }
user_opts = user_opts or {}
log('setup mapping', user_opts)
vim.validate({
lsp_attach_info = { lsp_attach_info, 'table' },
})
if _NgConfigValues.debug then
log('setup mapping for client', lsp_attach_info.client.name, lsp_attach_info.client.cmd)
end
local user_key = _NgConfigValues.keymaps or {}
local bufnr = user_opts.bufnr or 0
local bufnr = lsp_attach_info.bufnr or 0
local function del_keymap(...)
vim.api.nvim_buf_del_keymap(bufnr, ...)
local function del_keymap(mode, key, ...)
local ks = vim.api.nvim_buf_get_keymap(bufnr, mode)
if vim.tbl_contains(ks, key) then
vim.api.nvim_buf_del_keymap(bufnr, mode, key, ...)
end
end
local function set_keymap(...)
vim.api.nvim_buf_set_keymap(bufnr, ...)
end
-- local function buf_set_option(...)
-- vim.api.nvim_buf_set_option(bufnr, ...)
-- end
local doc_fmt, range_fmt, ccls = check_cap(user_opts)
local doc_fmt, range_fmt, ccls = check_cap(lsp_attach_info)
if ccls then
vim.list_extend(key_maps, ccls_mappings)
@ -145,93 +183,110 @@ local function set_mapping(user_opts)
key_maps = _NgConfigValues.keymaps or {}
log('setting maps to ', key_maps)
end
local fmtkey, rfmtkey
local fmtkey, rfmtkey, nrfmtkey
require('navigator.formatting')
for _, value in pairs(key_maps) do
local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>'
if string.find(value.func, 'require') then
f = '<Cmd>lua ' .. value.func .. '<CR>'
elseif string.find(value.func, 'diagnostic') then
local diagnostic = '<Cmd>lua vim.'
diagnostic = '<Cmd>lua vim.'
f = diagnostic .. value.func .. '<CR>'
elseif string.find(value.func, 'vim.') then
f = '<Cmd>lua ' .. value.func .. '<CR>'
if value.doc then
vim.notify('doc field no longer supported in navigator mapping, use desc instead')
end
local k = value.key
local m = value.mode or 'n'
if string.find(value.func, 'range_formatting') then
rfmtkey = value.key
elseif string.find(value.func, 'format') then
fmtkey = value.key
if type(value.func) == 'string' then -- deprecated will remove when 0.8 is out
vim.notify('keymap config updated: ' .. value.key .. ' func ' .. value.func .. ' should be a function')
local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>'
if string.find(value.func, 'require') or string.find(value.func, 'vim.') then
f = '<Cmd>lua ' .. value.func .. '<CR>'
elseif string.find(value.func, 'diagnostic') then
local diagnostic = '<Cmd>lua vim.'
diagnostic = '<Cmd>lua vim.'
f = diagnostic .. value.func .. '<CR>'
end
local k = value.key
local m = value.mode or 'n'
if string.find(value.func, 'range_formatting') then
rfmtkey = value.key
elseif string.find(value.func, 'format') then
fmtkey = value.key
end
trace('binding', k, f)
set_keymap(m, k, f, opts)
end
log('binding', k, f)
set_keymap(m, k, f, opts)
end
if type(value.func) == 'function' then -- new from 0.7.x
-- neovim 0.7.0
opts.buffer = key_maps.buffer or value.buffer
if value.desc then
opts.desc = value.desc
end
opts.buffer = bufnr
vim.keymap.set(value.mode or 'n', value.key, value.func, opts)
if string.find(value.desc, 'range format') and value.mode == 'v' then
rfmtkey = value.key
if string.find(value.desc, 'range format') and value.mode == 'n' then
nrfmtkey = value.key
elseif string.find(value.desc, 'format') then
fmtkey = value.key
end
end
end
end
for _, val in pairs(key_maps) do
table.insert(key_maps_help, (val.mode or 'n') .. '|' .. val.key .. '|' .. val.func)
local helper_msg = ''
if val.desc then
helper_msg = val.desc
elseif type(val.func) == 'string' then
helper_msg = val.func
end
local item = (val.mode or 'n') .. '|' .. val.key .. '|' .. helper_msg
if not vim.tbl_contains(key_maps_help, item) then
table.insert(key_maps_help, (val.mode or 'n') .. '|' .. val.key .. '|' .. helper_msg)
end
end
-- if user_opts.cap.document_formatting then
if doc_fmt and _NgConfigValues.lsp.format_on_save then
vim.cmd([[
aug NavigatorAuFormat
au!
autocmd BufWritePre <buffer> lua vim.lsp.buf.format({async = true})
aug END
]])
local gn = api.nvim_create_augroup('NavAuGroupFormat', {})
local fopts = _NgConfigValues.lsp.format_options
if not fopts.async and vim.api.nvim_buf_line_count(0) > 4000 then
fopts.async = true
end
api.nvim_create_autocmd({ 'BufWritePre' }, {
group = gn,
buffer = bufnr,
callback = function()
trace('format' .. vim.inspect(fopts))
vim.lsp.buf.format(fopts)
end,
})
elseif fmtkey then
del_keymap('n', fmtkey)
end
if user_opts.cap and user_opts.cap.document_range_formatting then
log('formatting enabled', user_opts.cap)
if lsp_attach_info.cap and lsp_attach_info.cap.document_range_formatting then
log('formatting enabled', lsp_attach_info.cap)
end
if not range_fmt and rfmtkey then
del_keymap('v', rfmtkey)
end
if not range_fmt and nrfmtkey then
del_keymap('n', nrfmtkey)
end
log('enable format ', doc_fmt, range_fmt, _NgConfigValues.lsp.format_on_save)
end
local function autocmd(user_opts)
vim.api.nvim_exec(
[[
aug NavigatorDocHlAu
au!
au CmdlineLeave : lua require('navigator.dochighlight').cmd_nohl()
aug END
]],
false
)
end
local function autocmd()
local gn = api.nvim_create_augroup('NavAuGroupDocHlAu', {})
local function set_event_handler(user_opts)
user_opts = user_opts or {}
local file_types =
'c,cpp,h,go,python,vim,sh,javascript,html,css,lua,typescript,rust,javascriptreact,typescriptreact,kotlin,php,dart,nim,java'
-- local format_files = "c,cpp,h,go,python,vim,javascript,typescript" --html,css,
vim.api.nvim_command([[augroup nvim_nv_lsp_autos]])
vim.api.nvim_command([[autocmd!]])
for _, value in pairs(event_hdlrs) do
local f = ''
if string.find(value.func, 'require') ~= nil then
f = 'lua ' .. value.func
else
f = 'lua vim.lsp.buf.' .. value.func
end
local cmd = 'autocmd FileType '
.. file_types
.. ' autocmd nvim_nv_lsp_autos '
.. value.ev
.. ' <buffer> silent! '
.. f
vim.api.nvim_command(cmd)
end
vim.api.nvim_command([[augroup END]])
api.nvim_create_autocmd({ 'BufWritePre' }, {
group = gn,
callback = require('navigator.dochighlight').cmd_nohl,
})
end
M.toggle_lspformat = function(on)
@ -253,17 +308,23 @@ M.toggle_lspformat = function(on)
end
end
function M.setup(user_opts)
user_opts = user_opts or _NgConfigValues
set_mapping(user_opts)
function M.setup(attach_opts)
if not attach_opts or not attach_opts.client then
vim.notify(
'please call require"navigator.mapping".setup({bufnr=bufnr, client=client}) inside on_attach(client,bufnr)',
vim.lsp.log_levels.WARN
)
end
attach_opts = attach_opts or { bufnr = 0, client = {}, cap = {} }
set_mapping(attach_opts)
set_cmds(attach_opts)
autocmd(user_opts)
set_event_handler(user_opts)
autocmd()
local client = user_opts.client or {}
local client = attach_opts.client or {}
local cap = client.server_capabilities or vim.lsp.protocol.make_client_capabilities()
log('lsp cap:', cap)
log('lsp cap:', cap.codeActionProvider)
if cap.call_hierarchy or cap.callHierarchyProvider then
vim.lsp.handlers['callHierarchy/incomingCalls'] = require('navigator.hierarchy').incoming_calls_handler
@ -301,7 +362,19 @@ function M.setup(user_opts)
})
end
vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = single })
api.nvim_create_autocmd({ 'BufWritePre' }, {
group = api.nvim_create_augroup('nvim_nv_event_autos', {}),
buffer = attach_opts.bufnr,
callback = function()
require('navigator.diagnostics').set_diag_loclist(attach_opts.bufnr)
end,
})
local border_style = single
if _NgConfigValues.border == 'double' then
border_style = double
end
vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = border_style })
if cap.documentFormattingProvider then
log('formatting enabled setup hdl')
vim.lsp.handlers['textDocument/formatting'] = require('navigator.formatting').format_hdl
@ -315,7 +388,7 @@ M.get_keymaps_help = function()
border = 'none',
prompt = true,
enter = true,
rect = { height = 20, width = 90 },
rect = { height = 24, width = 50 },
data = key_maps_help,
})

@ -0,0 +1,47 @@
return {
'angularls',
'gopls',
'tsserver',
'flow',
'bashls',
'dockerls',
'julials',
'pylsp',
'pyright',
'jedi_language_server',
'jdtls',
'sumneko_lua',
'vimls',
'html',
'jsonls',
'solargraph',
'cssls',
'yamlls',
'clangd',
'ccls',
'sqls',
'denols',
'graphql',
'dartls',
'dotls',
'kotlin_language_server',
'nimls',
'intelephense',
'vuels',
'volar',
'phpactor',
'omnisharp',
'r_language_server',
'rust_analyzer',
'terraformls',
'svelte',
'texlab',
'clojure_lsp',
'elixirls',
'sourcekit',
'fsautocomplete',
'vls',
'hls',
'tflint',
'terraform_lsp',
}

@ -0,0 +1,89 @@
local vfn = vim.fn
local library = {}
local sumneko_cfg = {
cmd = { 'lua-language-server' },
filetypes = { 'lua' },
on_attach = on_attach,
flags = { allow_incremental_sync = true, debounce_text_changes = 500 },
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
version = 'LuaJIT',
},
diagnostics = {
enable = true,
-- Get the language server to recognize the `vim` global
globals = { 'vim', 'describe', 'it', 'before_each', 'after_each', 'teardown', 'pending' },
},
completion = { callSnippet = 'Both' },
workspace = {
-- Make the server aware of Neovim runtime files
library = library,
maxPreload = 2000,
preloadFileSize = 40000,
},
telemetry = { enable = false },
},
},
on_new_config = function(cfg, root)
local libs = vim.tbl_deep_extend('force', {}, library)
libs[root] = nil
cfg.settings.Lua.workspace.library = libs
return cfg
end,
}
local function add(lib)
for _, p in pairs(vfn.expand(lib, false, true)) do
p = vim.loop.fs_realpath(p)
if p then
library[p] = true
end
end
end
local function sumneko_lua()
-- add runtime
-- add plugins it may be very slow to add all in path
add('$VIMRUNTIME')
-- add your config
-- local home = vfn.expand("$HOME")
add(vfn.stdpath('config'))
library[vfn.expand('$VIMRUNTIME/lua')] = true
library[vfn.expand('$VIMRUNTIME/lua/vim')] = true
library[vfn.expand('$VIMRUNTIME/lua/vim/lsp')] = true
local on_attach = require('navigator.lspclient.attach').on_attach
local luadevcfg = {
library = {
vimruntime = true, -- runtime path
types = true, -- full signature, docs and completion of vim.api, vim.treesitter, vim.lsp and others
plugins = { 'nvim-treesitter', 'plenary.nvim' },
},
lspconfig = {
-- cmd = {sumneko_binary},
on_attach = on_attach,
},
}
local luadev = {}
local user_luadev = _NgConfigValues.lsp['lua-dev']
if user_luadev then
luadevcfg = vim.tbl_deep_extend('force', luadevcfg, user_luadev)
end
require('navigator.lazyloader').load('lua-dev.nvim', 'folke/lua-dev.nvim')
local ok, l = pcall(require, 'lua-dev')
if ok and l then
luadev = l.setup(luadevcfg)
end
sumneko_cfg = vim.tbl_deep_extend('force', sumneko_cfg, luadev)
return sumneko_cfg
end
return {
sumneko_lua = sumneko_lua,
}

@ -19,7 +19,7 @@ cwd = gutil.add_pec(cwd)
local ts_nodes = require('navigator.lru').new(1000, 1024 * 1024)
local ts_nodes_time = require('navigator.lru').new(1000)
local TS_analysis_enabled = require('navigator').config_values().treesitter_analysis
local nts = require('navigator.treesitter')
-- extract symbol from range
function M.get_symbol(text, range)
if range == nil then
@ -74,7 +74,8 @@ end
function M.symbols_to_items(result)
local locations = {}
-- log(result)
result = result or {}
log(#result)
for i = 1, #result do
local item = result[i].location
if item ~= nil and item.range ~= nil then
@ -86,8 +87,9 @@ function M.symbols_to_items(result)
if kind ~= nil then
item.text = kind .. ': ' .. item.text
end
item.filename = vim.uri_to_fname(item.uri)
if not item.filename then
item.filename = vim.uri_to_fname(item.uri)
end
item.display_filename = item.filename:gsub(cwd .. path_sep, path_cur, 1)
if item.range == nil or item.range.start == nil then
log('range not set', result[i], item)
@ -143,29 +145,31 @@ end
function M.call_sync(method, params, opts, handler)
params = params or {}
opts = opts or {}
local results_lsp, err = lsp.buf_request_sync(0, method, params, opts.timeout or vim.g.navtator_timeout or 1000)
log(method, params)
local results_lsp, err = lsp.buf_request_sync(opts.bufnr or 0, method, params, opts.timeout or 1000)
handler(err, extract_result(results_lsp), { method = method }, nil)
return handler(err, extract_result(results_lsp), { method = method, no_show = opts.no_show }, nil)
end
function M.call_async(method, params, handler)
function M.call_async(method, params, handler, bufnr)
params = params or {}
local callback = function(...)
util.show(...)
handler(...)
end
return lsp.buf_request(0, method, params, callback)
bufnr = bufnr or 0
return lsp.buf_request(bufnr, method, params, callback)
-- results_lsp, canceller
end
local function ts_functions(uri)
local function ts_functions(uri, optional)
local unload_bufnr
local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals')
if not ts_enabled or not TS_analysis_enabled then
lerr('ts not enabled')
return nil
end
local ts_func = require('navigator.treesitter').buf_func
local ts_func = nts.buf_func
local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock()
trace(ts_nodes)
@ -183,6 +187,9 @@ local function ts_functions(uri)
ts_nodes_time:delete(uri)
end
end
if optional then
return
end
local unload = false
if not api.nvim_buf_is_loaded(bufnr) then
trace('! load buf !', uri, bufnr)
@ -202,7 +209,7 @@ local function ts_functions(uri)
return funcs, unload_bufnr
end
local function ts_definition(uri, range)
local function ts_definition(uri, range, optional)
local unload_bufnr
local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals')
if not ts_enabled or not TS_analysis_enabled then
@ -220,7 +227,10 @@ local function ts_definition(uri, range)
log('ts def from cache')
return tsnodes
end
local ts_def = require('navigator.treesitter').find_definition
if optional then
return
end
local ts_def = nts.find_definition
local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock()
trace(ts_nodes)
@ -242,6 +252,7 @@ local function ts_definition(uri, range)
end
local function find_ts_func_by_range(funcs, range)
log(funcs, range)
if funcs == nil or range == nil then
return nil
end
@ -294,20 +305,27 @@ local function slice_locations(locations, max_items)
return first_part, second_part
end
local function test_locations()
local locations = {
{ uri = '1', range = { start = { line = 1 } } },
{ uri = '2', range = { start = { line = 2 } } },
{ uri = '2', range = { start = { line = 3 } } },
{ uri = '1', range = { start = { line = 3 } } },
{ uri = '1', range = { start = { line = 4 } } },
{ uri = '3', range = { start = { line = 4 } } },
{ uri = '3', range = { start = { line = 4 } } },
}
local second_part
order_locations(locations)
local locations, second_part = slice_locations(locations, 3)
log(locations, second_part)
-- local function test_locations()
-- local locations = {
-- { uri = '1', range = { start = { line = 1 } } },
-- { uri = '2', range = { start = { line = 2 } } },
-- { uri = '2', range = { start = { line = 3 } } },
-- { uri = '1', range = { start = { line = 3 } } },
-- { uri = '1', range = { start = { line = 4 } } },
-- { uri = '3', range = { start = { line = 4 } } },
-- { uri = '3', range = { start = { line = 4 } } },
-- }
-- local second_part
-- order_locations(locations)
-- local locations, second_part = slice_locations(locations, 3)
-- log(locations, second_part)
-- end
local function ts_optional(i, unload_buf_size)
if unload_buf_size then
return unload_buf_size > _NgConfigValues.treesitter_analysis_max_num
end
return i > _NgConfigValues.treesitter_analysis_max_num
end
function M.locations_to_items(locations, ctx)
@ -335,7 +353,6 @@ function M.locations_to_items(locations, ctx)
local unload_bufnrs = {}
for i, loc in ipairs(locations) do
local funcs = nil
local item = lsp.util.locations_to_items({ loc }, enc)[1]
item.range = locations[i].range or locations[i].targetRange
item.uri = locations[i].uri or locations[i].targetUri
@ -346,17 +363,29 @@ function M.locations_to_items(locations, ctx)
log(cwd)
end
-- only load top 30 file.
local proj_file = item.uri:find(cwd) or is_win or i < 30
local proj_file = item.uri:find(cwd) or is_win or i < _NgConfigValues.treesitter_analysis_max_num
local unload, def
if TS_analysis_enabled and proj_file then
funcs, unload = ts_functions(item.uri)
local context = ''
if TS_analysis_enabled and proj_file and not ctx.no_show then
local ts_context = nts.ref_context
local bufnr = vim.uri_to_bufnr(item.uri)
if not api.nvim_buf_is_loaded(bufnr) then
log('! load buf !', item.uri, bufnr)
vim.fn.bufload(bufnr)
unload = bufnr
end
context = ts_context({ bufnr = bufnr, pos = item.range }) or ''
log(context)
-- TODO: unload buffers
if unload then
table.insert(unload_bufnrs, unload)
unload = nil
end
if not uri_def[item.uri] then
-- find def in file
def, unload = ts_definition(item.uri, item.range)
def, unload = ts_definition(item.uri, item.range, ts_optional(i, #unload_bufnrs))
if def and def.start then
uri_def[item.uri] = def
if def.start then -- find for the 1st time
@ -391,9 +420,15 @@ function M.locations_to_items(locations, ctx)
end
item.filename = assert(vim.uri_to_fname(item.uri))
local filename = item.filename:gsub(cwd .. path_sep, path_cur, 1)
if ctx.no_show then
local shorten = require('guihua.util').shorten
filename = shorten(filename)
end
item.display_filename = filename or item.filename
item.call_by = find_ts_func_by_range(funcs, item.range)
item.call_by = context -- find_ts_func_by_range(funcs, item.range)
item.rpath = util.get_relative_path(cwd, item.filename)
width = math.max(width, #item.text)
item.symbol_name = M.get_symbol(item.text, item.range)
@ -416,8 +451,8 @@ function M.locations_to_items(locations, ctx)
vim.cmd([[set eventignore-=FileType]])
log(items)
return items, width + 24, second_part -- TODO handle long line?
trace(items)
return items, width + 30, second_part -- TODO handle long line?
end
function M.symbol_to_items(locations)
@ -462,7 +497,7 @@ end
function M.request(method, hdlr) -- e.g textDocument/reference
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _)
client.request(method, ref_params, hdlr, bufnr)
end)
end

@ -4,7 +4,6 @@ local lsphelper = require('navigator.lspwrapper')
local gui = require('navigator.gui')
local lsp = require('navigator.lspwrapper')
local trace = require('navigator.util').trace
ListViewCtrl = ListViewCtrl or require('guihua.listviewctrl').ListViewCtrl
-- local partial = util.partial
-- local cwd = vim.loop.cwd()
-- local lsphelper = require "navigator.lspwrapper"
@ -12,12 +11,13 @@ local locations_to_items = lsphelper.locations_to_items
local M = {}
local ref_view = function(err, locations, ctx, cfg)
cfg = cfg or {}
local truncate = cfg and cfg.truncate or 20
local opts = {}
trace('arg1', err, ctx, locations)
trace(locations)
-- log(#locations, locations[1])
if ctx.combine then
-- wait for both request
-- wait for both reference and definition LSP request
if ctx.results == nil then
return
end
@ -27,7 +27,11 @@ local ref_view = function(err, locations, ctx, cfg)
end
local definitions = ctx.results.definitions
local references = ctx.results.references
log(ctx)
if _NgConfigValues.debug then
local logctx = { results = {} }
logctx = vim.tbl_extend('keep', logctx, ctx)
log(logctx, 'result size', 'def', #ctx.results.definitions, 'ref', #ctx.results.references)
end
if definitions.error and references.error then
vim.notify('lsp ref callback error' .. vim.inspect(ctx.result), vim.lsp.log_levels.WARN)
end
@ -38,24 +42,16 @@ local ref_view = function(err, locations, ctx, cfg)
end
vim.list_extend(locations, definitions.result)
end
if references and references.result and #references.result > 0 then
local refs = references.result
for _, value in pairs(locations) do
vrange = value.range or { start = { line = 0 }, ['end'] = { line = 0 } }
for i = 1, #refs, 1 do
local rg = refs[i].range or {}
log(value, refs[i])
log(rg, vrange)
if rg.start.line == vrange.start.line and rg['end'].line == vrange['end'].line then
table.remove(refs, i)
break
end
end
end
vim.list_extend(locations, refs)
end
err = nil
log(locations)
trace(locations)
-- lets de-dup first 10 elements. some lsp does not recognize definition and reference difference
locations = util.dedup(locations)
trace(locations)
end
-- log("num", num)
-- log("bfnr", bufnr)
@ -83,11 +79,11 @@ local ref_view = function(err, locations, ctx, cfg)
local thread_items = vim.deepcopy(items)
log('splits: ', #items, #second_part)
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')
local wwidth = vim.api.nvim_get_option('columns')
local mwidth = _NgConfigValues.width
width = math.min(width + 30, 120, math.floor(wwidth * mwidth))
width = math.min(width + 30, math.floor(wwidth * mwidth))
-- log(items)
-- log(width)
opts = {
@ -99,12 +95,22 @@ local ref_view = function(err, locations, ctx, cfg)
api = 'Reference',
enable_preview_edit = true,
}
local listview = gui.new_list_view(opts)
local listview
if not ctx.no_show then
listview = gui.new_list_view(opts)
if listview == nil then
vim.notify('failed to create preview windows', vim.lsp.log_levels.INFO)
return
if listview == nil then
vim.notify('failed to create preview windows', vim.lsp.log_levels.INFO)
return
end
end
if ctx.no_show then
opts.side_panel = true
local data = require('navigator.render').prepare_for_render(items, opts)
return data
end
-- trace("update items", listview.ctrl.class)
local nv_ref_async
nv_ref_async = vim.loop.new_async(vim.schedule_wrap(function()
@ -112,11 +118,13 @@ local ref_view = function(err, locations, ctx, cfg)
if vim.tbl_isempty(second_part) then
return
end
ctx.max_items = #second_part
local items2 = locations_to_items(second_part, ctx)
vim.list_extend(thread_items, items2)
local data = require('navigator.render').prepare_for_render(thread_items, opts)
log('thread data size', #data)
listview.ctrl:on_data_update(data)
if nv_ref_async then
vim.loop.close(nv_ref_async)
@ -137,6 +145,9 @@ end
local ref_hdlr = function(err, locations, ctx, cfg)
_NgConfigValues.closer = nil
trace(err, locations, ctx, cfg)
if ctx.no_show then
return ref_view(err, locations, ctx, cfg)
end
M.async_hdlr = vim.loop.new_async(vim.schedule_wrap(function()
ref_view(err, locations, ctx, cfg)
if M.async_hdlr:is_active() then
@ -204,20 +215,46 @@ local ref = function()
local bufnr = vim.api.nvim_get_current_buf()
local ref_params = vim.lsp.util.make_position_params()
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, bufnr)
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _)
if client.server_capabilities.referencesProvider then
client.request('textDocument/references', ref_params, ref_hdlr, bufnr)
end
end)
end
return {
local function side_panel()
local Panel = require('guihua.panel')
reference_handler = ref_hdlr,
local currentWord = vim.fn.expand('<cword>')
local p = Panel:new({
scope = 'range',
header = '' .. currentWord .. ' ref ',
render = function(bufnr)
local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype')
if ft == 'nofile' or ft == 'guihua' or ft == 'prompt' then
return
end
local ref_params = vim.lsp.util.make_position_params()
local sync_req = require('navigator.lspwrapper').call_sync
return sync_req(
'textDocument/references',
ref_params,
{ timeout = 1000, bufnr = bufnr, no_show = true },
vim.lsp.with(function(err, locations, ctx, cfg)
cfg.side_panel = true
return ref_hdlr(err, locations, ctx, cfg)
end, { no_show = true })
)
end,
})
p:open(true)
end
return {
side_panel = side_panel,
reference_handler = ref_hdlr,
reference = ref_req,
ref_view = ref_view,
async_ref = async_ref,
all_ref = ref,
}

@ -1,7 +1,9 @@
local log = require('guihua.log').info
local trace = require('guihua.log').trace
local M = {}
local util = require('navigator.util')
local log = util.log
local trace = util.trace
local clone = require('guihua.util').clone
local M = {}
local function filename(url)
if url == nil then
return ''
@ -68,18 +70,10 @@ function M.prepare_for_render(items, opts)
local ext = extension(fn)
icon = devicons.get_icon(fn, ext) or icon
end
local call_by_presented = false
local width = 100
opts.width = opts.width or width
-- local call_by_presented = false
opts.width = opts.width or math.floor(vim.api.nvim_get_option('columns') * 0.8)
local win_width = opts.width -- buf
for i = 1, #items do
if items[i].call_by and #items[i].call_by > 0 then
call_by_presented = true
end
end
-- log(items[1])
for i = 1, #items do
local space
local trim
@ -97,7 +91,7 @@ function M.prepare_for_render(items, opts)
display_items[last_summary_idx].filename_only = true
-- trace(items[i], items[i].filename, last_summary_idx, display_items[last_summary_idx].filename)
-- TODO refact display_filename generate part
if items[i].filename == fn then
if items[i].filename == fn or opts.hide_filename then
space, trim = get_pads(opts.width, icon .. ' ' .. dfn, lspapi_display .. ' 14 of 33 ')
if trim and opts.width > 50 and #dfn > opts.width - 20 then
local fn1 = string.sub(dfn, 1, opts.width - 50)
@ -148,7 +142,8 @@ function M.prepare_for_render(items, opts)
ts_report = _NgConfigValues.icons.value_changed
end
log(item.text, item.symbol_name, item.uri)
-- log(item.text, item.symbol_name, item.uri)
-- log(item.text)
if item.definition then
log('definition', item)
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
@ -157,41 +152,28 @@ function M.prepare_for_render(items, opts)
trace(ts_report, header_len)
item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '')
if item.call_by ~= nil and #item.call_by > 0 then
trace('call_by:', #item.call_by)
for _, value in pairs(item.call_by) do
if value.node_text then
local txt = value.node_text:gsub('%s*[%[%(%{]*%s*$', '')
local endwise = '{}'
if value.type == 'method' or value.type == 'function' then
endwise = '()'
local syb = items[i].symbol_name
if txt == items[i].symbol_name or (#txt > #syb and txt:sub(#txt - #syb + 1) == syb) then
if ts_report ~= _NgConfigValues.icons.value_definition .. ' ' then
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
end
header_len = #ts_report + 1
else
ts_report = ts_report .. ''
end
end
if #ts_report > header_len then
ts_report = ts_report .. ''
end
ts_report = ts_report .. value.kind .. txt .. endwise
trace(item)
end
end
if item.call_by ~= nil and item.call_by ~= '' then
ts_report = ts_report .. '' .. item.call_by
end
if #ts_report > 1 then
space, trim = get_pads(win_width, item.text, ts_report)
local l = math.max(20, opts.width - math.min(20, #ts_report))
if trim and #item.text < l then
trim = false
end
if trim then
item.text = string.sub(item.text, 1, opts.width - 20) .. ''
item.text = string.sub(item.text, 1, l)
item.text = util.sub_match(item.text)
-- let check if there are unmatched "/'
end
if #space + #item.text + #ts_report >= win_width then
if #item.text + #ts_report > win_width then
trace('exceeding', #item.text, #ts_report, win_width)
space = ' '
if #item.text + #ts_report >= win_width then
space = ' '
local len = math.max(win_width - #item.text - 4, 16)
trace('exceeding', #item.text, #ts_report, win_width, len)
ts_report = ts_report:sub(1, len)
else
local remain = win_width - #item.text - #ts_report
trace('remain', remain)

@ -1,10 +1,5 @@
local gui = require "navigator.gui"
local util = require "navigator.util"
local log = util.log
local partial = util.partial
local lsphelper = require "navigator.lspwrapper"
local cwd = vim.loop.cwd()
local M = {}
--- navigator signature
local match_parameter = function(result)

@ -3,8 +3,6 @@ local M = {}
local log = require('navigator.util').log
local trace = require('navigator.util').trace
local lsphelper = require('navigator.lspwrapper')
local locations_to_items = lsphelper.locations_to_items
local clone = require('guihua.util').clone
local symbol_kind = require('navigator.lspclient.lspkind').symbol_kind
local symbols_to_items = lsphelper.symbols_to_items
@ -12,8 +10,7 @@ function M.workspace_symbols(query)
query = query or pcall(vim.fn.input, 'Query: ')
local bufnr = vim.api.nvim_get_current_buf()
local params = { query = query }
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
-- if client.resolved_capabilities.workspace_symbol then
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _bufnr)
if client.server_capabilities.workspaceSymbolProvider then
client.request('workspace/symbol', params, M.workspace_symbol_handler, _bufnr)
end
@ -34,8 +31,7 @@ function M.document_symbols(opts)
local params = vim.lsp.util.make_position_params()
params.context = { includeDeclaration = true }
params.query = opts.prompt or ''
vim.lsp.for_each_buffer_client(bufnr, function(client, client_id, _bufnr)
-- if client.resolved_capabilities.document_symbol then
vim.lsp.for_each_buffer_client(bufnr, function(client, _, _bufnr)
if client.server_capabilities.documentSymbolProvider then
client.request('textDocument/documentSymbol', params, M.document_symbol_handler, _bufnr)
end
@ -53,7 +49,7 @@ M.document_symbol_handler = function(err, result, ctx)
end
if not result or vim.tbl_isempty(result) then
vim.notify('symbol' .. query .. 'not found for buf' .. vim.inspect(ctx), vim.lsp.log_levels.WARN)
vim.notify('symbol ' .. query .. ' not found for buf ' .. vim.inspect(ctx), vim.lsp.log_levels.WARN)
return
end
local locations = {}
@ -67,6 +63,9 @@ M.document_symbol_handler = function(err, result, ctx)
local kind = symbol_kind(item.kind)
item.name = result[i].name
item.range = result[i].range or result[i].location.range
if item.range == nil then
log('range missing in result', result[i])
end
item.uri = uri
item.selectionRange = result[i].selectionRange
item.detail = result[i].detail or ''
@ -74,10 +73,14 @@ M.document_symbol_handler = function(err, result, ctx)
item.detail = 'func'
end
item.lnum = result[i].range.start.line + 1
item.lnum = item.range.start.line + 1
item.text = '[' .. kind .. ']' .. item.name .. ' ' .. item.detail
item.filename = fname
item.indent_level = 1
item.type = kind
item.node_text = item.name
table.insert(locations, item)
if result[i].children ~= nil then
@ -85,21 +88,36 @@ M.document_symbol_handler = function(err, result, ctx)
local child = {}
child.kind = c.kind
child.name = c.name
child.range = c.range
child.range = c.range or c.location.range
local ckind = symbol_kind(child.kind)
child.node_text = child.name
child.type = ckind
child.selectionRange = c.selectionRange
child.filename = fname
child.uri = uri
child.lnum = c.range.start.line + 1
child.lnum = child.range.start.line + 1
child.detail = c.detail or ''
child.indent_level = item.indent_level + 1
child.text = '' .. ckind .. '' .. child.name .. ' ' .. child.detail
table.insert(locations, child)
end
end
end
if ctx.no_show then
return locations
end
local ft = vim.api.nvim_buf_get_option(bufnr, 'ft')
gui.new_list_view({ items = locations, prompt = true, rawdata = true, ft = ft, api = '' })
gui.new_list_view({
items = locations,
prompt = true,
rawdata = true,
height = 0.62,
preview_height = 0.1,
ft = ft,
api = _NgConfigValues.icons.doc_symbol,
})
end
M.workspace_symbol_handler = function(err, result, ctx, cfg)
@ -124,4 +142,27 @@ M.workspace_symbol_handler = function(err, result, ctx, cfg)
gui.new_list_view({ items = items, prompt = true, ft = ft, rowdata = true, api = '' })
end
function M.side_panel()
local Panel = require('guihua.panel')
local buf = vim.api.nvim_get_current_buf()
local p = Panel:new({
scope = 'range',
render = function(bufnr)
local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype')
if ft == 'nofile' or ft == 'guihua' or ft == 'prompt' then
return
end
local params = vim.lsp.util.make_range_params()
local sync_req = require('navigator.lspwrapper').call_sync
return sync_req(
'textDocument/documentSymbol',
params,
{ timeout = 1000, bufnr = bufnr, no_show = true },
vim.lsp.with(M.document_symbol_handler, { no_show = true })
)
end,
})
p:open(true)
end
return M

@ -22,7 +22,11 @@ local M = {}
local cwd = vim.loop.cwd()
local log = require('navigator.util').log
local lerr = require('navigator.util').error
local trace = require('navigator.util').trace
local trace = function(...) end
trace = log
if vim.fn.has('nvim-0.7') == 1 then
local trace = require('navigator.util').trace
end
local get_icon = function(kind)
if kind == nil or _NgConfigValues.icons.match_kinds[kind] == nil then
@ -106,20 +110,179 @@ function M.find_definition(range, bufnr)
end
end
function M.get_tsnode_at_pos(pos, bufnr, ignore_injected_langs)
if not pos or not pos.start then
return
end
local cursor_range = { pos.start.line, pos.start.character }
local buf = bufnr
local root_lang_tree = parsers.get_parser(buf)
if not root_lang_tree then
return
end
local root
if ignore_injected_langs then
for _, tree in ipairs(root_lang_tree:trees()) do
local tree_root = tree:root()
if tree_root and ts_utils.is_in_node_range(tree_root, cursor_range[1], cursor_range[2]) then
root = tree_root
break
end
end
else
root = ts_utils.get_root_for_position(cursor_range[1], cursor_range[2], root_lang_tree)
end
if not root then
return
end
return root:named_descendant_for_range(cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2])
end
-- Trim spaces and opening brackets from end
local transform_line = function(line)
line = line:gsub("%s*[%[%(%{]*%s*$", "")
line = line:gsub("function", "")
line = line:gsub("func%w*%s+", "")
if _NgConfigValues.treesitter_analysis_condense then
line = line:gsub("%([%a%.,%s%[%]%*]+%)", "()")
-- this is for multi return
line = line:gsub("%([%a%.,%s%[%]%*]+%)", "()")
line = line:gsub("%(%)%s*%(%)", "()")
end
return line
end
function M.ref_context(opts)
if not parsers.has_parser() then
return
end
local options = opts or {}
local bufnr = options.bufnr or 0
local pos = options.pos
if not pos then
pos = {start = vim.lsp.util.make_position_params().position}
end
local indicator_size = options.indicator_size or 100
local type_patterns = options.type_patterns or { "class", "function", "method" }
local transform_fn = options.transform_fn or transform_line
local separator = options.separator or ""
local current_node = M.get_tsnode_at_pos(pos, bufnr)
if not current_node then
log('no node at pos', bufnr, pos)
return ""
end
local lines = {}
local expr = current_node
while expr do
local line = ts_utils._get_line_for_node(expr, type_patterns, transform_fn, bufnr)
log(line)
if line ~= "" and not vim.tbl_contains(lines, line) then
table.insert(lines, 1, line)
end
expr = expr:parent()
end
local text = table.concat(lines, separator)
local text_len = #text
if text_len > indicator_size then
local str = text:sub(1, text_len)
return util.sub_match(str)
end
return text
end
--- Get definitions of bufnr (unique and sorted by order of appearance).
--- This function copy from treesitter/refactor/navigation.lua
local function get_definitions(bufnr)
local local_nodes = ts_locals.get_locals(bufnr)
-- Make sure the nodes are unique.
local nodes_set = {}
for _, loc in ipairs(local_nodes) do
trace(loc)
if loc.definition then
ts_locals.recurse_local_nodes(loc.definition, function(_, node, _, match)
-- lua doesn't compare tables by value,
-- use the value from byte count instead.
local _, _, start = node:start()
nodes_set[start] = { node = node, type = match or '' }
local row, col, offset = node:start()
local erow, ecol, end_ = node:end_()
trace(node, match)
trace(row, col, erow, offset, node:parent(), node:parent():start(), node:parent():type())
if node and node:parent() and string.find(node:parent():type(), 'parameter_declaration') then
log('parameter_declaration skip')
return
end
nodes_set[offset] = { node = node, type = match or '' }
end)
end
if loc.method then -- for go
ts_locals.recurse_local_nodes(loc.method, function(def, node, full_match, match)
local row, col, start = node:start()
trace(row, col, start, def, node, full_match, match, node:parent(), node:parent():start(), node:parent():type())
if node:type() == 'field_identifier' and nodes_set[start] == nil then
nodes_set[start] = { node = node, type = 'method' }
end
end)
end
if loc.interface then -- for go using interface can output full method definition
ts_locals.recurse_local_nodes(loc.interface, function(def, node, full_match, match)
local k, l, start = node:start()
trace(k, l, start, def, node, full_match, match, node:parent(), node:parent():start(), node:parent():type())
if nodes_set[start] == nil then
nodes_set[start] = { node = node, type = match or '' }
end
end)
end
if loc.reference then -- for go
ts_locals.recurse_local_nodes(loc.reference, function(def, node, full_match, match)
local row, col, start = node:start()
local p1, p1t = '', ''
local p2, p2t = '', ''
local p3, p3t = '', ''
if node:parent() and node:parent():parent() then
p1 = node:parent()
p1t = node:parent():type()
p2 = node:parent():parent()
p2t = node:parent():parent():type()
end
if p2 and p2:parent() then
p3 = p2:parent()
p3t = p2:parent():type()
end
trace(row, col, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, p2t, p3, p3t)
if p1t == 'arrow_function' then
row, col, start = p1:start()
trace('arrow_function 1', row, col)
nodes_set[start] = { node = p1, type = p1t }
end
if p2t == 'arrow_function' then
row, col, start = p2:start()
trace('arrow_function 2', row, col)
nodes_set[start] = { node = p2, type = p2t }
end
if nodes_set[start] == nil then
if -- qualified_type : e.g. io.Reader inside interface
node:parent()
and node:parent():parent()
and node:type() == 'type_identifier'
and node:parent():type() == 'qualified_type'
and string.find(node:parent():parent():type(), 'interface')
then
log('add node', node)
nodes_set[start] = { node = node, type = match or 'field' }
end
end
end)
end
end
@ -149,14 +312,12 @@ local function prepare_node(node, kind)
end
local function get_scope(type, source)
local sbl, sbc, sel, sec = source:range()
local current = source
local result = current
local next = ts_utils.get_next_node(source)
local parent = current:parent()
trace(source:type(), source:range(), parent)
if type == 'method' or type == 'function' and parent ~= nil then
if type == 'method' or type:find('function') and parent ~= nil then
trace(parent:type(), parent:range())
-- a function name
if parent:type() == 'function_name' then
@ -169,7 +330,7 @@ local function get_scope(type, source)
-- for C++
local n = source
for i = 1, 4, 1 do
for _ = 1, 4, 1 do
if n == nil or n:parent() == nil then
break
end
@ -195,7 +356,7 @@ local function get_scope(type, source)
-- M.fun1 = function() end
-- lets work up and see next node, lua
local n = source
for i = 1, 4, 1 do
for _ = 1, 4, 1 do
if n == nil or n:parent() == nil then
break
end
@ -280,7 +441,8 @@ local function get_all_nodes(bufnr, filter, summary)
local result = lru:get(hash)
if result ~= nil and result.ftime == ftime then
log('get data from cache')
trace('get data from cache', ftime, result)
return result.nodes, result.length
end
@ -290,11 +452,16 @@ local function get_all_nodes(bufnr, filter, summary)
trace(bufnr, filter, summary)
if not bufnr then
vim.notify('get_all_node invalide bufnr', vim.lsp.log_levels.WARN)
vim.notify('get_all_node invalid bufnr', vim.lsp.log_levels.WARN)
end
summary = summary or false
local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype')
if not parsers.has_parser() then
vim.notify('ts not loaded', vim.lsp.log_levels.WARN)
if not require('navigator.lspclient.clients').ft_disabled(ft) then
-- vim.notify('ts not loaded ' .. ft, vim.lsp.log_levels.Debug)
log('ts not loaded ' .. ft)
end
return {}
end
local path_sep = require('navigator.util').path_sep()
@ -302,17 +469,14 @@ local function get_all_nodes(bufnr, filter, summary)
local display_filename = fname:gsub(cwd .. path_sep, path_cur, 1)
local all_nodes = {}
-- Support completion-nvim customized label map
local customized_labels = vim.g.completion_customize_lsp_label or {}
-- Force some types to act like they are parents
-- instead of neighbors of the next nodes.
local containers = {
local containers = filter or {
['function'] = true,
['local_function'] = true,
['arrow_function'] = true,
['type'] = true,
['class'] = true,
['call_expression'] = true,
-- ['var'] = true,
['struct'] = true,
['method'] = true,
}
@ -328,17 +492,31 @@ local function get_all_nodes(bufnr, filter, summary)
-- Step 2 find correct completions
local length = 10
local parents = {} -- stack of nodes a clever algorithm from treesiter refactor @Santos Gallegos
local loaded_symbol = {}
for _, def in ipairs(get_definitions(bufnr)) do
local n = #parents
for i = 1, n do
local index = n + 1 - i
local parent_def = parents[index]
-- trace(parent_def.type, parent_def.node:type(), vim.treesitter.get_node_text(parent_def.node, bufnr))
-- trace(def.node:type(), vim.treesitter.get_node_text(def.node, bufnr))
if
ts_utils.is_parent(parent_def.node, def.node)
or (containers[parent_def.type] and ts_utils.is_parent(parent_def.node:parent(), def.node))
or (
containers[parent_def.type]
and (
ts_utils.is_parent(parent_def.node:parent(), def.node)
or (
parent_def.node:parent():type():find('dot_index')
and ts_utils.is_parent(parent_def.node:parent():parent(), def.node)
)
)
)
then
-- trace('is parent', i, index)
break
else
-- trace('leave node', i, index)
parents[index] = nil
end
end
@ -351,15 +529,24 @@ local function get_all_nodes(bufnr, filter, summary)
item.type = node.type
if filter ~= nil and not filter[item.type] then
trace(item.type, item.kind)
trace('skipped', item.type, item.kind)
goto continue
end
if item.type == 'associated' then
trace('skipped', item.type, item.kind)
goto continue
end
local tsdata = node.def
if node.def == nil then
trace('skipped', item.type, item.kind)
goto continue
end
item.node_text = vim.treesitter.get_node_text(tsdata, bufnr)
local text = vim.treesitter.get_node_text(tsdata, bufnr) or ''
text = vim.split(text, '\n')[1] or ''
item.node_text = text
log(item.node_text)
local scope, is_func
if summary then
@ -367,23 +554,44 @@ local function get_all_nodes(bufnr, filter, summary)
else
scope, is_func = get_smallest_context(tsdata)
end
log(item, scope, is_func)
if is_func then
-- hack for lua and maybe other language aswell
local parent = tsdata:parent()
if parent ~= nil and parent:type() == 'function_name' or parent:type() == 'function_name_field' then
if parent ~= nil and _NgConfigValues.debug == 'trace' then -- for github action failure
trace(parent:type(), vim.treesitter.get_node_text(parent, bufnr):sub(1, 30), item.node_text, item.type)
end
if
parent ~= nil
and (
parent:type() == 'function_name'
-- or parent:type() == 'function'
-- or parent:type() == 'function_declaration' -- this bring in too much info
or parent:type() == 'method_name'
or parent:type() == 'function_name_field'
)
then
-- replace function name
item.node_text = vim.treesitter.get_node_text(parent, bufnr)
local cut = item.node_text:find('[\n\r]')
if cut then
item.node_text = item.node_text:sub(1, cut - 1)
end
log(parent:type(), item.node_text)
end
end
trace(item.node_text, item.kind, item.type)
if scope ~= nil then
-- it is strange..
if not is_func and summary then
trace('skipped', item.node_text, item.type)
goto continue
end
item.node_scope = ts_utils.node_to_lsp_range(scope)
end
if item.node_text and vim.trim(item.node_text) == '_' then
goto continue
end
if summary then
if item.node_scope ~= nil then
table.insert(all_nodes, item)
@ -395,7 +603,6 @@ local function get_all_nodes(bufnr, filter, summary)
tsdata:type(),
item.node_text,
item.kind,
item.node_text,
'range',
item.node_scope.start.line,
item.node_scope['end'].line
@ -406,10 +613,9 @@ local function get_all_nodes(bufnr, filter, summary)
item.range = ts_utils.node_to_lsp_range(tsdata)
local start_line_node, _, _ = tsdata:start()
if item.node_text == '_' then
goto continue
end
item.full_text = vim.trim(api.nvim_buf_get_lines(bufnr, start_line_node, start_line_node + 1, false)[1] or '')
local line_text = api.nvim_buf_get_lines(bufnr, start_line_node, start_line_node + 1, false)[1] or ''
item.full_text = vim.trim(line_text)
item.full_text = item.full_text:gsub('%s*[%[%(%{]*%s*$', '')
item.uri = uri
@ -423,12 +629,39 @@ local function get_all_nodes(bufnr, filter, summary)
if #parents > 1 then
indent = string.rep(' ', #parents - 1) .. ''
end
item.indent = indent
item.indent_level = #parents -- maybe use real indent level ?
if item.indent_level <= 1 then
local sp = string.match(line_text, '(%s*)')
log(line_text, #sp)
if sp then
local indent_level = #sp / (vim.o.shiftwidth or 4) + 1
item.indent_level = math.max(item.indent_level, indent_level)
end
end
if #parents > 0 then
log(parents[1].type, vim.treesitter.get_node_text(parents[1].node, bufnr))
if parents[2] then
log(parents[2].type, vim.treesitter.get_node_text(parents[2].node, bufnr))
end
else
log('root node')
end
if #all_nodes >= 1 then
all_nodes[#all_nodes].next_indent_level = #parents
end
item.text = string.format(' %s %s%-10s\t %s', item.kind, indent, item.node_text, item.full_text)
if #item.text > length then
length = #item.text
end
table.insert(all_nodes, item)
if
loaded_symbol[item.node_text .. item.kind] == nil
or not util.range_inside(loaded_symbol[item.node_text .. item.kind], item.node_scope)
then
table.insert(all_nodes, item)
loaded_symbol[item.node_text .. item.kind] = item.node_scope
end
::continue::
end
end
@ -442,8 +675,12 @@ local function get_all_nodes(bufnr, filter, summary)
end
function M.buf_func(bufnr)
local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype')
if vim.api.nvim_buf_get_option(bufnr, 'buftype') == 'nofile' then
return
end
if not ok or ts_locals == nil then
error('treesitter not loaded')
error('treesitter not loaded: ' .. ft)
return
end
@ -451,6 +688,7 @@ function M.buf_func(bufnr)
local all_nodes, width = get_all_nodes(bufnr, {
['function'] = true,
['arrow_function'] = true,
['var'] = true,
['method'] = true,
['class'] = true,
@ -484,28 +722,55 @@ function M.buf_func(bufnr)
return false
end)
end
log(all_nodes)
return all_nodes, width
end
function M.buf_ts()
function M.all_ts_nodes(bufnr)
if ts_locals == nil then
error('treesitter not loaded')
return
end
local bufnr = api.nvim_get_current_buf()
bufnr = bufnr or api.nvim_get_current_buf()
local all_nodes, width = get_all_nodes(bufnr)
return all_nodes, width
end
function M.side_panel()
Panel = require('guihua.panel')
local bufnr = api.nvim_get_current_buf()
local panel = Panel:new({
header = 'treesitter',
render = function(b)
local ft = vim.api.nvim_buf_get_option(b, 'buftype')
log('render for ', bufnr, b)
if ft == 'nofile' or ft == 'guihua' then
b = bufnr
end
return require('navigator.treesitter').all_ts_nodes(b)
end,
scope = 'node_scope'
})
panel:open(true)
end
function M.buf_ts()
local all_nodes, width = M.all_ts_nodes()
local bufnr = api.nvim_get_current_buf()
local ft = vim.api.nvim_buf_get_option(bufnr, 'ft')
gui.new_list_view({
local listview = gui.new_list_view({
items = all_nodes,
prompt = true,
ft = ft,
rawdata = true,
height = 0.62,
preview_height = 0.12,
width = width + 10,
api = _NgConfigValues.icons.treesitter_defult,
})
return listview, all_nodes, width
end
M.get_all_nodes = get_all_nodes
@ -540,6 +805,8 @@ function M.bufs_ts()
items = ts_opened,
prompt = true,
ft = ft,
height = 0.62,
preview_height = 0.12,
width = max_length + 10,
api = _NgConfigValues.icons.treesitter_defult,
})

@ -6,6 +6,8 @@ local M = { log_path = vim.lsp.get_log_path() }
local guihua = require('guihua.util')
local nvim_0_6_1
local nvim_0_8
local vfn = vim.fn
local api = vim.api
M.path_sep = function()
local is_win = vim.loop.os_uname().sysname:find('Windows')
@ -42,10 +44,10 @@ function M.get_data_from_file(filename, startLine)
end
local uri = 'file:///' .. filename
local bufnr = vim.uri_to_bufnr(uri)
if not vim.api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
if not api.nvim_buf_is_loaded(bufnr) then
vfn.bufload(bufnr)
end
local data = vim.api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false)
local data = api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false)
if data == nil or vim.tbl_isempty(data) then
startLine = nil
else
@ -59,6 +61,29 @@ function M.get_data_from_file(filename, startLine)
return { data = data, line = displayLine }
end
function M.io_read(filename)
local f = io.open(filename, 'r')
if f == nil then
return nil
end
local content = f:read('*a') -- *a or *all reads the whole file
f:close()
return content
end
function M.rm_file(filename)
return os.remove(filename)
end
function M.file_exists(name)
local f = io.open(name, 'r')
if f ~= nil then
io.close(f)
return true
end
return false
end
M.merge = function(t1, t2)
for k, v in pairs(t2) do
t1[k] = v
@ -77,9 +102,9 @@ M.map = function(modes, key, result, options)
for i = 1, #modes do
if buffer then
vim.api.nvim_buf_set_keymap(0, modes[i], key, result, options)
api.nvim_buf_set_keymap(0, modes[i], key, result, options)
else
vim.api.nvim_set_keymap(modes[i], key, result, options)
api.nvim_set_keymap(modes[i], key, result, options)
end
end
end
@ -114,7 +139,13 @@ end
function M.get_relative_path(base_path, my_path)
local base_data = getDir(base_path)
if base_data == nil then
return
end
local my_data = getDir(my_path)
if my_data == nil then
return
end
local base_len = #base_data
local my_len = #my_data
@ -141,24 +172,46 @@ function M.get_relative_path(base_path, my_path)
return data
end
local level = 'error'
if _NgConfigValues.debug == true then
level = 'info'
elseif _NgConfigValues.debug == 'trace' then
level = 'trace'
M.log = function(...)
return { ... }
end
M.info = function(...)
return { ... }
end
local default_config = { use_console = false, use_file = true, level = level }
if _NgConfigValues.debug_console_output then
default_config.use_console = true
default_config.use_file = false
M.trace = function(...)
return { ... }
end
M.warn = function(...)
return { ... }
end
M.error = function(...)
print(...)
end
M._log = require('guihua.log').new(default_config, true)
-- add log to you lsp.log
M.log = M._log.info
M.info = M._log.info
M.trace = M._log.trace
M.error = M._log.error
local level = 'error'
function M.setup()
if _NgConfigValues.debug == true then
level = 'info'
elseif _NgConfigValues.debug == 'trace' then
level = 'trace'
end
local default_config = { use_console = false, use_file = true, level = level }
if _NgConfigValues.debug_console_output then
default_config.use_console = true
default_config.use_file = false
end
M._log = require('guihua.log').new(default_config, true)
if _NgConfigValues.debug then
-- add log to you lsp.log
M.trace = M._log.trace
M.info = M._log.info
M.warn = M._log.warn
M.error = M._log.error
M.log = M.info
end
end
function M.fmt(...)
M._log.fmt_info(...)
@ -252,7 +305,7 @@ function M.split2(s, sep)
sep = sep or ' '
local pattern = string.format('([^%s]+)', sep)
string.gsub(s, pattern, function(c)
_ = string.gsub(s, pattern, function(c)
fields[#fields + 1] = c
end)
@ -279,18 +332,18 @@ function M.trim_and_pad(txt)
end
M.open_file = function(filename)
vim.api.nvim_command(string.format('e! %s', filename))
api.nvim_command(string.format('e! %s', filename))
end
M.open_file_at = guihua.open_file_at
function M.exists(var)
for k, _ in pairs(_G) do
if k == var then
return true
end
end
end
-- function M.exists(var)
-- for k, _ in pairs(_G) do
-- if k == var then
-- return true
-- end
-- end
-- end
local exclude_ft = { 'scrollbar', 'help', 'NvimTree' }
function M.exclude(fname)
@ -306,7 +359,6 @@ end
-- name space search
local nss
local api = vim.api
local bufs
function M.set_virt_eol(bufnr, lnum, chunks, priority, id)
@ -348,7 +400,7 @@ function M.nvim_0_6_1()
if nvim_0_6_1 ~= nil then
return nvim_0_6_1
end
nvim_0_6_1 = vim.fn.has('nvim-0.6.1') == 1
nvim_0_6_1 = vfn.has('nvim-0.6.1') == 1
if nvim_0_6_1 == false then
M.warn('Please use navigator 0.3 version for neovim version < 0.6.1')
end
@ -359,7 +411,7 @@ function M.nvim_0_8()
if nvim_0_8 ~= nil then
return nvim_0_8
end
nvim_0_8 = vim.fn.has('nvim-0.8') == 1
nvim_0_8 = vfn.has('nvim-0.8') == 1
if nvim_0_8 == false then
M.log('Please use navigator 0.4 version for neovim version < 0.8')
end
@ -373,9 +425,27 @@ function M.mk_handler(fn)
end
function M.partial(func, arg)
return (M.mk_handler(function(...)
return function(...)
return func(arg, ...)
end))
end
end
function M.partial2(func, arg1, arg2)
return function(...)
return func(arg1, arg2, ...)
end
end
function M.partial3(func, arg1, arg2, arg3)
return function(...)
return func(arg1, arg2, arg3, ...)
end
end
function M.partial4(func, arg1, arg2, arg3, arg4)
return function(...)
return func(arg1, arg2, arg3, arg4, ...)
end
end
function M.empty(t)
@ -421,4 +491,82 @@ function M.info(msg)
vim.notify('INF: ' .. msg, vim.lsp.log_levels.INFO)
end
function M.dedup(locations)
local m = 10
if m > #locations then
m = #locations
end
local dict = {}
local del = {}
for i = 1, m, 1 do
local value = locations[i]
local range = value.range or value.originSelectionRange or value.targetRange
if not range then
break
end
local key = (value.uri or range.uri or value.targetUri or '')
.. ':'
.. tostring(range.start.line)
.. ':'
.. tostring(range.start.character)
.. ':'
.. tostring(range['end'].line)
.. ':'
.. tostring(range['end'].character)
if dict[key] == nil then
dict[key] = i
else
local j = dict[key]
if not locations[j].definition then
table.insert(del, i)
else
table.insert(del, j)
end
end
end
table.sort(del)
for i = #del, 1, -1 do
M.log('remove ', del[i])
table.remove(locations, del[i])
end
return locations
end
function M.range_inside(outer, inner)
if outer == nil or inner == nil then
return false
end
if outer.start == nil or outer['end'] == nil or inner.start == nil or inner['end'] == nil then
return false
end
return outer.start.line <= inner.start.line and outer['end'].line >= inner['end'].line
end
function M.dirname(pathname)
local path_sep = require('navigator.util').path_sep()
local strip_dir_pat = path_sep .. '([^' .. path_sep .. ']+)$'
local strip_sep_pat = path_sep .. '$'
if not pathname or #pathname == 0 then
return
end
local result = pathname:gsub(strip_sep_pat, ''):gsub(strip_dir_pat, '')
if #result == 0 then
return '/'
end
return result
end
function M.sub_match(str)
local _, j = string.gsub(str, [["]], '')
if j % 2 == 1 then
str = str .. '"'
end
_, j = string.gsub(str, [[']], '')
if j % 2 == 1 then
str = str .. [[']]
end
str = str .. ''
return str
end
return M

@ -1,12 +1,15 @@
-- https://github.com/lukas-reineke/dotfiles/blob/master/vim/lua/lsp/rename.lua
local M = {}
local util = require('navigator.util')
-- local rename_prompt = 'Rename -> '
local gutil = require('guihua.util')
local lsphelper = require('navigator.lspwrapper')
local symbols_to_items = lsphelper.symbols_to_items
local vfn = vim.fn
M.add_workspace_folder = function()
util.log(vim.ui.input)
local input = require('guihua.floating').input
input({prompt = 'Workspace To Add: ', default = vim.fn.expand('%:p:h')}, function(inputs)
input({ prompt = 'Workspace To Add: ', default = vfn.expand('%:p:h') }, function(inputs)
vim.lsp.buf.add_workspace_folder(inputs)
end)
end
@ -16,7 +19,7 @@ M.remove_workspace_folder = function()
local folders = vim.lsp.buf.list_workspace_folders()
if #folders > 1 then
select(folders, {prompt = 'select workspace to delete'}, function(workspace)
return select(folders, { prompt = 'select workspace to delete' }, function(workspace)
vim.lsp.buf.remove_workspace_folder(workspace)
end)
end
@ -24,13 +27,68 @@ end
M.workspace_symbol = function()
local input = require('guihua.floating').input
input({prompt = 'Find symbol: ', default = ''}, function(inputs)
input({ prompt = 'Search symbol: ', default = '' }, function(inputs)
util.log(inputs)
print(inputs)
vim.lsp.buf.workspace_symbol(inputs)
end)
end
function M.workspace_symbol_live()
local height = _NgConfigValues.height or 0.4
height = math.floor(height * vfn.winheight('%'))
local width = _NgConfigValues.width or 0.7
width = math.floor(vim.api.nvim_get_option('columns') * width)
local bufnr = vim.api.nvim_get_current_buf()
local ft = vim.o.ft
local data = { { text = 'input the symbol name to start fuzzy search' } }
for _ = 1, height do
table.insert(data, { text = '' })
end
local ListView = require('guihua.listview')
local opt = {
api = '',
bg = 'GuihuaListDark',
data = data,
items = data,
enter = true,
ft = ft,
loc = 'top_center',
transparency = 50,
prompt = true,
on_confirm = function(item)
vim.defer_fn(function()
if item and item.name then
require('navigator.symbols').workspace_symbols(item.name)
end
end, 10)
end,
on_input_filter = function(text)
local params = { query = text or '#' }
local results = vim.lsp.buf_request_sync(bufnr, 'workspace/symbol', params)
local result
for _, r in pairs(results) do
-- util.log(r)
if r.result then
result = r.result
break
end
end
if not result then
result = {}
end
local items = symbols_to_items(result)
items = gutil.dedup(items, 'name', 'kind')
return items
end,
rect = { height = height, pos_x = 0, pos_y = 0, width = width },
}
local win = ListView:new(opt)
win:on_draw({})
-- require('guihua.gui').new_list_view(opt)
end
M.list_workspace_folders = function()
local folders = vim.lsp.buf.list_workspace_folders()
if #folders > 0 then
@ -38,8 +96,7 @@ M.list_workspace_folders = function()
items = folders,
border = 'single',
rawdata = true,
on_move = function(...)
end
on_move = function() end,
})
end
end

@ -41,12 +41,23 @@ local function load_plugins()
use({ 'ray-x/lsp_signature.nvim' })
use({ 'ray-x/aurora' })
use({
'ray-x/navigator.lua',
-- '~/github/navigator.lua',
-- 'ray-x/navigator.lua',
'~/github/ray-x/navigator.lua',
requires = { 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
config = function()
require('navigator').setup({
lsp_signature_help = true,
debug = true,
keymaps = {
{ key = 'gK', func = vim.lsp.buf.definition, doc = 'definition' },
{
key = '<leader>ld',
func = require('navigator.diagnostics').show_buf_diagnostics,
desc = 'show_buf_diagnostics',
},
},
icons = {
diagnostic_virtual_text = '',
},
})
end,
})

@ -16,34 +16,7 @@ local function load_plugins()
'williamboman/nvim-lsp-installer',
config = function()
local lsp_installer = require('nvim-lsp-installer')
local coq = require('coq')
local enhance_server_opts = {
['sumneko_lua'] = function(options)
options.settings = {
Lua = {
diagnostics = {
globals = { 'vim' },
},
},
}
end,
['tsserver'] = function(options)
options.on_attach = function(client)
client.resolved_capabilities.document_formatting = false
end
end,
}
lsp_installer.on_server_ready(function(server)
local options = {}
if enhance_server_opts[server.name] then
enhance_server_opts[server.name](options)
end
server:setup(coq.lsp_ensure_capabilities(options))
end)
lsp_installer.setup{}
end,
})
use({

@ -0,0 +1,79 @@
vim.cmd([[set runtimepath=$VIMRUNTIME]])
vim.cmd([[set packpath=/tmp/nvim/site]])
local package_root = '/tmp/nvim/site/pack'
local install_path = package_root .. '/packer/start/packer.nvim'
local function load_plugins()
require('packer').startup({
function(use)
use('wbthomason/packer.nvim')
use('neovim/nvim-lspconfig')
use({
'williamboman/nvim-lsp-installer',
config = function()
require('nvim-lsp-installer').setup({})
end,
})
use({
'ray-x/navigator.lua',
-- '~/github/ray-x/navigator.lua',
config = function()
require('navigator').setup({
debug = true,
lsp_installer = true,
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
})
end,
})
use('ray-x/guihua.lua')
use({
'hrsh7th/nvim-cmp',
requires = {
'hrsh7th/cmp-nvim-lsp',
},
config = function()
local cmp = require('cmp')
cmp.setup({
mapping = {
['<CR>'] = cmp.mapping.confirm({ select = true }),
['<Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.confirm({ select = true })
else
fallback()
end
end, { 'i', 's' }),
},
sources = {
{ name = 'nvim_lsp' },
},
})
end,
})
use('ray-x/aurora')
end,
config = {
package_root = package_root,
compile_path = install_path .. '/plugin/packer_compiled.lua',
},
})
-- navigator/LSP setup
end
if vim.fn.isdirectory(install_path) == 0 then
print('install packer')
vim.fn.system({
'git',
'clone',
'https://github.com/wbthomason/packer.nvim',
install_path,
})
load_plugins()
require('packer').sync()
vim.cmd('colorscheme aurora')
else
load_plugins()
vim.cmd('colorscheme aurora')
end

@ -1 +1,6 @@
std="vim"
std="lua52+vim"
[rules]
global_usage = "allow"
multiple_statements = "allow"
unused_variable = "allow"

@ -0,0 +1,69 @@
local busted = require('plenary/busted')
local eq = assert.are.same
local cur_dir = vim.fn.expand('%:p:h')
-- local status = require("plenary.reload").reload_module("go.nvim")
-- status = require("plenary.reload").reload_module("nvim-treesitter")
-- local ulog = require('go.utils').log
describe('should run lsp call hierarchy', function()
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local status = require('plenary.reload').reload_module('navigator')
status = require('plenary.reload').reload_module('guihua')
status = require('plenary.reload').reload_module('lspconfig')
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr('')
require('navigator').setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
border = 'none',
})
-- allow gopls start
for _ = 1, 20 do
vim.wait(400, function() end)
local found = false
for _, client in ipairs(vim.lsp.get_active_clients()) do
if client.name == 'gopls' then
found = true
break
end
end
if found then
break
end
end
it('should show panel', function()
vim.fn.setpos('.', { bufn, 24, 15, 0 })
require('navigator.hierarchy').incoming_calls_panel()
vim.wait(300, function() end)
local panel = require('guihua.panel').debug()
eq(panel.name, 'Panel')
vim.wait(500, function() end)
panel = require('guihua.panel').debug()
print(vim.inspect(panel))
-- eq(
-- panel.activePanel.sections[1].header[1],
-- '──────────Call Hierarchy──────────'
-- )
-- eq(panel.activePanel.sections[1].nodes[1].name, 'measure')
end)
it('should not crash and show hierarchy', function()
vim.fn.setpos('.', { bufn, 24, 15, 0 })
local ret = require('navigator.hierarchy')._call_hierarchy()
vim.wait(400, function() end)
eq(ret, ret) -- make sure doesn't crash the result
end)
end)

@ -44,83 +44,59 @@ describe('should run lsp reference', function()
uri = 'file://' .. cur_dir .. '/tests/fixtures/interface_test.go',
},
}
it('should show references', function()
local status = require('plenary.reload').reload_module('navigator')
local status = require('plenary.reload').reload_module('guihua')
local status = require('plenary.reload').reload_module('lspconfig')
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr('')
-- require'lspconfig'.gopls.setup {}
require('navigator').setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = { code_action_icon = 'A ' },
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
border = 'none',
})
-- allow gopls start
for i = 1, 10 do
vim.wait(400, function() end)
local clients = vim.lsp.get_active_clients()
print('lsp clients: ', #clients)
if #clients > 0 then
local status = require('plenary.reload').reload_module('navigator')
status = require('plenary.reload').reload_module('guihua')
status = require('plenary.reload').reload_module('lspconfig')
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr('')
-- require'lspconfig'.gopls.setup {}
require('navigator').setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = { code_action_icon = 'A ' },
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
border = 'none',
})
if vim.fn.has('nvim-0.7') then
_NgConfigValues.treesitter_analysis = true
else
_NgConfigValues.treesitter_analysis = false
end
-- allow gopls start
for _ = 1, 20 do
vim.wait(400, function() end)
local found = false
for _, client in ipairs(vim.lsp.get_active_clients()) do
if client.name == 'gopls' then
found = true
break
end
end
if found then
break
end
end
it('should show references', function()
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
vim.bo.filetype = 'go'
-- vim.lsp.buf.references()
vim.lsp.buf.references()
eq(1, 1)
end)
it('reference handler should return items', function()
local status = require('plenary.reload').reload_module('navigator')
local status = require('plenary.reload').reload_module('guihua')
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
print(path)
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
-- vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr('')
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
vim.bo.filetype = 'go'
require('navigator').setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = { code_action_icon = 'A ' },
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
debug_console_output = true,
border = 'none',
})
_NgConfigValues.debug_console_output = true
vim.bo.filetype = 'go'
-- allow gopls start
for i = 1, 10 do
vim.wait(400, function() end)
local clients = vim.lsp.get_active_clients()
print('clients ', #clients)
if #clients > 0 then
break
end
end
-- allow gopls start
vim.wait(200, function() end)
@ -136,53 +112,15 @@ describe('should run lsp reference', function()
win, items, width = require('navigator.reference').reference_handler(nil, 'textDocument/references', result, 1, 1)
end
print('win', vim.inspect(win))
-- print('win', vim.inspect(win))
print('items', vim.inspect(items))
eq(win.ctrl.data[1].display_filename, './interface.go')
eq(win.ctrl.data[1].display_filename, './tests/fixtures/interface.go')
eq(win.ctrl.data[2].range.start.line, 14)
eq(items[1].display_filename, './interface.go')
eq(items[1].display_filename, './tests/fixtures/interface.go')
-- eq(width, 60)
end)
it('reference handler should return items with thread', function()
local status = require('plenary.reload').reload_module('navigator')
local status = require('plenary.reload').reload_module('guihua')
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
print(path)
local cmd = "silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr('')
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
vim.bo.filetype = 'go'
require('navigator').setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = { code_action_icon = 'A ' },
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
debug_console_output = true,
border = 'none',
})
_NgConfigValues.debug_console_output = true
vim.bo.filetype = 'go'
-- allow gopls start
for i = 1, 10 do
vim.wait(400, function() end)
local clients = vim.lsp.get_active_clients()
print('clients ', #clients)
if #clients > 0 then
break
end
end
-- allow gopls start
vim.wait(200, function() end)
local win, items, width
@ -196,11 +134,10 @@ describe('should run lsp reference', function()
else
win, items, width = require('navigator.reference').reference_handler(nil, 'textDocument/references', result, 1, 1)
end
print('win', vim.inspect(win))
-- print('win', vim.inspect(win))
print('items', vim.inspect(items))
-- eq(win.ctrl.data, "./interface.go")
eq(win.ctrl.data[1].display_filename, './interface.go')
eq(win.ctrl.data[1].display_filename, './tests/fixtures/interface.go')
eq(win.ctrl.data[2].range.start.line, 14)
-- eq(items[1].display_filename, "./interface.go")

@ -0,0 +1,217 @@
local golden_result = {
{
col = 9,
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
full_text = 'package main',
kind = '🚀',
lnum = 1,
node_scope = {
['end'] = {
character = 0,
line = 12,
},
start = {
character = 0,
line = 0,
},
},
node_text = 'main',
indent = '',
range = {
['end'] = {
character = 12,
line = 0,
},
start = {
character = 8,
line = 0,
},
},
text = ' 🚀 main \t package main',
type = 'namespace',
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
},
{
col = 6,
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
full_text = 'func interfaceTest()',
kind = '',
lnum = 5,
indent = '',
node_scope = {
['end'] = {
character = 1,
line = 11,
},
start = {
character = 0,
line = 4,
},
},
node_text = 'interfaceTest',
range = {
['end'] = {
character = 18,
line = 4,
},
start = {
character = 5,
line = 4,
},
},
text = '  interfaceTest\t func interfaceTest()',
type = 'function',
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
},
{
col = 2,
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
full_text = 'r := rect{width: 3, height: 4}',
kind = '',
lnum = 6,
node_scope = {
['end'] = {
character = 1,
line = 11,
},
start = {
character = 21,
line = 4,
},
},
indent = ' ',
node_text = 'r',
range = {
['end'] = {
character = 2,
line = 5,
},
start = {
character = 1,
line = 5,
},
},
text = '   r \t r := rect{width: 3, height: 4}',
type = 'var',
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
},
{
col = 2,
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
full_text = 'c := circle{radius: 5}',
kind = '',
lnum = 7,
node_scope = {
['end'] = {
character = 1,
line = 11,
},
start = {
character = 21,
line = 4,
},
},
node_text = 'c',
indent = ' ',
range = {
['end'] = {
character = 2,
line = 6,
},
start = {
character = 1,
line = 6,
},
},
text = '   c \t c := circle{radius: 5}',
type = 'var',
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
},
{
col = 2,
display_filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
filename = '/tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
full_text = 'd := circle{radius: 10}',
kind = '',
lnum = 10,
indent = ' ',
node_scope = {
['end'] = {
character = 1,
line = 11,
},
start = {
character = 21,
line = 4,
},
},
node_text = 'd',
range = {
['end'] = {
character = 2,
line = 9,
},
start = {
character = 1,
line = 9,
},
},
text = '   d \t d := circle{radius: 10}',
type = 'var',
uri = 'file:///tmp/github/ray-x/navigator.lua/tests/fixtures/interface_test.go',
},
}
print(golden_result[1].node_text)
local busted = require('plenary/busted')
local eq = assert.are.same
local cur_dir = vim.fn.expand('%:p:h')
-- local status = require("plenary.reload").reload_module("go.nvim")
-- status = require("plenary.reload").reload_module("nvim-treesitter")
-- local ulog = require('go.utils').log
describe('should run lsp reference', function()
-- vim.fn.readfile('minimal.vim')
it('should show ts nodes', function()
local status = require('plenary.reload').reload_module('navigator')
local status = require('plenary.reload').reload_module('guihua')
local status = require('plenary.reload').reload_module('lspconfig')
vim.cmd([[packadd nvim-lspconfig]])
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. '/tests/fixtures/interface_test.go' -- %:p:h ? %:p
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr('')
-- require'lspconfig'.gopls.setup {}
require('navigator').setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
})
-- allow gopls start
for i = 1, 10 do
vim.wait(400, function() end)
local clients = vim.lsp.get_active_clients()
print('lsp clients: ', #clients)
if #clients > 0 then
break
end
end
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
vim.bo.filetype = 'go'
local view, items, w = require('navigator.treesitter').buf_ts()
eq(items[1].node_text, golden_result[1].node_text)
eq(items[2].node_text, golden_result[2].node_text)
end)
end)

@ -1,5 +1,5 @@
[selene]
base = "lua51"
base = "lua52"
name = "vim"
[vim]
@ -8,9 +8,11 @@ any = true
[_G]
property = true
writable = "new-fields"
[_NgConfigValues]
property = true
writable = "new-fields"
any = true
# property = true
# writable = "full-write"
[debug]
property = true

@ -0,0 +1,47 @@
---
base: lua52
name: vim
globals:
_G:
property: new-fields
_NgConfigValues:
any: true
after_each:
args:
- type: function
assert.equals:
args:
- type: any
- type: any
- required: false
type: any
assert.is_not:
any: true
assert.same:
args:
- type: any
- type: any
assert.spy:
args:
- type: any
assert.stub:
args:
- type: any
assert.truthy:
args:
- type: any
before_each:
args:
- type: function
debug:
property: read-only
describe:
args:
- type: string
- type: function
it:
args:
- type: string
- type: function
vim:
any: true
Loading…
Cancel
Save