Compare commits

...

78 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

@ -15,11 +15,11 @@ jobs:
manager: sudo snap manager: sudo snap
packages: go packages: go
- os: ubuntu-22.04 - os: ubuntu-22.04
url: https://github.com/neovim/neovim/releases/download/v0.7.2/nvim-linux64.tar.gz url: https://github.com/neovim/neovim/releases/download/v0.7.0/nvim-linux64.tar.gz
manager: sudo snap manager: sudo snap
packages: go packages: go
- os: ubuntu-22.04 - 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 manager: sudo snap
packages: go packages: go
steps: steps:

4
.gitignore vendored

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

@ -72,11 +72,11 @@ variable is:
- Async request with lsp.buf_request for reference search - 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 - 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 - Preview definination/references
@ -96,7 +96,7 @@ variable is:
- ccls call hierarchy (Non-standard `ccls/call` API) supports - ccls call hierarchy (Non-standard `ccls/call` API) supports
- Syntax folding based on treesitter or LSP_fold folding algorithm. (It behaves similar to vs-code); comment folding - 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 - Treesitter symbols sidebar, LSP document symbole sidebar. Both with preview and folding
@ -257,12 +257,14 @@ require'navigator'.setup({
-- end, -- end,
-- The attach code will apply to all LSP clients -- The attach code will apply to all LSP clients
default_mapping = true, -- set to false if you will remap every key ts_fold = false, -- modified version of treesitter folding
keymaps = {{key = "gK", func = "declaration()"}}, -- a list of key maps 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 -- this kepmap gK will override "gD" mapping function declaration() in default kepmap
-- please check mapping.lua for all keymaps -- please check mapping.lua for all keymaps
treesitter_analysis = true, -- treesitter variable context treesitter_analysis = true, -- treesitter variable context
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis 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 -- 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 transparency = 50, -- 0 ~ 100 blur the main window, 100: fully transparent, 0: opaque, set to nil or 100 to disable it
@ -271,24 +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 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 = { icons = {
-- Code action -- Code action
code_action_icon = "🏏", code_action_icon = "🏏", -- note: need terminal support, for those not support unicode, might crash
-- Diagnostics -- Diagnostics
diagnostic_head = '🐛', diagnostic_head = '🐛',
diagnostic_head_severity_1 = "🈲", diagnostic_head_severity_1 = "🈲",
-- refer to lua/navigator.lua for more icons setups -- 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 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 = { lsp = {
enable = true, -- skip lsp setup if disabled make sure add require('navigator.lspclient.mapping').setup() in you enable = true, -- skip lsp setup if disabled make sure add require('navigator.lspclient.mapping').setup() in you
-- own on_attach -- own on_attach
code_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true}, 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}, 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_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 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 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 -- 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 {} -- Default {}
diagnostic = { diagnostic = {
underline = true, underline = true,
@ -308,9 +316,9 @@ require'navigator'.setup({
}, },
ctags ={ ctags ={
cmd = 'ctags', cmd = 'ctags',
tagfile = 'tags' tagfile = 'tags',
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number' options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
} },
gopls = { -- gopls setting gopls = { -- gopls setting
on_attach = function(client, bufnr) -- on_attach for gopls on_attach = function(client, bufnr) -- on_attach for gopls
-- your special on attach here -- your special on attach here
@ -322,6 +330,18 @@ require'navigator'.setup({
gopls = {gofumpt = false} -- disable gofumpt etc, 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_lua = {
sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server", 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", sumneko_binary = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server/bin/macOS/lua-language-server",
@ -429,7 +449,7 @@ In `playground` folder, there is a `init.lua` and source code for you to play wi
| n | gd | definition | | n | gd | definition |
| n | g0 | document symbol | | n | g0 | document symbol |
| n | \<C-]\> | go to definition (if multiple show listview) | | 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 | \<C-LeftMouse\> | definition |
| n | g\<LeftMouse\> | implementation | | n | g\<LeftMouse\> | implementation |
| n | \<Leader>gt | treesitter document symbol | | n | \<Leader>gt | treesitter document symbol |
@ -470,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 | \<Enter\> | open preview file in nvim/Apply action |
| n | \<ESC\> | close listview of floating window | | n | \<ESC\> | close listview of floating window |
| i/n | \<C-e\> | 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-b\> | previous page in listview |
| i/n | \<C-f\> | next page in listview | | i/n | \<C-f\> | next page in listview |
| i/n | \<C-s\> | save the modification to preview window to file | | i/n | \<C-s\> | save the modification to preview window to file |
### Colors/Highlight: ### 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. e.g.
```vim ```vim
hi default GHTextViewDark guifg=#e0d8f4 guibg=#332e55 hi default GuihuaTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GHListDark guifg=#e0d8f4 guibg=#103234 hi default GuihuaListDark guifg=#e0d8f4 guibg=#103234
hi default GHListHl guifg=#e0d8f4 guibg=#404254 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, There are other Lsp highlight been used in this plugin, e.g LspReferenceRead/Text/Write are used for document highlight,
@ -501,18 +522,18 @@ 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). 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 ```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}` In the config. Also please setup the lsp server from installer setup with `server:setup{opts}`
example: lsp-installer example:
```lua ```lua
use({ use({
'williamboman/nvim-lsp-installer', 'williamboman/nvim-lsp-installer',
@ -525,14 +546,79 @@ example:
'ray-x/navigator.lua', 'ray-x/navigator.lua',
config = function() config = function()
require('navigator').setup({ require('navigator').setup({
debug = true,
lsp_installer = true, lsp_installer = true,
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
}) })
end, 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) Please refer to [lsp_installer_config](https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
for more info for more info
@ -548,7 +634,9 @@ To start LSP installed by lsp_installer, please use following setups
require'navigator'.setup({ require'navigator'.setup({
-- lsp_installer = false -- default value is false -- lsp_installer = false -- default value is false
lsp = { 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'} }
} }
}) })
@ -563,6 +651,7 @@ require'navigator'.setup({
lsp = { lsp = {
tsserver = { tsserver = {
cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" } 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"}
} }
} }
} }
@ -604,22 +693,27 @@ Here is an example [init_lsp_installer.lua](https://github.com/ray-x/navigator.l
### Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension) ### Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension)
There are lots of plugins provides lsp support 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. * 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
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 Here is an example to setup rust with rust-tools
```lua ```lua
require'navigator'.setup({ require'navigator'.setup({
lsp = { lsp = {
disable_lsp = { "rust_analyzer", "clangd" }, -- will not run rust_analyzer setup from navigator 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({ require('rust-tools').setup({
server = { server = {
on_attach = function(client, bufnr) on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here, 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 -- otherwise, you can define your own commands to call navigator functions
end, end,
} }
@ -629,6 +723,8 @@ require("clangd_extensions").setup {
server = { server = {
on_attach = function(client, bufnr) on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here, 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 -- otherwise, you can define your own commands to call navigator functions
end, end,
} }
@ -664,7 +760,7 @@ Highlight I am using:
- LspReferenceRead, LspReferenceText and LspReferenceWrite are used for `autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()` - 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. 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 (Normal) and PmenuSel
- In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat - In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat
@ -681,6 +777,7 @@ You can override the above highlight to fit your current colorscheme
| LspRestart | reload lsp | | LspRestart | reload lsp |
| LspToggleFmt | toggle lsp format | | LspToggleFmt | toggle lsp format |
| LspSymbols | document symbol in side panel | | LspSymbols | document symbol in side panel |
| NRefPanel | show symbol reference in side panel |
| TSymobls | treesitter symbol in side panel | | TSymobls | treesitter symbol in side panel |
| Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) | | Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) |
@ -820,11 +917,14 @@ Codelens for C++/ccls. Symbol reference
### VS-code style folding with treesitter ### VS-code style folding with treesitter
Folding is using a hacked version of treesitter folding. (option: ts_fold)
#### folding function #### folding function
![image](https://user-images.githubusercontent.com/1681295/148491596-6cd6c507-c157-4536-b8c4-dc969436763a.png) ![image](https://user-images.githubusercontent.com/1681295/148491596-6cd6c507-c157-4536-b8c4-dc969436763a.png)
#### folding comments #### 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) ![image](https://user-images.githubusercontent.com/1681295/148491845-5ffb18ea-f05d-4229-aec3-aa635b3de814.png)

@ -477,13 +477,13 @@ DEFAULT KEYMAPS *navigator-default_keymap
COLORS/HIGHLIGHT: *navigator-colors/highlight:* 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. e.g.
> >
hi default GHTextViewDark guifg=#e0d8f4 guibg=#332e55 hi default GuihuaTextViewDark guifg=#e0d8f4 guibg=#332e55
hi default GHListDark guifg=#e0d8f4 guibg=#103234 hi default GuihuaListDark guifg=#e0d8f4 guibg=#103234
hi default GHListHl guifg=#e0d8f4 guibg=#404254 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, There are other Lsp highlight been used in this plugin, e.g LspReferenceRead/Text/Write are used for document highlight,
@ -644,7 +644,7 @@ Highlight I am using:
* LspReferenceRead, LspReferenceText and LspReferenceWrite are used for `autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()` * 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. 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 (Normal) and PmenuSel
* In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat * In future, I will use NormalFloat for floating view. But ATM, most of colorscheme does not define NormalFloat
@ -660,8 +660,9 @@ COMMANDS *navigator-command
| Nctags {args} | show ctags symbols, args: -g regen ctags | | Nctags {args} | show ctags symbols, args: -g regen ctags |
| LspRestart | reload lsp | | LspRestart | reload lsp |
| LspSymbols | document symbol in side panel | | LspSymbols | document symbol in side panel |
| NRefPanel |symbol reference in side panel |
| TSymobls | treesitter symbol in side panel | | TSymobls | treesitter symbol in side panel |
| CallTree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) | | Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) |
:LspToggleFmt *:LspToggleFmt* :LspToggleFmt *:LspToggleFmt*
Toggle lsp auto format. Toggle lsp auto format.
@ -683,6 +684,9 @@ COMMANDS *navigator-command
:TSSymbols *:TSSymbols* :TSSymbols *:TSSymbols*
Treesitter symbol in side panel. Treesitter symbol in side panel.
:NRefPanel *:NRefPanel*
Symbol reference in side panel.
:Calltree [flags] *:Calltree* :Calltree [flags] *:Calltree*
Lsp call hierarchy call tree. Lsp call hierarchy call tree.
[flags]: [flags]:

@ -1,11 +1,14 @@
local M = {} local M = {}
local api = vim.api
local function warn(msg) local function warn(msg)
vim.api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {}) api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {})
end end
local function info(msg) local function info(msg)
vim.api.nvim_echo({ { 'Info: ' .. msg } }, true, {}) if _NgConfigValues.debug then
api.nvim_echo({ { 'Info: ' .. msg } }, true, {})
end
end end
_NgConfigValues = { _NgConfigValues = {
@ -16,7 +19,7 @@ _NgConfigValues = {
preview_lines = 40, -- total lines in preview screen preview_lines = 40, -- total lines in preview screen
preview_lines_before = 5, -- lines before the highlight line preview_lines_before = 5, -- lines before the highlight line
default_mapping = true, 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 external = nil, -- true: enable for goneovim multigrid otherwise false
border = 'single', -- border style, can be one of 'none', 'single', 'double', "shadow" border = 'single', -- border style, can be one of 'none', 'single', 'double', "shadow"
@ -29,11 +32,16 @@ _NgConfigValues = {
ts_fold = false, ts_fold = false,
treesitter_analysis = true, -- treesitter variable context treesitter_analysis = true, -- treesitter variable context
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis 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 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 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 -- 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 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' }, ctags = {
cmd = 'ctags',
tagfile = '.tags',
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number',
},
lsp = { lsp = {
enable = true, -- if disabled make sure add require('navigator.lspclient.mapping').setup() in you on_attach enable = true, -- if disabled make sure add require('navigator.lspclient.mapping').setup() in you on_attach
code_action = { code_action = {
@ -43,6 +51,7 @@ _NgConfigValues = {
virtual_text = true, virtual_text = true,
virtual_text_icon = true, virtual_text_icon = true,
}, },
document_highlight = true, -- highlight reference a symbol
code_lens_action = { code_lens_action = {
enable = true, enable = true,
sign = true, sign = true,
@ -57,6 +66,7 @@ _NgConfigValues = {
severity_sort = { reverse = true }, 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_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_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_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 disable_lsp = {}, -- a list of lsp server disabled for your project, e.g. denols and tsserver you may
@ -71,6 +81,10 @@ _NgConfigValues = {
-- filetypes = {'typescript'} -- disable javascript etc, -- filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetype -- 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_lua = {
-- sumneko_root_path = sumneko_root_path, -- sumneko_root_path = sumneko_root_path,
-- sumneko_binary = sumneko_binary, -- sumneko_binary = sumneko_binary,
@ -79,6 +93,7 @@ _NgConfigValues = {
servers = {}, -- you can add additional lsp server so navigator will load the default for you 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 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 = {
icons = true, -- set to false to use system default ( if you using a terminal does not have nerd/icon) icons = true, -- set to false to use system default ( if you using a terminal does not have nerd/icon)
-- Code action -- Code action
@ -157,6 +172,8 @@ local extend_config = function(opts)
if opts.debug then if opts.debug then
_NgConfigValues.debug = opts.debug _NgConfigValues.debug = opts.debug
end end
-- enable logs
require('navigator.util').setup()
for key, value in pairs(opts) do for key, value in pairs(opts) do
if _NgConfigValues[key] == nil then if _NgConfigValues[key] == nil then
warn( warn(
@ -199,12 +216,12 @@ local extend_config = function(opts)
else else
if _NgConfigValues[key][k] == nil then if _NgConfigValues[key][k] == nil then
if key == 'lsp' 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 if not vim.tbl_contains(lsp or {}, k) and k ~= 'efm' and k ~= 'null-ls' then
info(string.format('[] extend LSP support for %s %s ', key, k)) info(string.format('[] extend LSP support for %s %s ', key, k))
end end
elseif key == 'keymaps' then elseif key == 'keymaps' then
info('keymap override') info('keymap override' .. vim.inspect(v))
-- skip key check and allow mapping to handle that -- skip key check and allow mapping to handle that
else else
warn(string.format('[] Key %s %s not valid', key, k)) warn(string.format('[] Key %s %s not valid', key, k))
@ -234,7 +251,14 @@ M.setup = function(cfg)
cfg = cfg or {} cfg = cfg or {}
extend_config(cfg) 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.lazyloader').init()
require('navigator.lspclient.clients').setup(_NgConfigValues) require('navigator.lspclient.clients').setup(_NgConfigValues)
@ -244,7 +268,8 @@ M.setup = function(cfg)
require('navigator.implementation') require('navigator.implementation')
cfg.lsp = cfg.lsp or _NgConfigValues.lsp cfg.lsp = cfg.lsp or _NgConfigValues.lsp
if cfg.lsp.enable then
if _NgConfigValues.lsp.enable then
require('navigator.diagnostics').config(cfg.lsp.diagnostic) require('navigator.diagnostics').config(cfg.lsp.diagnostic)
end end
if not _NgConfigValues.loaded then if not _NgConfigValues.loaded then
@ -261,7 +286,6 @@ M.setup = function(cfg)
local _start_client = vim.lsp.start_client local _start_client = vim.lsp.start_client
vim.lsp.start_client = function(lsp_config) vim.lsp.start_client = function(lsp_config)
-- add highlight for Lspxxx -- add highlight for Lspxxx
require('navigator.dochighlight').documentHighlight()
require('navigator.lspclient.highlight').add_highlight() require('navigator.lspclient.highlight').add_highlight()
require('navigator.lspclient.highlight').diagnositc_config_sign() require('navigator.lspclient.highlight').diagnositc_config_sign()
-- require('navigator.lspclient.mapping').setup() -- require('navigator.lspclient.mapping').setup()

@ -152,9 +152,13 @@ local code_action_req = function(_call_back_fn, diagnostics)
end end
local function sort_select(action_tuples, opts, on_user_choice) local function sort_select(action_tuples, opts, on_user_choice)
-- table.sort(action_tuples, function(a, b) if action_tuples ~= nil and action_tuples[1][2] ~= nil and action_tuples[1][2].command then
-- return a[1] > b[1] table.sort(action_tuples, function(a, b)
-- end) return a[1] > b[1]
end)
end
trace(action_tuples)
require('guihua.gui').select(action_tuples, opts, on_user_choice) require('guihua.gui').select(action_tuples, opts, on_user_choice)
end end
@ -162,8 +166,6 @@ code_action.code_action = function()
local original_select = vim.ui.select local original_select = vim.ui.select
vim.ui.select = sort_select vim.ui.select = sort_select
log('codeaction')
vim.lsp.buf.code_action() vim.lsp.buf.code_action()
vim.defer_fn(function() vim.defer_fn(function()
vim.ui.select = original_select vim.ui.select = original_select
@ -186,17 +188,19 @@ code_action.range_code_action = function(startpos, endpos)
local original_input = vim.ui.input local original_input = vim.ui.input
vim.ui.input = require('guihua.input').input vim.ui.input = require('guihua.input').input
vim.lsp.buf.range_code_action(context, startpos, endpos)
vim.defer_fn(function()
vim.ui.select = original_select
end, 1000)
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.defer_fn(function()
vim.ui.select = original_select
vim.ui.input = original_input vim.ui.input = original_input
end, 1000) end, 1000)
end end
code_action.code_action_prompt = function() code_action.code_action_prompt = function(bufnr)
if special_buffers[vim.bo.filetype] then if special_buffers[vim.bo.filetype] then
log('skip buffer', vim.bo.filetype) log('skip buffer', vim.bo.filetype)
return return

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

@ -89,7 +89,7 @@ local function ctags_symbols()
local height = _NgConfigValues.height or 0.4 local height = _NgConfigValues.height or 0.4
local width = _NgConfigValues.width or 0.7 local width = _NgConfigValues.width or 0.7
height = math.floor(height * vfn.winheight('%')) height = math.floor(height * vfn.winheight('%'))
width = math.floor(width * vfn.winwidth('%')) width = math.floor(vim.api.nvim_get_option('columns') * width)
local items = {} local items = {}
local ctags_file = _NgConfigValues.ctags.tagfile local ctags_file = _NgConfigValues.ctags.tagfile
if not util.file_exists(ctags_file) then if not util.file_exists(ctags_file) then
@ -118,7 +118,7 @@ local function ctags_symbols()
local opt = { local opt = {
api = '', api = '',
ft = ft, ft = ft,
bg = 'GHListDark', bg = 'GuihuaListDark',
data = result, data = result,
items = result, items = result,
enter = true, enter = true,

@ -3,6 +3,7 @@ local lsphelper = require('navigator.lspwrapper')
local locations_to_items = lsphelper.locations_to_items local locations_to_items = lsphelper.locations_to_items
local gui = require('navigator.gui') local gui = require('navigator.gui')
local log = util.log local log = util.log
local trace = util.trace
local TextView = require('guihua.textview') local TextView = require('guihua.textview')
-- callback for lsp definition, implementation and declaration handler -- callback for lsp definition, implementation and declaration handler
local definition_hdlr = function(err, locations, ctx, _) local definition_hdlr = function(err, locations, ctx, _)
@ -21,6 +22,10 @@ local definition_hdlr = function(err, locations, ctx, _)
end end
local oe = require('navigator.util').encoding(ctx.client_id) 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 vim.tbl_islist(locations) then
if #locations > 1 then if #locations > 1 then
local items = locations_to_items(locations) local items = locations_to_items(locations)
@ -69,7 +74,7 @@ local function def_preview(timeout_ms)
local row = range.start.line local row = range.start.line
-- in case there are comments -- in case there are comments
row = math.max(row - 3, 1) 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 local uri = data[1].uri or data[1].targetUri
if not uri then if not uri then
return return
@ -80,7 +85,12 @@ local function def_preview(timeout_ms)
end end
local ok, parsers = pcall(require, 'nvim-treesitter.parsers') 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 if ok then
local ts = require('navigator.treesitter') local ts = require('navigator.treesitter')
local root = parsers.get_parser(bufnr) local root = parsers.get_parser(bufnr)
@ -92,10 +102,10 @@ local function def_preview(timeout_ms)
local sr, _, er, _ = ts.get_node_scope(def_node) local sr, _, er, _ = ts.get_node_scope(def_node)
log(sr, er) 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 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 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) 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 for _ = 1, math.min(3, #definition), 1 do
@ -107,7 +117,8 @@ local function def_preview(timeout_ms)
end end
end end
local width = 40 local width = 40
local maxwidth = math.floor(vim.fn.winwidth(0) * 4 / 5)
local maxwidth = math.floor( vim.api.nvim_get_option('columns') * 0.8)
for _, value in pairs(definition) do for _, value in pairs(definition) do
-- log(key, value, width) -- log(key, value, width)
width = math.max(width, #value + 4) width = math.max(width, #value + 4)
@ -121,7 +132,7 @@ local function def_preview(timeout_ms)
relative = 'cursor', relative = 'cursor',
style = 'minimal', style = 'minimal',
ft = filetype, ft = filetype,
rect = { width = width, height = #definition + 3, pos_y = 2 }, rect = { width = width, height = math.min(#definition + 3, 16), pos_y = 2 }, -- TODO: 16 hardcoded
data = definition, data = definition,
enter = true, enter = true,
border = _NgConfigValues.border or 'shadow', border = _NgConfigValues.border or 'shadow',

@ -2,7 +2,6 @@ local gui = require('navigator.gui')
local diagnostic_list = {} local diagnostic_list = {}
local diagnostic = vim.diagnostic or vim.lsp.diagnostic local diagnostic = vim.diagnostic or vim.lsp.diagnostic
-- local hide = diagnostic.hide or diagnostic.clear -- 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 util = require('navigator.util')
local log = util.log local log = util.log
local trace = require('guihua.log').trace local trace = require('guihua.log').trace
@ -11,6 +10,8 @@ local error = util.error
local path_sep = require('navigator.util').path_sep() local path_sep = require('navigator.util').path_sep()
local path_cur = require('navigator.util').path_cur() local path_cur = require('navigator.util').path_cur()
local empty = util.empty 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 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') 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 end
local diagnostic_cfg = { 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 function get_count(bufnr, level) local function get_count(bufnr, level)
if vim.diagnostic ~= nil then if vim.diagnostic ~= nil then
@ -74,15 +58,18 @@ local function error_marker(result, ctx, config)
if bufnr == nil then if bufnr == nil then
bufnr = vim.uri_to_bufnr(result.uri) bufnr = vim.uri_to_bufnr(result.uri)
end 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) local uri = vim.uri_from_fname(fname)
if uri ~= result.uri then if uri ~= result.uri then
log('not same buf', ctx, result.uri, bufnr, vim.fn.bufnr()) log('not same buf', ctx, result.uri, bufnr, vim.fn.bufnr())
return return
end end
if not vim.api.nvim_buf_is_loaded(bufnr) then if not api.nvim_buf_is_loaded(bufnr) then
log('buf not loaded', bufnr) trace('buf not loaded', bufnr)
return return
end end
@ -93,7 +80,7 @@ local function error_marker(result, ctx, config)
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]]) local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then
log('great no errors') 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 end
return return
end end
@ -101,12 +88,12 @@ local function error_marker(result, ctx, config)
-- total line num of current buffer -- total line num of current buffer
-- local winid = vim.fn.win_getid(vim.fn.winnr()) -- local winid = vim.fn.win_getid(vim.fn.winnr())
-- local winid = vim.api.nvim_get_current_win() -- local winid = api.nvim_get_current_win()
local total_num = vim.api.nvim_buf_line_count(bufnr) local total_num = api.nvim_buf_line_count(bufnr)
-- local total_num = vim.fn.getbufinfo(vim.fn.winbufnr(winid))[1].linecount -- local total_num = vim.fn.getbufinfo(vim.fn.winbufnr(winid))[1].linecount
-- window size of current buffer -- 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 wwidth = stats.width;
local wheight = stats.height local wheight = stats.height
@ -114,7 +101,7 @@ local function error_marker(result, ctx, config)
return return
end end
if _NG_VT_DIAG_NS == nil then 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 end
local pos = {} local pos = {}
@ -156,7 +143,7 @@ local function error_marker(result, ctx, config)
end end
if not vim.tbl_isempty(pos) then 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 end
for _, s in pairs(pos) do for _, s in pairs(pos) do
local hl = 'ErrorMsg' local hl = 'ErrorMsg'
@ -177,7 +164,7 @@ local function error_marker(result, ctx, config)
end end
trace('add pos', s, bufnr) trace('add pos', s, bufnr)
vim.api.nvim_buf_set_extmark( api.nvim_buf_set_extmark(
bufnr, bufnr,
_NG_VT_DIAG_NS, _NG_VT_DIAG_NS,
l, l,
@ -201,9 +188,9 @@ local diag_hdlr = function(err, result, ctx, config)
return return
end 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 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 end
local cwd = vim.loop.cwd() local cwd = vim.loop.cwd()
local ft = vim.bo.filetype local ft = vim.bo.filetype
@ -239,14 +226,18 @@ local diag_hdlr = function(err, result, ctx, config)
item.uri = uri item.uri = uri
-- trace(item) -- trace(item)
local head = _NgConfigValues.icons.diagnostic_head local head = _NgConfigValues.icons.diagnostic_head
if v.severity == 1 then if v.severity then
head = _NgConfigValues.icons.diagnostic_head_severity_1 if v.severity == 1 then
end head = _NgConfigValues.icons.diagnostic_head_severity_1
if v.severity == 2 then end
head = _NgConfigValues.icons.diagnostic_head_severity_2 if v.severity == 2 then
end head = _NgConfigValues.icons.diagnostic_head_severity_2
if v.severity > 2 then end
head = _NgConfigValues.icons.diagnostic_head_severity_3 if v.severity > 2 then
head = _NgConfigValues.icons.diagnostic_head_severity_3
end
else
v.severity = 2
end end
if v.relatedInformation and v.relatedInformation[1] then if v.relatedInformation and v.relatedInformation[1] then
local info = v.relatedInformation[1] local info = v.relatedInformation[1]
@ -259,7 +250,7 @@ local diag_hdlr = function(err, result, ctx, config)
end end
end end
local bufnr1 = vim.uri_to_bufnr(uri) 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 if _NgConfigValues.diagnostic_load_files then
-- print('load buffers') -- print('load buffers')
if not loaded then if not loaded then
@ -267,7 +258,7 @@ local diag_hdlr = function(err, result, ctx, config)
end end
local pos = v.range.start local pos = v.range.start
local row = pos.line 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 if line ~= nil then
item.text = head .. line .. _NgConfigValues.icons.diagnostic_head_description .. v.message item.text = head .. line .. _NgConfigValues.icons.diagnostic_head_description .. v.message
else else
@ -301,7 +292,7 @@ local diag_hdlr = function(err, result, ctx, config)
marker(result, ctx, config) marker(result, ctx, config)
else else
trace('great, no diag errors') 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 _NG_VT_DIAG_NS = nil
end end
end end
@ -312,24 +303,56 @@ end
-- end -- end
local M = {} local M = {}
function M.setup()
diagnostic_cfg.virtual_text = _NgConfigValues.lsp.diagnostic.virtual_text if diagnostic_cfg ~= nil and diagnostic_cfg.float ~= nil then
if type(_NgConfigValues.lsp.diagnostic.virtual_text) == 'table' then return
diagnostic_cfg.virtual_text.prefix = _NgConfigValues.icons.diagnostic_virtual_text 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 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 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) log(bufnr, _NG_VT_DIAG_NS)
if _NG_VT_DIAG_NS == nil then if _NG_VT_DIAG_NS == nil then
return return
end 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 _NG_VT_DIAG_NS = nil
end end
@ -371,15 +394,15 @@ M.show_buf_diagnostics = function()
end end
trace('new buffer', listview.bufnr) trace('new buffer', listview.bufnr)
if listview.bufnr then 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
end end
end end
-- set loc list win -- set loc list win
M.set_diag_loclist = function() M.set_diag_loclist = function(bufnr)
local bufnr = vim.api.nvim_get_current_buf() bufnr = bufnr or api.nvim_get_current_buf()
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]]) local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if diag_cnt == 0 then if diag_cnt == 0 then
log('great, no errors!') log('great, no errors!')
@ -399,7 +422,7 @@ M.set_diag_loclist = function()
if diagnostic.set_loclist then if diagnostic.set_loclist then
diagnostic.set_loclist(cfg) diagnostic.set_loclist(cfg)
else else
cfg.namespaces = diagnostic.get_namespace(nil) cfg.namespaces = diagnostic.get_namespaces()
diagnostic.setloclist(cfg) diagnostic.setloclist(cfg)
end end
else else
@ -415,7 +438,7 @@ function M.update_err_marker()
-- nothing to update -- nothing to update
return return
end end
local bufnr = vim.api.nvim_get_current_buf() local bufnr = api.nvim_get_current_buf()
local diag_cnt = get_count(bufnr, [[Error]]) local diag_cnt = get_count(bufnr, [[Error]])
+ get_count(bufnr, [[Warning]]) + get_count(bufnr, [[Warning]])
@ -424,12 +447,12 @@ function M.update_err_marker()
-- redraw -- redraw
if diag_cnt == 0 and _NG_VT_DIAG_NS ~= nil then 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') trace('no errors')
return return
end 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) local errors = diagnostic.get(bufnr)
if #errors == 0 then if #errors == 0 then
trace('no errors', errors) trace('no errors', errors)
@ -443,30 +466,40 @@ function M.update_err_marker()
marker(result, { bufnr = bufnr, method = 'textDocument/publishDiagnostics' }) marker(result, { bufnr = bufnr, method = 'textDocument/publishDiagnostics' })
end 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() function M.get_line_diagnostic()
local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1 local lnum = api.nvim_win_get_cursor(0)[1] - 1
return diagnostic.get(vim.api.nvim_get_current_buf(), { lnum = lnum }) 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 end
function M.show_diagnostics(pos) function M.show_diagnostics(pos)
local bufnr = vim.api.nvim_get_current_buf() local bufnr = api.nvim_get_current_buf()
local lnum = vim.api.nvim_win_get_cursor(0)[1] - 1
local opt = { border = 'single' } local lnum, col = unpack(api.nvim_win_get_cursor(0))
if diagnostic.open_float and type(diagnostic.open_float) == 'function' then 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 if pos == true then
opt.scope = 'cursor' opt.scope = 'cursor'
else else
opt.scope = 'line' opt.scope = 'line'
end end
diagnostic.open_float(bufnr, opt)
else
-- deprecated
diagnostic.show_line_diagnostics(opt, bufnr, lnum)
end 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 end
function M.treesitter_and_diag_panel() function M.treesitter_and_diag_panel()
@ -476,7 +509,7 @@ function M.treesitter_and_diag_panel()
local results = diagnostic_list[ft] local results = diagnostic_list[ft]
log(diagnostic_list, ft) log(diagnostic_list, ft)
local bufnr = vim.api.nvim_get_current_buf() local bufnr = api.nvim_get_current_buf()
local p = Panel:new({ local p = Panel:new({
header = 'treesitter', header = 'treesitter',
render = function(b) render = function(b)
@ -486,7 +519,8 @@ function M.treesitter_and_diag_panel()
}) })
p:add_section({ p:add_section({
header = 'diagnostic', header = 'diagnostic',
render = function(bufnr) render = function(buf)
log(buf, diagnostic)
if diagnostic_list[ft] ~= nil then if diagnostic_list[ft] ~= nil then
local display_items = {} local display_items = {}
for _, client_items in pairs(results) do for _, client_items in pairs(results) do
@ -507,7 +541,9 @@ function M.treesitter_and_diag_panel()
end end
function M.config(cfg) function M.config(cfg)
M.setup()
cfg = cfg or {} cfg = cfg or {}
log('diag config', cfg)
local default_cfg = { local default_cfg = {
underline = true, underline = true,
virtual_text = true, virtual_text = true,

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

@ -28,19 +28,14 @@ function M.on_attach()
end end
function M.setup_plugin() function M.setup_plugin()
api.nvim_command('augroup FoldingCommand') local cmd_group = api.nvim_create_augroup('NGFoldGroup', {})
api.nvim_command('autocmd! * <buffer>') api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost' }, {
api.nvim_command("autocmd BufEnter <buffer> lua require'navigator.foldlsp'.update_folds()") group = cmd_group,
api.nvim_command("autocmd BufWritePost <buffer> lua require'navigator.foldlsp'.update_folds()") pattern = '*',
api.nvim_command('augroup end') callback = function()
require('navigator.foldlsp').update_folds()
-- vim.cmd([[ end,
-- })
-- function! folding_nvim#foldexpr()
-- return luaeval(printf('require"navigator.foldlsp".get_fold_indic(%d)', v:lnum))
-- endfunction
--
-- ]])
local clients = vim.lsp.buf_get_clients(0) local clients = vim.lsp.buf_get_clients(0)

@ -21,7 +21,12 @@ function NG_custom_fold_text()
local line = vim.fn.getline(vim.v.foldstart) local line = vim.fn.getline(vim.v.foldstart)
local line_count = vim.v.foldend - vim.v.foldstart + 1 local line_count = vim.v.foldend - vim.v.foldstart + 1
-- log("" .. line .. " // " .. line_count .. " lines") -- 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 end
vim.opt.foldtext = NG_custom_fold_text() vim.opt.foldtext = NG_custom_fold_text()
@ -30,11 +35,6 @@ vim.opt.fillchars = { eob = '-', fold = ' ' }
vim.opt.viewoptions:remove('options') vim.opt.viewoptions:remove('options')
function M.setup_fold() 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('augroup FoldingCommand')
api.nvim_command('autocmd! * <buffer>') api.nvim_command('autocmd! * <buffer>')
api.nvim_command('augroup end') api.nvim_command('augroup end')
@ -43,10 +43,27 @@ function M.setup_fold()
vim.opt.viewoptions:remove('options') vim.opt.viewoptions:remove('options')
local current_window = api.nvim_get_current_win() 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, 'foldmethod', 'expr')
api.nvim_win_set_option(current_window, 'foldexpr', 'folding#ngfoldexpr()') api.nvim_win_set_option(current_window, 'foldexpr', 'folding#ngfoldexpr()')
end 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 -- This is cached on buf tick to avoid computing that multiple times
-- Especially not for every line in the file when `zx` is hit -- Especially not for every line in the file when `zx` is hit
local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr) local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
@ -102,27 +119,39 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
prev_stop = stop prev_stop = stop
end end
end end
trace(start_counts)
trace(stop_counts)
local levels = {} local levels = {}
local current_level = 0 local current_level = 0
-- We now have the list of fold opening and closing, fill the gaps and mark where fold start -- 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 for lnum = 0, api.nvim_buf_line_count(bufnr) do
local node, _ = get_node_at_line(lnum + 1) local node, _ = get_node_at_line(lnum + 1)
-- log(lnum, node:type())
local comment = node:type() == 'comment' 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) local last_trimmed_level = trim_level(current_level)
current_level = current_level + (start_counts[lnum] or 0) current_level = current_level + (start_counts[lnum] or 0)
local trimmed_level = trim_level(current_level) local trimmed_level = trim_level(current_level)
current_level = current_level - (stop_counts[lnum] or 0) local current_level2 = current_level - (stop_counts[lnum] or 0)
local next_trimmed_level = trim_level(current_level) 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 comment then
if lnum == 0 or levels[lnum] == tostring(trimmed_level) then trace('comment node', trimmed_level)
levels[lnum + 1] = '>' .. tostring(trimmed_level + 1) -- allow comment fold independtly -- if trimmed_level == 0 then
else -- trimmed_level = 1
levels[lnum + 1] = tostring(trimmed_level + 1) -- allow comment fold independtly -- 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 end
else else
-- Determine if it's the start/end of a fold -- Determine if it's the start/end of a fold
@ -133,28 +162,59 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
-- ( \n ( \n ) \n ( \n ) \n ) -- ( \n ( \n ) \n ( \n ) \n )
-- If it did have such a mechansim, (trimmed_level - last_trimmed_level) -- If it did have such a mechansim, (trimmed_level - last_trimmed_level)
-- would be the correct number of starts to pass on. -- would be the correct number of starts to pass on.
levels[lnum + 1] = tostring(trimmed_level)
if trimmed_level - last_trimmed_level > 0 then if trimmed_level - last_trimmed_level > 0 then
levels[lnum + 1] = tostring(trimmed_level) -- hack if levels[lnum + 1] ~= '>' .. tostring(trimmed_level) then
levels[lnum + 2] = '>' .. tostring(trimmed_level + 1) -- dirty hack levels[lnum + 1] = tostring(trimmed_level) -- hack do not fold current line as it is first in fold range
elseif trimmed_level - next_trimmed_level > 0 then 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 -- 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 -- the fold level changes by at least 2; we can uncomment this if
-- vim's behavior gets fixed. -- 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 end
levels[lnum + 1] = tostring(trimmed_level) -- levels[lnum + 1] = tostring(trimmed_level + 1)
-- else
current_level = current_level - 1
else else
-- if levels[lnum + 1] == nil then trace('same')
levels[lnum + 1] = tostring(trimmed_level + 1) if pre_node and pre_node:type() == 'comment' then
-- end 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 end
trace(levels)
end end
pre_node = node
end end
trace(levels) trace(levels)
return levels return levels
end) end)
@ -165,7 +225,7 @@ function M.get_fold_indic(lnum)
local buf = api.nvim_get_current_buf() local buf = api.nvim_get_current_buf()
local shown = false local shown = false
for i = 1, vim.fn.tabpagenr('$') do 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 if value == buf then
shown = true shown = true
end end
@ -176,7 +236,7 @@ function M.get_fold_indic(lnum)
end end
local levels = folds_levels(buf) or {} 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' return levels[lnum] or '0'
end end

@ -1,5 +1,6 @@
-- https://github.com/wention/dotfiles/blob/master/.config/nvim/lua/config/lsp.lua -- 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 -- https://github.com/lukas-reineke/dotfiles/blob/master/vim/lua/lsp/handlers.lua
return { return {
format_hdl = function(err, result, ctx, _) -- FIXME: bufnr is nil format_hdl = function(err, result, ctx, _) -- FIXME: bufnr is nil
if err ~= nil or result == nil then if err ~= nil or result == nil then
@ -31,4 +32,18 @@ return {
end end
end, 100) end, 100)
end, 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 M = {}
local ListView = require('guihua.listview') -- local ListView = require('guihua.listview')
local TextView = require('guihua.textview') -- local TextView = require('guihua.textview')
local util = require('navigator.util') local util = require('navigator.util')
local log = util.log local log = util.log
local trace = require('navigator.util').trace local trace = require('navigator.util').trace
@ -16,7 +16,7 @@ function M.new_list_view(opts)
local winnr = active_list_view.win local winnr = active_list_view.win
local bufnr = active_list_view.buf 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') log('list view already present')
return active_list_view return active_list_view
end end
@ -35,6 +35,14 @@ function M.new_list_view(opts)
opts.border = config.border or 'shadow' opts.border = config.border or 'shadow'
if vim.fn.hlID('TelescopePromptBorder') > 0 then if vim.fn.hlID('TelescopePromptBorder') > 0 then
opts.border_hl = 'TelescopePromptBorder' 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 end
if not items or vim.tbl_isempty(items) then if not items or vim.tbl_isempty(items) then
log('empty data return') log('empty data return')

@ -100,7 +100,7 @@ hierarchy_handler = function(dir, handler, show, api, err, result, ctx, cfg)
trace(dir, handler, api, show, err, result, ctx, cfg) trace(dir, handler, api, show, err, result, ctx, cfg)
ctx = ctx or {} -- can be nil if it is async call ctx = ctx or {} -- can be nil if it is async call
cfg = cfg or {} cfg = cfg or {}
opts = ctx.opts or {} local opts = ctx.opts or {}
vim.validate({ handler = { handler, 'function' }, show = { show, 'function' }, api = { api, 'string' } }) vim.validate({ handler = { handler, 'function' }, show = { show, 'function' }, api = { api, 'string' } })
local bufnr = ctx.bufnr or vim.api.nvim_get_current_buf() 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') assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp hierarchy')
@ -142,11 +142,12 @@ local function display_panel(args)
local Panel = require('guihua.panel') local Panel = require('guihua.panel')
local bufnr = args.bufnr or vim.api.nvim_get_current_buf() 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 ft = args.ft or vim.api.nvim_buf_get_option(bufnr, 'buftype')
local items = args.items local items = args.items
local p = Panel:new({ local p = Panel:new({
header = args.header or 'Call Hierarchy', header = args.header or 'Call Hierarchy',
render = function(bufnr) render = function(buf)
log(buf)
return items return items
end, end,
fold = function(panel, node) fold = function(panel, node)

@ -1,7 +1,6 @@
return { return {
init = function() init = function()
local loader = nil local loader = nil
local packer_plugins = packer_plugins or nil -- suppress warnings
local log = require('navigator.util').log local log = require('navigator.util').log
-- packer only -- packer only
if packer_plugins ~= nil then -- packer install if packer_plugins ~= nil then -- packer install
@ -51,7 +50,7 @@ return {
end, end,
load = function(plugin_name, path) load = function(plugin_name, path)
local loader = nil local loader = nil
local packer_plugins = packer_plugins or nil -- suppress warnings packer_plugins = packer_plugins or nil -- suppress warnings
-- packer only -- packer only
if packer_plugins ~= nil then -- packer install if packer_plugins ~= nil then -- packer install
local lazy_plugins = {} local lazy_plugins = {}

@ -4,7 +4,7 @@ local lsp = require('vim.lsp')
local util = require('navigator.util') local util = require('navigator.util')
local log = util.log local log = util.log
local trace = util.trace local trace = util.trace
_NG_Attached = {}
local M = {} local M = {}
M.on_attach = function(client, bufnr) M.on_attach = function(client, bufnr)
@ -23,6 +23,7 @@ M.on_attach = function(client, bufnr)
log('attaching: ', bufnr, client.name, uri) log('attaching: ', bufnr, client.name, uri)
trace(client) trace(client)
_NG_Attached[client.name] = true
-- add highlight for Lspxxx -- add highlight for Lspxxx
require('navigator.lspclient.highlight').add_highlight() require('navigator.lspclient.highlight').add_highlight()
@ -35,9 +36,16 @@ M.on_attach = function(client, bufnr)
}) })
if client.server_capabilities.documentHighlightProvider == true then if client.server_capabilities.documentHighlightProvider == true then
require('navigator.dochighlight').documentHighlight() 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 end
require('navigator.lspclient.lspkind').init() require('navigator.lspclient.lspkind').init()
local config = require('navigator').config_values() local config = require('navigator').config_values()
@ -62,9 +70,13 @@ M.on_attach = function(client, bufnr)
if _NgConfigValues.lsp.code_action.enable then if _NgConfigValues.lsp.code_action.enable then
if client.server_capabilities.codeActionProvider and client.name ~= 'null-ls' then if client.server_capabilities.codeActionProvider and client.name ~= 'null-ls' then
log('code action enabled for client', client.server_capabilities.codeActionProvider) log('code action enabled for client', client.server_capabilities.codeActionProvider)
api.nvim_command('augroup NCodeAction') api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {
vim.cmd([[autocmd CursorHold,CursorHoldI <buffer> lua require'navigator.codeAction'.code_action_prompt()]]) group = api.nvim_create_augroup('NGCodeActGroup_'..tostring(bufnr), {}),
api.nvim_command('augroup end') buffer = bufnr,
callback = function()
require('navigator.codeAction').code_action_prompt(bufnr)
end,
})
end end
end end
end end

@ -4,6 +4,7 @@ local log = ng_util.log
local trace = ng_util.trace local trace = ng_util.trace
local empty = ng_util.empty local empty = ng_util.empty
local warn = ng_util.warn local warn = ng_util.warn
local vfn = vim.fn
_NG_Loaded = {} _NG_Loaded = {}
_LoadedFiletypes = {} _LoadedFiletypes = {}
@ -41,6 +42,7 @@ local disabled_ft = {
'windline', 'windline',
'notify', 'notify',
'nofile', 'nofile',
'help',
'', '',
} }
-- local cap = vim.lsp.protocol.make_client_capabilities() -- local cap = vim.lsp.protocol.make_client_capabilities()
@ -63,322 +65,45 @@ local luadevcfg = {
} }
local luadev = {} 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') require('navigator.lazyloader').load('lua-dev.nvim', 'folke/lua-dev.nvim')
if _NgConfigValues.lsp_installer then if _NgConfigValues.lsp_installer then
require('navigator.lazyloader').load('nvim-lsp-installer', 'williamboman/nvim-lsp-installer') require('navigator.lazyloader').load('nvim-lsp-installer', 'williamboman/nvim-lsp-installer')
end end
local ok, l = pcall(require, 'lua-dev')
if ok and l then
luadev = l.setup(luadevcfg)
end
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 if _NgConfigValues.mason then
add('$VIMRUNTIME') require('navigator.lazyloader').load('mason.nvim', 'williamboman/mason.nvim')
require('navigator.lazyloader').load('mason-lspconfig.nvim', 'williamboman/mason-lspconfig.nvim')
-- 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
end 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, _)
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',
},
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 setups = require('navigator.lspclient.clients_default').defaults()
local servers = require('navigator.lspclient.servers')
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 lsp_installer_servers = {} local lsp_installer_servers = {}
local has_lspinst = false local has_lspinst = false
local has_mason = false
if config.lsp_installer == true then has_lspinst, _ = pcall(require, 'nvim-lsp-installer')
has_lspinst, _ = pcall(require, 'nvim-lsp-installer') if has_lspinst then
if has_lspinst then local srvs = require('nvim-lsp-installer.servers').get_installed_servers()
local srvs = require('nvim-lsp-installer.servers').get_installed_servers() if #srvs > 0 then
log('lsp_installered servers', srvs) lsp_installer_servers = srvs
if #srvs > 0 then end
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 end
log(lsp_installer_servers)
end end
log("lsp_installer:", lsp_installer_servers)
if config.lsp.disable_lsp == 'all' then if config.lsp.disable_lsp == 'all' then
config.lsp.disable_lsp = servers config.lsp.disable_lsp = servers
end end
@ -389,8 +114,8 @@ local ng_default_cfg = {
} }
-- check and load based on file type -- check and load based on file type
local function load_cfg(ft, client, cfg, loaded) local function load_cfg(ft, client, cfg, loaded, starting)
log(ft, client, loaded) log(ft, client, loaded, starting)
trace(cfg) trace(cfg)
if lspconfig[client] == nil then if lspconfig[client] == nil then
log('not supported by nvim', client) log('not supported by nvim', client)
@ -399,6 +124,7 @@ local function load_cfg(ft, client, cfg, loaded)
local lspft = lspconfig[client].document_config.default_config.filetypes local lspft = lspconfig[client].document_config.default_config.filetypes
local additional_ft = setups[client] and setups[client].filetypes or {} local additional_ft = setups[client] and setups[client].filetypes or {}
local bufnr = vim.api.nvim_get_current_buf()
local cmd = cfg.cmd local cmd = cfg.cmd
vim.list_extend(lspft, additional_ft) vim.list_extend(lspft, additional_ft)
@ -414,19 +140,46 @@ local function load_cfg(ft, client, cfg, loaded)
end end
trace('lsp for client', client, cfg) trace('lsp for client', client, cfg)
if cmd == nil or #cmd == 0 or vim.fn.executable(cmd[1]) == 0 then if cmd == nil or #cmd == 0 or vfn.executable(cmd[1]) == 0 then
log('lsp not installed for client', client, cmd) log('lsp not installed for client', client, cmd, "fallback")
return return
end end
if _NG_Loaded == nil then
return log('_NG_Loaded not set')
end
for k, c in pairs(loaded) do for k, c in pairs(loaded) do
if client == k then if client == k then
-- loaded -- loaded
log(client, 'already been loaded for', ft, loaded, c) 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 return
end end
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 if lspconfig[client] == nil then
error('client ' .. client .. ' not supported') error('client ' .. client .. ' not supported')
return return
@ -436,8 +189,27 @@ local function load_cfg(ft, client, cfg, loaded)
log('lspconfig setup') log('lspconfig setup')
-- log(lspconfig.available_servers()) -- log(lspconfig.available_servers())
-- force reload with config -- force reload with config
lspconfig[client].setup(cfg) -- lets have a guard here
log(client, 'loading for', ft) 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 end
-- need to verify the lsp server is up -- need to verify the lsp server is up
end end
@ -455,7 +227,7 @@ local function setup_fmt(client, enabled)
client.server_capabilities.documentFormattingProvider = false client.server_capabilities.documentFormattingProvider = false
else else
client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
or enabled or enabled
end end
end end
@ -481,7 +253,7 @@ end
local loaded = {} local loaded = {}
local function lsp_startup(ft, retry, user_lsp_opts) local function lsp_startup(ft, retry, user_lsp_opts)
retry = retry or false retry = retry or false
local path_sep = require('navigator.util').path_sep()
local capabilities = update_capabilities() local capabilities = update_capabilities()
for _, lspclient in ipairs(servers) do for _, lspclient in ipairs(servers) do
@ -551,7 +323,7 @@ local function lsp_startup(ft, retry, user_lsp_opts)
log(lspclient) log(lspclient)
-- if user provides override values -- if user provides override values
cfg.capabilities = capabilities -- cfg.capabilities = capabilities
log(lspclient, config.lsp.disable_format_cap) log(lspclient, config.lsp.disable_format_cap)
if vim.tbl_contains(config.lsp.disable_format_cap or {}, lspclient) then if vim.tbl_contains(config.lsp.disable_format_cap or {}, lspclient) then
log('fileformat disabled for ', lspclient) log('fileformat disabled for ', lspclient)
@ -635,16 +407,21 @@ local function lsp_startup(ft, retry, user_lsp_opts)
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 if installed and installer_cfg then
local paths = installer_cfg:get_default_options().cmd_env.PATH 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, ':') paths = vim.split(paths, ':')
if vim.fn.empty(cfg.cmd) == 1 then if vfn.empty(cfg.cmd) == 1 then
cfg.cmd = { installer_cfg.name } cfg.cmd = { installer_cfg.name }
end end
if vim.fn.executable(cfg.cmd[1]) == 0 then if vfn.executable(cfg.cmd[1]) == 0 then
for _, path in ipairs(paths) do for _, path in ipairs(paths) do
log(path) log(path)
if vim.fn.isdirectory(path) == 1 and string.find(path, installer_cfg.root_dir) then if vfn.isdirectory(path) == 1 and string.find(path, installer_cfg.root_dir) then
cfg.cmd[1] = path .. path_sep .. cfg.cmd[1] cfg.cmd[1] = path .. path_sep .. cfg.cmd[1]
log(cfg.cmd) log(cfg.cmd)
break break
@ -656,17 +433,49 @@ local function lsp_startup(ft, retry, user_lsp_opts)
end end
end 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) log('lsp server not installed in path ' .. lspclient .. vim.inspect(cfg.cmd), vim.lsp.log_levels.WARN)
end end
if _NG_Loaded[lspclient] then if _NG_Loaded[lspclient] then
log('client loaded ?', lspclient) log('client loaded ?', lspclient, _NG_Loaded[lspclient])
end
local starting = {}
if _NG_Loaded[lspclient] == true then
starting = { cnt = 1 }
end end
load_cfg(ft, lspclient, cfg, loaded)
_NG_Loaded[lspclient] = true load_cfg(ft, lspclient, cfg, loaded, starting)
-- load_cfg(ft, lspclient, {}, loaded) -- load_cfg(ft, lspclient, {}, loaded)
::continue:: ::continue::
end end
@ -740,7 +549,7 @@ local function setup(user_opts, cnt)
local bufnr = user_opts.bufnr or vim.api.nvim_get_current_buf() local bufnr = user_opts.bufnr or vim.api.nvim_get_current_buf()
if ft == '' or ft == nil then if ft == '' or ft == nil then
log('nil filetype, callback') log('nil filetype, callback')
local ext = vim.fn.expand('%:e') local ext = vfn.expand('%:e')
if ext ~= '' then if ext ~= '' then
cnt = cnt or 0 cnt = cnt or 0
local opts = vim.deepcopy(user_opts) local opts = vim.deepcopy(user_opts)
@ -820,7 +629,7 @@ local function setup(user_opts, cnt)
--- if code lens enabled --- if code lens enabled
if _NgConfigValues.lsp.code_lens_action.enable then if _NgConfigValues.lsp.code_lens_action.enable then
require('navigator.codelens').setup() require('navigator.codelens').setup(bufnr)
end end
-- _LoadedFiletypes[ft .. tostring(bufnr)] = true -- may prevent lsp config when reboot lsp -- _LoadedFiletypes[ft .. tostring(bufnr)] = true -- may prevent lsp config when reboot lsp
@ -835,23 +644,38 @@ local function on_filetype()
return return
end end
if uri == 'file://' or uri == 'file:///' then if uri == 'file://' or uri == 'file:///' then
log('skip loading for ft ', ft, uri) trace('skip loading for ft ', ft, uri)
return return
end 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) log(uri)
local wids = vim.fn.win_findbuf(bufnr) local wids = vfn.win_findbuf(bufnr)
if empty(wids) then if empty(wids) then
log('buf not shown return') log('buf not shown return')
end end
setup({ bufnr = bufnr }) setup({ bufnr = bufnr })
_NG_Loaded[bufnr] = 1
end end
return { return {
setup = setup, setup = setup,
get_cfg = get_cfg, get_cfg = get_cfg,
lsp = servers,
add_servers = add_servers, add_servers = add_servers,
on_filetype = on_filetype, on_filetype = on_filetype,
disabled_ft = disabled_ft, disabled_ft = disabled_ft,

@ -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,5 +1,3 @@
local lsp = require("vim.lsp")
local M = {} local M = {}
local capabilities = vim.lsp.protocol.make_client_capabilities() local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true capabilities.textDocument.completion.completionItem.snippetSupport = true

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

@ -1,12 +1,7 @@
local util = require('navigator.util') local util = require('navigator.util')
local log = util.log local log = util.log
local trace = util.trace local trace = util.trace
local event_hdlrs = { local api = vim.api
{ ev = 'BufWritePre', func = [[require "navigator.diagnostics".set_diag_loclist()]] },
{ ev = 'CursorHold', func = 'document_highlight()' },
{ ev = 'CursorHoldI', func = 'document_highlight()' },
{ ev = 'CursorMoved', func = 'clear_references()' },
}
if vim.lsp.buf.format == nil then if vim.lsp.buf.format == nil then
vim.lsp.buf.format = vim.lsp.buf.formatting vim.lsp.buf.format = vim.lsp.buf.formatting
@ -20,56 +15,60 @@ local single = { '╭', '─', '╮', '│', '╯', '─', '╰', '│' }
-- TODO https://github.com/neovim/neovim/pull/16591 use vimkeymap.set/del -- TODO https://github.com/neovim/neovim/pull/16591 use vimkeymap.set/del
-- LuaFormatter off -- LuaFormatter off
local key_maps = { local key_maps = {
{ key = 'gr', func = "require('navigator.reference').async_ref()" }, { key = 'gr', func = require('navigator.reference').async_ref, desc = 'async_ref' },
{ key = '<Leader>gr', func = "require('navigator.reference').reference()" }, -- reference deprecated { key = '<Leader>gr', func = require('navigator.reference').reference, desc = 'reference' }, -- reference deprecated
{ mode = 'i', key = '<M-k>', func = 'signature_help()' }, { mode = 'i', key = '<M-k>', func = vim.lsp.signature_help, desc = 'signature_help' },
{ key = '<c-k>', func = 'signature_help()' }, { key = '<c-k>', func = vim.lsp.buf.signature_help, desc = 'signature_help' },
{ key = 'g0', func = "require('navigator.symbols').document_symbols()" }, { key = 'g0', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' },
{ key = 'gW', func = "require('navigator.workspace').workspace_symbol_live()" }, { key = 'gW', func = require('navigator.workspace').workspace_symbol_live, desc = 'workspace_symbol_live' },
{ key = '<c-]>', func = "require('navigator.definition').definition()" }, { key = '<c-]>', func = require('navigator.definition').definition, desc = 'definition' },
{ key = 'gd', func = "require('navigator.definition').definition()" }, { key = 'gd', func = require('navigator.definition').definition, desc = 'definition' },
{ key = 'gD', func = "declaration({ border = 'rounded', max_width = 80 })" }, { key = 'gD', func = vim.lsp.buf.declaration, desc = 'declaration' },
{ key = 'gp', func = "require('navigator.definition').definition_preview()" }, { key = 'gp', func = require('navigator.definition').definition_preview, desc = 'definition_preview' },
{ key = '<Leader>gt', func = "require('navigator.treesitter').buf_ts()" }, { key = '<Leader>gt', func = require('navigator.treesitter').buf_ts, desc = 'buf_ts' },
{ key = '<Leader>gT', func = "require('navigator.treesitter').bufs_ts()" }, { key = '<Leader>gT', func = require('navigator.treesitter').bufs_ts, desc = 'bufs_ts' },
{ key = '<Leader>ct', func = "require('navigator.ctags').ctags()" }, { key = '<Leader>ct', func = require('navigator.ctags').ctags, desc = 'ctags' },
{ key = 'K', func = 'hover({ popup_opts = { border = single, max_width = 80 }})' }, { key = 'K', func = vim.lsp.buf.hover, desc = 'hover' },
{ key = '<Space>ca', mode = 'n', func = "require('navigator.codeAction').code_action()" }, { 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()" }, {
key = '<Space>ca',
mode = 'v',
func = require('navigator.codeAction').range_code_action,
desc = 'range_code_action',
},
-- { key = '<Leader>re', func = 'rename()' }, -- { key = '<Leader>re', func = 'rename()' },
{ key = '<Space>rn', func = "require('navigator.rename').rename()" }, { key = '<Space>rn', func = require('navigator.rename').rename, desc = 'rename' },
{ key = '<Leader>gi', func = 'incoming_calls()' }, { key = '<Leader>gi', func = vim.lsp.buf.incoming_calls, desc = 'incoming_calls' },
{ key = '<Leader>go', func = 'outgoing_calls()' }, { key = '<Leader>go', func = vim.lsp.buf.outgoing_calls, desc = 'outgoing_calls' },
{ key = 'gi', func = 'implementation()' }, { key = 'gi', func = vim.lsp.buf.implementation, desc = 'implementation' },
{ key = '<Space>D', func = 'type_definition()' }, { key = '<Space>D', func = vim.lsp.buf.type_definition, desc = 'type_definition' },
{ key = 'gL', func = "require('navigator.diagnostics').show_diagnostics()" }, { key = 'gL', func = require('navigator.diagnostics').show_diagnostics, desc = 'show_diagnostics' },
{ key = 'gG', func = "require('navigator.diagnostics').show_buf_diagnostics()" }, { key = 'gG', func = require('navigator.diagnostics').show_buf_diagnostics, desc = 'show_buf_diagnostics' },
{ key = '<Leader>dt', func = "require('navigator.diagnostics').toggle_diagnostics()" }, { key = '<Leader>dt', func = require('navigator.diagnostics').toggle_diagnostics, desc = 'toggle_diagnostics' },
{ key = ']d', func = "diagnostic.goto_next({ border = 'rounded', max_width = 80})" }, { key = ']d', func = vim.diagnostic.goto_next, desc = 'next diagnostics' },
{ key = '[d', func = "diagnostic.goto_prev({ border = 'rounded', max_width = 80})" }, { key = '[d', func = vim.diagnostic.goto_prev, desc = 'prev diagnostics' },
{ key = ']O', func = 'diagnostic.set_loclist()' }, { key = ']O', func = vim.diagnostic.set_loclist, desc = 'diagnostics set loclist' },
{ key = ']r', func = "require('navigator.treesitter').goto_next_usage()" }, { key = ']r', func = require('navigator.treesitter').goto_next_usage, desc = 'goto_next_usage' },
{ key = '[r', func = "require('navigator.treesitter').goto_previous_usage()" }, { key = '[r', func = require('navigator.treesitter').goto_previous_usage, desc = 'goto_previous_usage' },
{ key = '<C-LeftMouse>', func = 'definition()' }, { key = '<C-LeftMouse>', func = vim.lsp.buf.definition, desc = 'definition' },
{ key = 'g<LeftMouse>', func = 'implementation()' }, { key = 'g<LeftMouse>', func = vim.lsp.buf.implementation, desc = 'implementation' },
{ key = '<Leader>k', func = "require('navigator.dochighlight').hi_symbol()" }, { key = '<Leader>k', func = require('navigator.dochighlight').hi_symbol, desc = 'hi_symbol' },
{ key = '<Space>wa', func = "require('navigator.workspace').add_workspace_folder()" }, { key = '<Space>wa', func = require('navigator.workspace').add_workspace_folder, desc = 'add_workspace_folder' },
{ key = '<Space>wr', func = "require('navigator.workspace').remove_workspace_folder()" }, {
{ key = '<Space>ff', func = 'format({async = true})', mode = 'n' }, key = '<Space>wr',
{ key = '<Space>ff', func = 'range_formatting()', mode = 'v' }, func = require('navigator.workspace').remove_workspace_folder,
{ key = '<Space>wl', func = "require('navigator.workspace').list_workspace_folders()" }, desc = 'remove_workspace_folder',
{ key = '<Space>la', mode = 'n', func = "require('navigator.codelens').run_action()" }, },
} { 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' },
local commands = { {
[[command! -nargs=* Nctags lua require("navigator.ctags").ctags(<f-args>)]], key = '<Space>gm',
"command! -nargs=0 LspLog lua require'navigator.lspclient.config'.open_lsp_log()", func = require('navigator.formatting').range_format,
"command! -nargs=0 LspRestart lua require'navigator.lspclient.config'.reload_lsp()", mode = 'n',
"command! -nargs=0 LspToggleFmt lua require'navigator.lspclient.mapping'.toggle_lspformat()<CR>", desc = 'range format operator e.g gmip',
"command! -nargs=0 LspKeymaps lua require'navigator.lspclient.mapping'.get_keymaps_help()<CR>", },
"command! -nargs=0 LspSymbols lua require'navigator.symbols'.side_panel()<CR>", { key = '<Space>wl', func = require('navigator.workspace').list_workspace_folders, desc = 'list_workspace_folders' },
"command! -nargs=0 TSymbols lua require'navigator.treesitter'.side_panel()<CR>", { key = '<Space>la', mode = 'n', func = require('navigator.codelens').run_action, desc = 'run code lens action' },
"command! -nargs=* Calltree lua require'navigator.hierarchy'.calltree(<f-args>)<CR>",
} }
local key_maps_help = {} local key_maps_help = {}
@ -77,8 +76,8 @@ local key_maps_help = {}
local M = {} local M = {}
local ccls_mappings = { local ccls_mappings = {
{ key = '<Leader>gi', func = "require('navigator.cclshierarchy').incoming_calls()" }, { key = '<Leader>gi', func = require('navigator.cclshierarchy').incoming_calls, desc = 'incoming_calls' },
{ key = '<Leader>go', func = "require('navigator.cclshierarchy').outgoing_calls()" }, { key = '<Leader>go', func = require('navigator.cclshierarchy').outgoing_calls, desc = 'outgoing_calls' },
} }
local check_cap = function(opts) local check_cap = function(opts)
@ -116,12 +115,25 @@ local check_cap = function(opts)
end end
local function set_cmds(_) 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 for _, value in pairs(commands) do
vim.cmd(value) vim.cmd(value)
end end
end end
-- should works for both 1)attach from known lsp client or from a disabled lsp client -- 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 function set_mapping(lsp_attach_info)
local opts = { noremap = true, silent = true } local opts = { noremap = true, silent = true }
vim.validate({ vim.validate({
@ -133,13 +145,17 @@ local function set_mapping(lsp_attach_info)
local user_key = _NgConfigValues.keymaps or {} local user_key = _NgConfigValues.keymaps or {}
local bufnr = lsp_attach_info.bufnr or 0 local bufnr = lsp_attach_info.bufnr or 0
local function del_keymap(...) local function del_keymap(mode, key, ...)
vim.api.nvim_buf_del_keymap(bufnr, ...) 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 end
local function set_keymap(...) local function set_keymap(...)
vim.api.nvim_buf_set_keymap(bufnr, ...) vim.api.nvim_buf_set_keymap(bufnr, ...)
end end
-- local function buf_set_option(...) -- local function buf_set_option(...)
-- vim.api.nvim_buf_set_option(bufnr, ...) -- vim.api.nvim_buf_set_option(bufnr, ...)
-- end -- end
@ -167,42 +183,85 @@ local function set_mapping(lsp_attach_info)
key_maps = _NgConfigValues.keymaps or {} key_maps = _NgConfigValues.keymaps or {}
log('setting maps to ', key_maps) log('setting maps to ', key_maps)
end end
local fmtkey, rfmtkey local fmtkey, rfmtkey, nrfmtkey
require('navigator.formatting')
for _, value in pairs(key_maps) do for _, value in pairs(key_maps) do
local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>' if value.doc then
if string.find(value.func, 'require') or string.find(value.func, 'vim.') then vim.notify('doc field no longer supported in navigator mapping, use desc instead')
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 .. '<string.find(value.func, 'vim.')CR>'
end end
local k = value.key if type(value.func) == 'string' then -- deprecated will remove when 0.8 is out
local m = value.mode or 'n' vim.notify('keymap config updated: ' .. value.key .. ' func ' .. value.func .. ' should be a function')
if string.find(value.func, 'range_formatting') then local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>'
rfmtkey = value.key if string.find(value.func, 'require') or string.find(value.func, 'vim.') then
elseif string.find(value.func, 'format') then f = '<Cmd>lua ' .. value.func .. '<CR>'
fmtkey = value.key 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 end
trace('binding', k, f) if type(value.func) == 'function' then -- new from 0.7.x
set_keymap(m, k, f, opts) -- neovim 0.7.0
end
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 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 end
-- if user_opts.cap.document_formatting then -- if user_opts.cap.document_formatting then
if doc_fmt and _NgConfigValues.lsp.format_on_save then if doc_fmt and _NgConfigValues.lsp.format_on_save then
vim.cmd([[ local gn = api.nvim_create_augroup('NavAuGroupFormat', {})
aug NavigatorAuFormat
au! local fopts = _NgConfigValues.lsp.format_options
autocmd BufWritePre <buffer> lua vim.lsp.buf.format({async = true})
aug END 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 elseif fmtkey then
del_keymap('n', fmtkey) del_keymap('n', fmtkey)
end end
@ -215,45 +274,19 @@ local function set_mapping(lsp_attach_info)
del_keymap('v', rfmtkey) del_keymap('v', rfmtkey)
end 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) log('enable format ', doc_fmt, range_fmt, _NgConfigValues.lsp.format_on_save)
end end
local function autocmd() local function autocmd()
vim.api.nvim_exec( local gn = api.nvim_create_augroup('NavAuGroupDocHlAu', {})
[[
aug NavigatorDocHlAu
au!
au CmdlineLeave : lua require('navigator.dochighlight').cmd_nohl()
aug END
]],
false
)
end
local function set_event_handler(user_opts) api.nvim_create_autocmd({ 'BufWritePre' }, {
user_opts = user_opts or {} group = gn,
local file_types = callback = require('navigator.dochighlight').cmd_nohl,
'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]])
end end
M.toggle_lspformat = function(on) M.toggle_lspformat = function(on)
@ -287,7 +320,6 @@ function M.setup(attach_opts)
set_cmds(attach_opts) set_cmds(attach_opts)
autocmd() autocmd()
set_event_handler(attach_opts)
local client = attach_opts.client or {} local client = attach_opts.client or {}
local cap = client.server_capabilities or vim.lsp.protocol.make_client_capabilities() local cap = client.server_capabilities or vim.lsp.protocol.make_client_capabilities()
@ -330,6 +362,14 @@ function M.setup(attach_opts)
}) })
end end
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 local border_style = single
if _NgConfigValues.border == 'double' then if _NgConfigValues.border == 'double' then
border_style = double border_style = double
@ -348,7 +388,7 @@ M.get_keymaps_help = function()
border = 'none', border = 'none',
prompt = true, prompt = true,
enter = true, enter = true,
rect = { height = 20, width = 90 }, rect = { height = 24, width = 50 },
data = key_maps_help, 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 = require('navigator.lru').new(1000, 1024 * 1024)
local ts_nodes_time = require('navigator.lru').new(1000) local ts_nodes_time = require('navigator.lru').new(1000)
local TS_analysis_enabled = require('navigator').config_values().treesitter_analysis local TS_analysis_enabled = require('navigator').config_values().treesitter_analysis
local nts = require('navigator.treesitter')
-- extract symbol from range -- extract symbol from range
function M.get_symbol(text, range) function M.get_symbol(text, range)
if range == nil then if range == nil then
@ -169,7 +169,7 @@ local function ts_functions(uri, optional)
lerr('ts not enabled') lerr('ts not enabled')
return nil return nil
end end
local ts_func = require('navigator.treesitter').buf_func local ts_func = nts.buf_func
local bufnr = vim.uri_to_bufnr(uri) local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock() local x = os.clock()
trace(ts_nodes) trace(ts_nodes)
@ -230,7 +230,7 @@ local function ts_definition(uri, range, optional)
if optional then if optional then
return return
end end
local ts_def = require('navigator.treesitter').find_definition local ts_def = nts.find_definition
local bufnr = vim.uri_to_bufnr(uri) local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock() local x = os.clock()
trace(ts_nodes) trace(ts_nodes)
@ -252,6 +252,7 @@ local function ts_definition(uri, range, optional)
end end
local function find_ts_func_by_range(funcs, range) local function find_ts_func_by_range(funcs, range)
log(funcs, range)
if funcs == nil or range == nil then if funcs == nil or range == nil then
return nil return nil
end end
@ -352,7 +353,6 @@ function M.locations_to_items(locations, ctx)
local unload_bufnrs = {} local unload_bufnrs = {}
for i, loc in ipairs(locations) do for i, loc in ipairs(locations) do
local funcs = nil
local item = lsp.util.locations_to_items({ loc }, enc)[1] local item = lsp.util.locations_to_items({ loc }, enc)[1]
item.range = locations[i].range or locations[i].targetRange item.range = locations[i].range or locations[i].targetRange
item.uri = locations[i].uri or locations[i].targetUri item.uri = locations[i].uri or locations[i].targetUri
@ -363,13 +363,25 @@ function M.locations_to_items(locations, ctx)
log(cwd) log(cwd)
end end
-- only load top 30 file. -- 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 local unload, def
if TS_analysis_enabled and proj_file then local context = ''
funcs, unload = ts_functions(item.uri, ts_optional(i, #unload_bufnrs)) 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 if unload then
table.insert(unload_bufnrs, unload) table.insert(unload_bufnrs, unload)
unload = nil
end end
if not uri_def[item.uri] then if not uri_def[item.uri] then
-- find def in file -- find def in file
@ -408,9 +420,15 @@ function M.locations_to_items(locations, ctx)
end end
item.filename = assert(vim.uri_to_fname(item.uri)) item.filename = assert(vim.uri_to_fname(item.uri))
local filename = item.filename:gsub(cwd .. path_sep, path_cur, 1) 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.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) item.rpath = util.get_relative_path(cwd, item.filename)
width = math.max(width, #item.text) width = math.max(width, #item.text)
item.symbol_name = M.get_symbol(item.text, item.range) item.symbol_name = M.get_symbol(item.text, item.range)

@ -11,10 +11,11 @@ local locations_to_items = lsphelper.locations_to_items
local M = {} local M = {}
local ref_view = function(err, locations, ctx, cfg) local ref_view = function(err, locations, ctx, cfg)
cfg = cfg or {}
local truncate = cfg and cfg.truncate or 20 local truncate = cfg and cfg.truncate or 20
local opts = {} local opts = {}
trace('arg1', err, ctx, locations) trace('arg1', err, ctx, locations)
log(#locations, locations[1]) -- log(#locations, locations[1])
if ctx.combine then if ctx.combine then
-- wait for both reference and definition LSP request -- wait for both reference and definition LSP request
if ctx.results == nil then if ctx.results == nil then
@ -41,24 +42,16 @@ local ref_view = function(err, locations, ctx, cfg)
end end
vim.list_extend(locations, definitions.result) vim.list_extend(locations, definitions.result)
end end
if references and references.result and #references.result > 0 then if references and references.result and #references.result > 0 then
local refs = references.result local refs = references.result
for _, value in pairs(locations) do
local vrange = value.range or { start = { line = 0 }, ['end'] = { line = 0 } }
for i = 1, #refs, 1 do
local rg = refs[i].range or {}
trace(value, refs[i])
trace(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) vim.list_extend(locations, refs)
end end
err = nil err = nil
trace(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 end
-- log("num", num) -- log("num", num)
-- log("bfnr", bufnr) -- log("bfnr", bufnr)
@ -86,11 +79,11 @@ local ref_view = function(err, locations, ctx, cfg)
local thread_items = vim.deepcopy(items) local thread_items = vim.deepcopy(items)
log('splits: ', #items, #second_part) 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 wwidth = vim.api.nvim_get_option('columns')
local mwidth = _NgConfigValues.width 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(items)
-- log(width) -- log(width)
opts = { opts = {
@ -102,12 +95,22 @@ local ref_view = function(err, locations, ctx, cfg)
api = 'Reference', api = 'Reference',
enable_preview_edit = true, 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 if listview == nil then
vim.notify('failed to create preview windows', vim.lsp.log_levels.INFO) vim.notify('failed to create preview windows', vim.lsp.log_levels.INFO)
return 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 end
-- trace("update items", listview.ctrl.class) -- trace("update items", listview.ctrl.class)
local nv_ref_async local nv_ref_async
nv_ref_async = vim.loop.new_async(vim.schedule_wrap(function() nv_ref_async = vim.loop.new_async(vim.schedule_wrap(function()
@ -142,6 +145,9 @@ end
local ref_hdlr = function(err, locations, ctx, cfg) local ref_hdlr = function(err, locations, ctx, cfg)
_NgConfigValues.closer = nil _NgConfigValues.closer = nil
trace(err, locations, ctx, cfg) 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() M.async_hdlr = vim.loop.new_async(vim.schedule_wrap(function()
ref_view(err, locations, ctx, cfg) ref_view(err, locations, ctx, cfg)
if M.async_hdlr:is_active() then if M.async_hdlr:is_active() then
@ -216,7 +222,36 @@ local ref = function()
end) end)
end end
local function side_panel()
local Panel = require('guihua.panel')
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 { return {
side_panel = side_panel,
reference_handler = ref_hdlr, reference_handler = ref_hdlr,
reference = ref_req, reference = ref_req,
ref_view = ref_view, ref_view = ref_view,

@ -1,7 +1,9 @@
local log = require('guihua.log').info local util = require('navigator.util')
local trace = require('guihua.log').trace local log = util.log
local M = {} local trace = util.trace
local clone = require('guihua.util').clone local clone = require('guihua.util').clone
local M = {}
local function filename(url) local function filename(url)
if url == nil then if url == nil then
return '' return ''
@ -69,7 +71,7 @@ function M.prepare_for_render(items, opts)
icon = devicons.get_icon(fn, ext) or icon icon = devicons.get_icon(fn, ext) or icon
end end
-- local call_by_presented = false -- local call_by_presented = false
opts.width = opts.width or 100 opts.width = opts.width or math.floor(vim.api.nvim_get_option('columns') * 0.8)
local win_width = opts.width -- buf local win_width = opts.width -- buf
for i = 1, #items do for i = 1, #items do
@ -150,52 +152,28 @@ function M.prepare_for_render(items, opts)
trace(ts_report, header_len) trace(ts_report, header_len)
item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '') item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '')
if item.call_by ~= nil and #item.call_by > 0 then if item.call_by ~= nil and item.call_by ~= '' then
trace('call_by:', #item.call_by) ts_report = ts_report .. '' .. 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
end end
if #ts_report > 1 then if #ts_report > 1 then
space, trim = get_pads(win_width, item.text, ts_report) 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 if trim then
local ts_r = ts_report or '' item.text = string.sub(item.text, 1, l)
item.text = string.sub(item.text, 1, math.max(1, opts.width - math.max(20, #ts_r))) item.text = util.sub_match(item.text)
local _, j = string.gsub(item.text, [["]], '')
if j % 2 == 1 then
item.text = item.text .. '"'
end
_, j = string.gsub(item.text, [[']], '')
if j % 2 == 1 then
item.text = item.text .. [[']]
end
item.text = item.text .. ''
-- let check if there are unmatched "/' -- let check if there are unmatched "/'
end end
if #space + #item.text + #ts_report >= win_width then if #space + #item.text + #ts_report >= win_width then
if #item.text + #ts_report > win_width then if #item.text + #ts_report >= win_width then
trace('exceeding', #item.text, #ts_report, win_width) space = ' '
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 else
local remain = win_width - #item.text - #ts_report local remain = win_width - #item.text - #ts_report
trace('remain', remain) trace('remain', remain)

@ -23,6 +23,7 @@ local cwd = vim.loop.cwd()
local log = require('navigator.util').log local log = require('navigator.util').log
local lerr = require('navigator.util').error local lerr = require('navigator.util').error
local trace = function(...) end local trace = function(...) end
trace = log
if vim.fn.has('nvim-0.7') == 1 then if vim.fn.has('nvim-0.7') == 1 then
local trace = require('navigator.util').trace local trace = require('navigator.util').trace
end end
@ -109,6 +110,96 @@ function M.find_definition(range, bufnr)
end end
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). --- Get definitions of bufnr (unique and sorted by order of appearance).
--- This function copy from treesitter/refactor/navigation.lua --- This function copy from treesitter/refactor/navigation.lua
local function get_definitions(bufnr) local function get_definitions(bufnr)
@ -121,23 +212,23 @@ local function get_definitions(bufnr)
ts_locals.recurse_local_nodes(loc.definition, function(_, node, _, match) ts_locals.recurse_local_nodes(loc.definition, function(_, node, _, match)
-- lua doesn't compare tables by value, -- lua doesn't compare tables by value,
-- use the value from byte count instead. -- use the value from byte count instead.
local k, l, start = node:start() local row, col, offset = node:start()
local erow, ecol, end_ = node:end_()
trace(node, match) trace(node, match)
trace(k, l, start, node:parent(), node:parent():start(), node:parent():type()) 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 if node and node:parent() and string.find(node:parent():type(), 'parameter_declaration') then
log('parameter_declaration skip') log('parameter_declaration skip')
return return
end end
nodes_set[start] = { node = node, type = match or '' } nodes_set[offset] = { node = node, type = match or '' }
end) end)
end end
if loc.method then -- for go if loc.method then -- for go
ts_locals.recurse_local_nodes(loc.method, function(def, node, full_match, match) ts_locals.recurse_local_nodes(loc.method, function(def, node, full_match, match)
local k, l, start = node:start() local row, col, start = node:start()
trace(row, col, start, def, node, full_match, match, node:parent(), node:parent():start(), node:parent():type())
trace(k, l, 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 if node:type() == 'field_identifier' and nodes_set[start] == nil then
nodes_set[start] = { node = node, type = 'method' } nodes_set[start] = { node = node, type = 'method' }
end end
@ -154,16 +245,32 @@ local function get_definitions(bufnr)
end end
if loc.reference then -- for go if loc.reference then -- for go
ts_locals.recurse_local_nodes(loc.reference, function(def, node, full_match, match) ts_locals.recurse_local_nodes(loc.reference, function(def, node, full_match, match)
local k, l, start = node:start() local row, col, start = node:start()
local p1, p1t = '', '' local p1, p1t = '', ''
local p2, p2t = '', '' local p2, p2t = '', ''
local p3, p3t = '', ''
if node:parent() and node:parent():parent() then if node:parent() and node:parent():parent() then
p1 = node:parent() p1 = node:parent()
p1t = node:parent():type() p1t = node:parent():type()
p2 = node:parent():parent() p2 = node:parent():parent()
p2t = node:parent():parent():type() p2t = node:parent():parent():type()
end end
trace(k, l, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, p2t) 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 nodes_set[start] == nil then
if -- qualified_type : e.g. io.Reader inside interface if -- qualified_type : e.g. io.Reader inside interface
node:parent() node:parent()
@ -210,7 +317,7 @@ local function get_scope(type, source)
local parent = current:parent() local parent = current:parent()
trace(source:type(), source:range(), 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()) trace(parent:type(), parent:range())
-- a function name -- a function name
if parent:type() == 'function_name' then if parent:type() == 'function_name' then
@ -345,13 +452,14 @@ local function get_all_nodes(bufnr, filter, summary)
trace(bufnr, filter, summary) trace(bufnr, filter, summary)
if not bufnr then 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 end
summary = summary or false summary = summary or false
local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype') local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype')
if not parsers.has_parser() then if not parsers.has_parser() then
if not require('navigator.lspclient.clients').ft_disabled(ft) then if not require('navigator.lspclient.clients').ft_disabled(ft) then
vim.notify('ts not loaded ' .. ft, vim.lsp.log_levels.Debug) -- vim.notify('ts not loaded ' .. ft, vim.lsp.log_levels.Debug)
log('ts not loaded ' .. ft)
end end
return {} return {}
end end
@ -361,17 +469,13 @@ local function get_all_nodes(bufnr, filter, summary)
local display_filename = fname:gsub(cwd .. path_sep, path_cur, 1) local display_filename = fname:gsub(cwd .. path_sep, path_cur, 1)
local all_nodes = {} local all_nodes = {}
-- Support completion-nvim customized label map local containers = filter or {
-- 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 = {
['function'] = true, ['function'] = true,
['local_function'] = true, ['local_function'] = true,
['arrow_function'] = true, ['arrow_function'] = true,
['type'] = true, ['type'] = true,
['class'] = true, ['class'] = true,
['call_expression'] = true,
-- ['var'] = true, -- ['var'] = true,
['struct'] = true, ['struct'] = true,
['method'] = true, ['method'] = true,
@ -394,8 +498,8 @@ local function get_all_nodes(bufnr, filter, summary)
for i = 1, n do for i = 1, n do
local index = n + 1 - i local index = n + 1 - i
local parent_def = parents[index] local parent_def = parents[index]
log(parent_def.type, parent_def.node:type(), vim.treesitter.get_node_text(parent_def.node, bufnr)) -- trace(parent_def.type, parent_def.node:type(), vim.treesitter.get_node_text(parent_def.node, bufnr))
log(def.node:type(), vim.treesitter.get_node_text(def.node, bufnr)) -- trace(def.node:type(), vim.treesitter.get_node_text(def.node, bufnr))
if if
ts_utils.is_parent(parent_def.node, def.node) ts_utils.is_parent(parent_def.node, def.node)
or ( or (
@ -409,10 +513,10 @@ local function get_all_nodes(bufnr, filter, summary)
) )
) )
then then
log('is parent', i, index) -- trace('is parent', i, index)
break break
else else
log('leave node', i, index) -- trace('leave node', i, index)
parents[index] = nil parents[index] = nil
end end
end end
@ -439,7 +543,10 @@ local function get_all_nodes(bufnr, filter, summary)
trace('skipped', item.type, item.kind) trace('skipped', item.type, item.kind)
goto continue goto continue
end end
item.node_text = vim.treesitter.get_node_text(tsdata, bufnr) or '' 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 local scope, is_func
if summary then if summary then
@ -447,6 +554,7 @@ local function get_all_nodes(bufnr, filter, summary)
else else
scope, is_func = get_smallest_context(tsdata) scope, is_func = get_smallest_context(tsdata)
end end
log(item, scope, is_func)
if is_func then if is_func then
-- hack for lua and maybe other language aswell -- hack for lua and maybe other language aswell
local parent = tsdata:parent() local parent = tsdata:parent()
@ -476,7 +584,7 @@ local function get_all_nodes(bufnr, filter, summary)
trace(item.node_text, item.kind, item.type) trace(item.node_text, item.kind, item.type)
if scope ~= nil then if scope ~= nil then
if not is_func and summary then if not is_func and summary then
log('skipped', item.node_text, item.type) trace('skipped', item.node_text, item.type)
goto continue goto continue
end end
item.node_scope = ts_utils.node_to_lsp_range(scope) item.node_scope = ts_utils.node_to_lsp_range(scope)
@ -580,6 +688,7 @@ function M.buf_func(bufnr)
local all_nodes, width = get_all_nodes(bufnr, { local all_nodes, width = get_all_nodes(bufnr, {
['function'] = true, ['function'] = true,
['arrow_function'] = true,
['var'] = true, ['var'] = true,
['method'] = true, ['method'] = true,
['class'] = true, ['class'] = true,
@ -613,6 +722,7 @@ function M.buf_func(bufnr)
return false return false
end) end)
end end
log(all_nodes)
return all_nodes, width return all_nodes, width
end end

@ -61,7 +61,7 @@ function M.get_data_from_file(filename, startLine)
return { data = data, line = displayLine } return { data = data, line = displayLine }
end end
function M.io_read(filename, total) function M.io_read(filename)
local f = io.open(filename, 'r') local f = io.open(filename, 'r')
if f == nil then if f == nil then
return nil return nil
@ -172,41 +172,45 @@ function M.get_relative_path(base_path, my_path)
return data return data
end end
local level = 'error' M.log = function(...)
if _NgConfigValues.debug == true then return { ... }
level = 'info' end
elseif _NgConfigValues.debug == 'trace' then M.info = function(...)
level = 'trace' return { ... }
end
M.trace = function(...)
return { ... }
end
M.warn = function(...)
return { ... }
end end
local default_config = { use_console = false, use_file = true, level = level } M.error = function(...)
if _NgConfigValues.debug_console_output then print(...)
default_config.use_console = true
default_config.use_file = false
end end
M._log = require('guihua.log').new(default_config, true) local level = 'error'
if _NgConfigValues.debug then
-- add log to you lsp.log
M.trace = M._log.trace function M.setup()
M.info = M._log.info if _NgConfigValues.debug == true then
M.warn = M._log.warn level = 'info'
M.error = M._log.error elseif _NgConfigValues.debug == 'trace' then
M.log = M.info level = 'trace'
else
M.log = function(...)
return { ... }
end
M.info = function(...)
return { ... }
end end
M.trace = function(...) local default_config = { use_console = false, use_file = true, level = level }
return { ... } if _NgConfigValues.debug_console_output then
default_config.use_console = true
default_config.use_file = false
end end
M.warn = function(...)
return { ... } 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
M.error = M._log.error
end end
function M.fmt(...) function M.fmt(...)
@ -487,6 +491,47 @@ function M.info(msg)
vim.notify('INF: ' .. msg, vim.lsp.log_levels.INFO) vim.notify('INF: ' .. msg, vim.lsp.log_levels.INFO)
end 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) function M.range_inside(outer, inner)
if outer == nil or inner == nil then if outer == nil or inner == nil then
return false return false
@ -497,4 +542,31 @@ function M.range_inside(outer, inner)
return outer.start.line <= inner.start.line and outer['end'].line >= inner['end'].line return outer.start.line <= inner.start.line and outer['end'].line >= inner['end'].line
end 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 return M

@ -19,7 +19,7 @@ M.remove_workspace_folder = function()
local folders = vim.lsp.buf.list_workspace_folders() local folders = vim.lsp.buf.list_workspace_folders()
if #folders > 1 then 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) vim.lsp.buf.remove_workspace_folder(workspace)
end) end)
end end
@ -37,7 +37,7 @@ function M.workspace_symbol_live()
local height = _NgConfigValues.height or 0.4 local height = _NgConfigValues.height or 0.4
height = math.floor(height * vfn.winheight('%')) height = math.floor(height * vfn.winheight('%'))
local width = _NgConfigValues.width or 0.7 local width = _NgConfigValues.width or 0.7
width = math.floor(width * vfn.winwidth('%')) width = math.floor(vim.api.nvim_get_option('columns') * width)
local bufnr = vim.api.nvim_get_current_buf() local bufnr = vim.api.nvim_get_current_buf()
local ft = vim.o.ft local ft = vim.o.ft
local data = { { text = 'input the symbol name to start fuzzy search' } } local data = { { text = 'input the symbol name to start fuzzy search' } }
@ -47,7 +47,7 @@ function M.workspace_symbol_live()
local ListView = require('guihua.listview') local ListView = require('guihua.listview')
local opt = { local opt = {
api = '', api = '',
bg = 'GHListDark', bg = 'GuihuaListDark',
data = data, data = data,
items = data, items = data,
enter = true, enter = true,

@ -41,12 +41,23 @@ local function load_plugins()
use({ 'ray-x/lsp_signature.nvim' }) use({ 'ray-x/lsp_signature.nvim' })
use({ 'ray-x/aurora' }) use({ 'ray-x/aurora' })
use({ use({
'ray-x/navigator.lua', -- 'ray-x/navigator.lua',
-- '~/github/ray-x/navigator.lua', '~/github/ray-x/navigator.lua',
requires = { 'ray-x/guihua.lua', run = 'cd lua/fzy && make' }, requires = { 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
config = function() config = function()
require('navigator').setup({ 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, end,
}) })

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

@ -60,10 +60,10 @@ describe('should run lsp call hierarchy', function()
-- eq(panel.activePanel.sections[1].nodes[1].name, 'measure') -- eq(panel.activePanel.sections[1].nodes[1].name, 'measure')
end) end)
it('should show hierarchy', function() it('should not crash and show hierarchy', function()
vim.fn.setpos('.', { bufn, 24, 15, 0 }) vim.fn.setpos('.', { bufn, 24, 15, 0 })
local ret = require('navigator.hierarchy')._call_hierarchy() local ret = require('navigator.hierarchy')._call_hierarchy()
vim.wait(400, function() end) vim.wait(400, function() end)
eq(ret, {}) eq(ret, ret) -- make sure doesn't crash the result
end) end)
end) end)

@ -114,9 +114,9 @@ describe('should run lsp reference', function()
-- print('win', vim.inspect(win)) -- print('win', vim.inspect(win))
print('items', vim.inspect(items)) 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(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) -- eq(width, 60)
end) end)
@ -137,7 +137,7 @@ describe('should run lsp reference', function()
-- print('win', vim.inspect(win)) -- print('win', vim.inspect(win))
print('items', vim.inspect(items)) print('items', vim.inspect(items))
-- eq(win.ctrl.data, "./interface.go") -- 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(win.ctrl.data[2].range.start.line, 14)
-- eq(items[1].display_filename, "./interface.go") -- eq(items[1].display_filename, "./interface.go")

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