Merge branch 'master' into neovim_0.6

neovim_0.6
ray-x 2 years ago
commit 251bb84471

@ -0,0 +1,3 @@
# These are supported funding model platforms
github: ray-x

@ -10,23 +10,23 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: ubuntu-20.04 - os: ubuntu-22.04
url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz
manager: sudo snap manager: sudo snap
packages: go packages: go
- os: ubuntu-20.04 - os: ubuntu-22.04
url: https://github.com/neovim/neovim/releases/download/v0.5.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
- os: ubuntu-20.04 - os: ubuntu-22.04
url: https://github.com/neovim/neovim/releases/download/v0.6.0/nvim-linux64.tar.gz url: https://github.com/neovim/neovim/releases/download/v0.6.1/nvim-linux64.tar.gz
manager: sudo snap manager: sudo snap
packages: go packages: go
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: "^1.17.2" # The Go version to download (if necessary) and use. go-version: "^1.18.1" # The Go version to download (if necessary) and use.
- run: date +%F > todays-date - run: date +%F > todays-date
- name: Restore cache for today's nightly. - name: Restore cache for today's nightly.
uses: actions/cache@v2 uses: actions/cache@v2
@ -42,7 +42,7 @@ jobs:
mkdir -p _neovim mkdir -p _neovim
curl -sL ${{ matrix.url }} | tar xzf - --strip-components=1 -C "${PWD}/_neovim" curl -sL ${{ matrix.url }} | tar xzf - --strip-components=1 -C "${PWD}/_neovim"
} }
GO111MODULE=on go get golang.org/x/tools/gopls@latest GO111MODULE=on go install golang.org/x/tools/gopls@latest
mkdir -p ~/.local/share/nvim/site/pack/vendor/start mkdir -p ~/.local/share/nvim/site/pack/vendor/start
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim

@ -1,9 +1,14 @@
# Navigator # Navigator
- Source code analysis and navigate tool
- Easy code navigation, view diagnostic errors, see relationships of functions, variables - Easy code navigation, view diagnostic errors, see relationships of functions, variables
- A plugin combines the power of LSP and 🌲🏡 Treesitter together. Not only provids a better highlight but also help you analyse symbol context effectively. - A plugin combines the power of LSP and 🌲🏡 Treesitter together. Not only provids a better highlight but also help you analyse symbol context effectively.
- ctags fuzzy search & build ctags symbols
-
- [![a short intro of navigator](https://user-images.githubusercontent.com/1681295/147378905-51eede5f-e36d-48f4-9799-ae562949babe.jpeg)](https://youtu.be/P1kd7Y8AatE) - [![a short intro of navigator](https://user-images.githubusercontent.com/1681295/147378905-51eede5f-e36d-48f4-9799-ae562949babe.jpeg)](https://youtu.be/P1kd7Y8AatE)
Here are some examples Here are some examples
@ -91,7 +96,11 @@ 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 folding algorithm. (It behaves similar to vs-code) - Syntax folding based on treesitter or LSP_fold folding algorithm. (It behaves similar to vs-code); comment folding
- Treesitter symbols sidebar, LSP document symbole sidebar. Both with preview and folding
- Calltree: Display and expand Lsp incoming/outgoing calls hierarchy-tree with sidebar
- Fully support LSP CodeAction, CodeLens, CodeLens action. Help you improve code quality. - Fully support LSP CodeAction, CodeLens, CodeLens action. Help you improve code quality.
@ -101,6 +110,8 @@ variable is:
- Multigrid support (different font and detachable) - Multigrid support (different font and detachable)
- Side panel (sidebar) and floating windows
# Why a new plugin # Why a new plugin
I'd like to go beyond what the system is offering. I'd like to go beyond what the system is offering.
@ -116,7 +127,7 @@ I'd like to go beyond what the system is offering.
# Install # Install
Require nvim-0.5.0 (a.k.a nightly) Require nvim-0.6.1 or above, nightly (0.8) prefered
You can remove your lspconfig setup and use this plugin. You can remove your lspconfig setup and use this plugin.
The plugin depends on lspconfig and [guihua.lua](https://github.com/ray-x/guihua.lua), which provides GUI and fzy support(migrate from [romgrk's project](romgrk/fzy-lua-native)). The plugin depends on lspconfig and [guihua.lua](https://github.com/ray-x/guihua.lua), which provides GUI and fzy support(migrate from [romgrk's project](romgrk/fzy-lua-native)).
@ -127,14 +138,18 @@ Plug 'ray-x/guihua.lua', {'do': 'cd lua/fzy && make' }
Plug 'ray-x/navigator.lua' Plug 'ray-x/navigator.lua'
``` ```
Note: Highly recommened: 'nvim-treesitter/nvim-treesitter' Note: Highly recommend: 'nvim-treesitter/nvim-treesitter'
Packer Packer
```lua ```lua
use({
use {'ray-x/navigator.lua', requires = {'ray-x/guihua.lua', run = 'cd lua/fzy && make'}} 'ray-x/navigator.lua',
requires = {
{ 'ray-x/guihua.lua', run = 'cd lua/fzy && make' },
{ 'neovim/nvim-lspconfig' },
},
})
``` ```
## Setup ## Setup
@ -247,6 +262,8 @@ require'navigator'.setup({
-- 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
-- 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
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
@ -262,6 +279,8 @@ require'navigator'.setup({
}, },
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
lsp = { lsp = {
enable = true, -- skip lsp setup if disabled make sure add require('navigator.lspclient.mapping').setup() in you
-- own on_attach
code_action = {enable = true, sign = true, sign_priority = 40, virtual_text = true}, code_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},
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)
@ -271,6 +290,12 @@ require'navigator'.setup({
-- 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'
-- Default {} -- Default {}
diagnostic = {
underline = true,
virtual_text = true, -- show virtual for diagnostic message
update_in_insert = false, -- update diagnostic message in insert mode
},
diagnostic_scrollbar_sign = {'▃', '▆', '█'}, -- experimental: diagnostic status in scroll bar area; set to false to disable the diagnostic sign, diagnostic_scrollbar_sign = {'▃', '▆', '█'}, -- experimental: diagnostic status in scroll bar area; set to false to disable the diagnostic sign,
-- for other style, set to {'╍', 'ﮆ'} or {'-', '='} -- for other style, set to {'╍', 'ﮆ'} or {'-', '='}
diagnostic_virtual_text = true, -- show virtual for diagnostic message diagnostic_virtual_text = true, -- show virtual for diagnostic message
@ -281,6 +306,11 @@ require'navigator'.setup({
filetypes = {'typescript'} -- disable javascript etc, filetypes = {'typescript'} -- disable javascript etc,
-- set to {} to disable the lspclient for all filetypes -- set to {} to disable the lspclient for all filetypes
}, },
ctags ={
cmd = 'ctags',
tagfile = 'tags'
options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number'
}
gopls = { -- gopls setting 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
@ -317,7 +347,8 @@ local servers = {
"jedi_language_server", "jdtls", "sumneko_lua", "vimls", "html", "jsonls", "solargraph", "cssls", "jedi_language_server", "jdtls", "sumneko_lua", "vimls", "html", "jsonls", "solargraph", "cssls",
"yamlls", "clangd", "ccls", "sqls", "denols", "graphql", "dartls", "dotls", "yamlls", "clangd", "ccls", "sqls", "denols", "graphql", "dartls", "dotls",
"kotlin_language_server", "nimls", "intelephense", "vuels", "phpactor", "omnisharp", "kotlin_language_server", "nimls", "intelephense", "vuels", "phpactor", "omnisharp",
"r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp", "elixirls" "r_language_server", "rust_analyzer", "terraformls", "svelte", "texlab", "clojure_lsp", "elixirls",
"sourcekit", "fsautocomplete", "vls", "hls"
} }
``` ```
@ -389,8 +420,8 @@ In `playground` folder, there is a `init.lua` and source code for you to play wi
| mode | key | function | | mode | key | function |
| ---- | --------------- | ---------------------------------------------------------- | | ---- | --------------- | ---------------------------------------------------------- |
| n | gr | show reference and context | | n | gr | async references, definitions and context |
| n | Gr | async references, definitions and context (experiential) | | n | \<Leader>gr | show reference and context |
| i | \<m-k\> | signature help | | i | \<m-k\> | signature help |
| n | \<c-k\> | signature help | | n | \<c-k\> | signature help |
| n | gW | workspace symbol | | n | gW | workspace symbol |
@ -403,10 +434,12 @@ In `playground` folder, there is a `init.lua` and source code for you to play wi
| n | g\<LeftMouse\> | implementation | | n | g\<LeftMouse\> | implementation |
| n | \<Leader>gt | treesitter document symbol | | n | \<Leader>gt | treesitter document symbol |
| n | \<Leader\>gT | treesitter symbol for all open buffers | | n | \<Leader\>gT | treesitter symbol for all open buffers |
| n | \<Leader\> ct | ctags symbol search |
| n | \<Leader\> cg | ctags symbol generate |
| n | K | hover doc | | n | K | hover doc |
| n | \<Space\>ca | code action (when you see 🏏 ) | | n | \<Space\>ca | code action (when you see 🏏 ) |
| n | \<Space\>la | code lens action (when you see a codelens indicator) | | n | \<Space\>la | code lens action (when you see a codelens indicator) |
| v | \<Space\>cA | range code action (when you see 🏏 ) | | v | \<Space\>ca | range code action (when you see 🏏 ) |
| n | \<Space\>rn | rename with floating window | | n | \<Space\>rn | rename with floating window |
| n | \<Leader\>re | rename (lsp default) | | n | \<Leader\>re | rename (lsp default) |
| n | \<Leader\>gi | hierarchy incoming calls | | n | \<Leader\>gi | hierarchy incoming calls |
@ -479,7 +512,33 @@ lsp_installer = true
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}`
Alternatively, Navigator can be used to startup the server installed by lsp-installer. Please do not call `server:setup{opts}` from lsp installer example:
```lua
use({
'williamboman/nvim-lsp-installer',
config = function()
local lsp_installer = require('nvim-lsp-installer')
lsp_installer.setup{}
end,
})
use({
'ray-x/navigator.lua',
config = function()
require('navigator').setup({
debug = true,
lsp_installer = true,
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
})
end,
})
```
Please refer to [lsp_installer_config](https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
for more info
Alternatively, Navigator can be used to startup the server installed by lsp-installer.
as it will override the navigator setup as it will override the navigator setup
To start LSP installed by lsp_installer, please use following setups To start LSP installed by lsp_installer, please use following setups
@ -538,6 +597,47 @@ require'navigator'.setup({
``` ```
Use lsp_installer configs
You can delegate the lsp server setup to lsp_installer with `server:setup{opts}`
Here is an example [init_lsp_installer.lua](https://github.com/ray-x/navigator.lua/blob/master/playground/init_lsp_installer.lua)
### Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension)
There are lots of plugins provides lsp support
go.nvim allow you either hook gopls from go.nvim or from navigator and it can export the lsp setup from go.nvim.
rust-tools and clangd allow you to setup on_attach from config server
Here is an example to setup rust with rust-tools
```lua
require'navigator'.setup({
lsp = {
disable_lsp = { "rust_analyzer", "clangd" }, -- will not run rust_analyzer setup from navigator
}
})
require('rust-tools').setup({
server = {
on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here,
-- otherwise, you can define your own commands to call navigator functions
end,
}
})
require("clangd_extensions").setup {
server = {
on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({client=client, bufnr=bufnr}) -- setup navigator keymaps here,
-- otherwise, you can define your own commands to call navigator functions
end,
}
}
```
## Usage ## Usage
Please refer to lua/navigator/lspclient/mapping.lua on key mappings. Should be able to work out-of-box. Please refer to lua/navigator/lspclient/mapping.lua on key mappings. Should be able to work out-of-box.
@ -577,6 +677,12 @@ You can override the above highlight to fit your current colorscheme
| ------------ | ------------------------- | | ------------ | ------------------------- |
| LspToggleFmt | toggle lsp auto format | | LspToggleFmt | toggle lsp auto format |
| LspKeymaps | show LSP releated keymaps | | LspKeymaps | show LSP releated keymaps |
| Nctags {args} | show ctags symbols, args: -g regen ctags |
| LspRestart | reload lsp |
| LspToggleFmt | toggle lsp format |
| LspSymbols | document symbol in side panel |
| TSymobls | treesitter symbol in side panel |
| Calltree {args} | lsp call hierarchy call tree, args: -i (incomming default), -o (outgoing) |
## Screenshots ## Screenshots
@ -592,6 +698,14 @@ Using treesitter and LSP to view the symbol definition
![image](https://user-images.githubusercontent.com/1681295/139771978-bbc970a5-be9f-42cf-8942-3477485bd89c.png) ![image](https://user-images.githubusercontent.com/1681295/139771978-bbc970a5-be9f-42cf-8942-3477485bd89c.png)
### Sidebar, folding, outline
Treesitter outline and Diagnostics
<img width="708" alt="image" src="https://user-images.githubusercontent.com/1681295/174791609-0023e68f-f1f4-4335-9ea2-d2360e9f0bfd.png">
<img width="733" alt="image" src="https://user-images.githubusercontent.com/1681295/174804579-26f87fbf-426b-46d0-a7a3-a5aab69c032f.png">
Calltree (Expandable LSP call hierarchy)
<img width="769" alt="image" src="https://user-images.githubusercontent.com/1681295/176998572-e39fc968-4c8c-475d-b3b8-fb7991663646.png">
### GUI and multigrid support ### GUI and multigrid support
You can load a different font size for floating win You can load a different font size for floating win
@ -754,7 +868,7 @@ end
# Errors and Bug Reporting # Errors and Bug Reporting
- Please double check your setup and check if minium setup works or not - Please double check your setup and check if minium setup works or not
- It should works for 0.5.1, neovim 0.6.x prefered. - It should works for 0.6.1, neovim 0.7.x prefered.
- Check console output - Check console output
- Check `LspInfo` and treesitter status with `checkhealth` - Check `LspInfo` and treesitter status with `checkhealth`
- Turn on log and attach the log to your issue if possible you can remove any personal/company info in the log - Turn on log and attach the log to your issue if possible you can remove any personal/company info in the log

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

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

@ -0,0 +1,4 @@
autocmd BufRead,BufNewFile *.tf,*.tfvars set filetype=terraform
autocmd BufRead,BufNewFile *.tfstate,*.tfstate.backup set filetype=json
autocmd BufRead,BufNewFile *.hcl set filetype=hcl
autocmd BufRead,BufNewFile .terraformrc,terraform.rc set filetype=hcl

@ -27,14 +27,15 @@ _NgConfigValues = {
-- your on_attach will be called at end of navigator on_attach -- your on_attach will be called at end of navigator on_attach
end, end,
ts_fold = false, ts_fold = false,
-- code_action_prompt = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
-- code_lens_action_prompt = {enable = true, sign = true, sign_priority = 40, virtual_text = true},
treesitter_analysis = true, -- treesitter variable context treesitter_analysis = true, -- treesitter variable context
treesitter_analysis_max_num = 100, -- how many items to run treesitter analysis
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' },
lsp = { lsp = {
enable = true, -- if disabled make sure add require('navigator.lspclient.mapping').setup() in you on_attach
code_action = { code_action = {
enable = true, enable = true,
sign = true, sign = true,
@ -49,10 +50,16 @@ _NgConfigValues = {
virtual_text = true, virtual_text = true,
virtual_text_icon = true, virtual_text_icon = true,
}, },
diagnostic = {
underline = true,
virtual_text = { spacing = 3, source = true }, -- show virtual for diagnostic message
update_in_insert = false, -- update diagnostic message in insert mode
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)
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
code_lens = false,
-- only want to enable one lsp server -- only want to enable one lsp server
disply_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors disply_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors
diagnostic_load_files = false, -- lsp diagnostic errors list may contains uri that not opened yet set to true diagnostic_load_files = false, -- lsp diagnostic errors list may contains uri that not opened yet set to true
@ -94,6 +101,15 @@ _NgConfigValues = {
-- Values -- Values
value_changed = '📝', value_changed = '📝',
value_definition = '🐶🍡', -- it is easier to see than 🦕 value_definition = '🐶🍡', -- it is easier to see than 🦕
side_panel = {
section_separator = '',
line_num_left = '',
line_num_right = '',
inner_node = '├○',
outer_node = '╰○',
bracket_left = '',
bracket_right = '',
},
-- Treesitter -- Treesitter
match_kinds = { match_kinds = {
var = '', -- "👹", -- Vampaire var = '', -- "👹", -- Vampaire
@ -104,18 +120,15 @@ _NgConfigValues = {
namespace = '🚀', namespace = '🚀',
type = '', type = '',
field = '🏈', field = '🏈',
module = '📦',
flag = '🎏',
}, },
treesitter_defult = '🌲', treesitter_defult = '🌲',
doc_symbols = '',
}, },
} }
vim.cmd("command! -nargs=0 LspLog lua require'navigator.lspclient.config'.open_lsp_log()")
vim.cmd("command! -nargs=0 LspRestart lua require'navigator.lspclient.config'.reload_lsp()")
vim.cmd("command! -nargs=0 LspToggleFmt lua require'navigator.lspclient.mapping'.toggle_lspformat()<CR>")
vim.cmd("command! -nargs=0 LspKeymaps lua require'navigator.lspclient.mapping'.get_keymaps_help()<CR>")
M.deprecated = function(cfg) M.deprecated = function(cfg)
local warn = require('navigator.util').warn
if cfg.code_action_prompt then if cfg.code_action_prompt then
warn('code_action_prompt moved to lsp.code_action') warn('code_action_prompt moved to lsp.code_action')
end end
@ -127,6 +140,10 @@ M.deprecated = function(cfg)
warn('disable_format_ft renamed to disable_format_cap') warn('disable_format_ft renamed to disable_format_cap')
end end
if cfg.lsp ~= nil and cfg.lsp.code_lens == true then
warn('code_lens moved to lsp.code_lens_action')
end
if cfg.lspinstall ~= nil then if cfg.lspinstall ~= nil then
warn('lspinstall deprecated, please use lsp-installer instead or use "lspinstall" branch') warn('lspinstall deprecated, please use lsp-installer instead or use "lspinstall" branch')
end end
@ -137,9 +154,8 @@ local extend_config = function(opts)
if next(opts) == nil then if next(opts) == nil then
return return
end end
if opts.lsp and opts.lsp.servers then if opts.debug then
require('navigator.lspclient.clients').add_servers(opts.lsp.servers) _NgConfigValues.debug = opts.debug
opts.lsp.server = nil
end end
for key, value in pairs(opts) do for key, value in pairs(opts) do
if _NgConfigValues[key] == nil then if _NgConfigValues[key] == nil then
@ -185,7 +201,7 @@ local extend_config = function(opts)
if key == 'lsp' then if key == 'lsp' then
local lsp = require('navigator.lspclient.clients').lsp local lsp = require('navigator.lspclient.clients').lsp
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 ', 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')
@ -215,31 +231,42 @@ M.config_values = function()
end end
M.setup = function(cfg) M.setup = function(cfg)
cfg = cfg or {}
extend_config(cfg) extend_config(cfg)
vim.cmd([[autocmd FileType,BufEnter * lua require'navigator.lspclient.clients'.on_filetype()]]) -- BufWinEnter BufNewFile,BufRead ? vim.cmd([[autocmd FileType,BufEnter * lua require'navigator.lspclient.clients'.on_filetype()]]) -- BufWinEnter BufNewFile,BufRead ?
-- local log = require"navigator.util".log
-- log(debug.traceback())
-- log(cfg, _NgConfigValues)
-- print("loading navigator")
require('navigator.lazyloader').init() require('navigator.lazyloader').init()
require('navigator.lspclient.clients').setup(_NgConfigValues) require('navigator.lspclient.clients').setup(_NgConfigValues)
-- keymaps should be added to on_attach. in case on_attach is not called
-- require('navigator.lspclient.mapping').setup(_NgConfigValues)
require('navigator.reference') require('navigator.reference')
require('navigator.definition') require('navigator.definition')
require('navigator.hierarchy') require('navigator.hierarchy')
require('navigator.implementation') require('navigator.implementation')
-- log("navigator loader") cfg.lsp = cfg.lsp or _NgConfigValues.lsp
if cfg.lsp.enable then
-- vim.cmd("autocmd BufNewFile,BufRead *.go setlocal noexpandtab tabstop=4 shiftwidth=4") require('navigator.diagnostics').config(cfg.lsp.diagnostic)
end
if not _NgConfigValues.loaded then if not _NgConfigValues.loaded then
_NgConfigValues.loaded = true _NgConfigValues.loaded = true
end end
if _NgConfigValues.ts_fold == true then if _NgConfigValues.ts_fold == true then
require('navigator.foldts').on_attach() local ok, _ = pcall(require, 'nvim-treesitter')
if ok then
require('navigator.foldts').on_attach()
end
end
local _start_client = vim.lsp.start_client
vim.lsp.start_client = function(lsp_config)
-- add highlight for Lspxxx
require('navigator.dochighlight').documentHighlight()
require('navigator.lspclient.highlight').add_highlight()
require('navigator.lspclient.highlight').diagnositc_config_sign()
-- require('navigator.lspclient.mapping').setup()
require('navigator.lspclient.lspkind').init()
return _start_client(lsp_config)
end end
end end

@ -11,9 +11,9 @@ local M = {}
local function call_hierarchy_handler(direction, err, result, ctx, cfg, error_message) local function call_hierarchy_handler(direction, err, result, ctx, cfg, error_message)
log('call_hierarchy') log('call_hierarchy')
log('call_hierarchy', direction, err, result) log('call_hierarchy', direction, err, result, ctx, cfg)
assert(#vim.lsp.buf_get_clients() > 0, 'Must have a client running to use lsp_tags') assert(next(vim.lsp.buf_get_clients()), 'Must have a client running to use lsp_tags')
if err ~= nil then if err ~= nil then
log('hierarchy error', ctx, 'dir', direction, 'result', result, 'err', err) log('hierarchy error', ctx, 'dir', direction, 'result', result, 'err', err)
vim.notify('ERROR: ' .. error_message, vim.lsp.log_levels.WARN) vim.notify('ERROR: ' .. error_message, vim.lsp.log_levels.WARN)
@ -51,25 +51,27 @@ end
local call_hierarchy_handler_from = partial(call_hierarchy_handler, 'from') local call_hierarchy_handler_from = partial(call_hierarchy_handler, 'from')
local call_hierarchy_handler_to = partial(call_hierarchy_handler, 'to') local call_hierarchy_handler_to = partial(call_hierarchy_handler, 'to')
local function incoming_calls_handler(bang, err, result, ctx, cfg) local function incoming_calls_handler(_, err, result, ctx, cfg)
assert(#vim.lsp.buf_get_clients() > 0, 'Must have a client running to use lsp_tags') local bufnr = vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
local results = call_hierarchy_handler_from(err, result, ctx, cfg, 'Incoming calls not found') local results = call_hierarchy_handler_from(err, result, ctx, cfg, 'Incoming calls not found')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft') local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')
gui.new_list_view({ items = results, ft = ft, api = '' }) gui.new_list_view({ items = results, ft = ft or 'cpp', api = '' })
end end
-- err, method, result, client_id, bufnr -- err, method, result, client_id, bufnr
local function outgoing_calls_handler(bang, err, result, ctx, cfg) local function outgoing_calls_handler(_, err, result, ctx, cfg)
local results = call_hierarchy_handler_to(err, result, ctx, cfg, 'Outgoing calls not found') local results = call_hierarchy_handler_to(err, result, ctx, cfg, 'Outgoing calls not found')
local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft') local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft')
gui.new_list_view({ items = results, ft = ft, api = '' }) gui.new_list_view({ items = results, ft = ft or 'cpp', api = '' })
-- fzf_locations(bang, "", "Outgoing Calls", results, false) -- fzf_locations(bang, "", "Outgoing Calls", results, false)
end end
function M.incoming_calls(bang, opts) function M.incoming_calls(bang, opts)
assert(#vim.lsp.buf_get_clients() > 0, 'Must have a client running to use lsp_tags') local bufnr = vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
-- if not lsphelper.check_capabilities("call_hierarchy") then -- if not lsphelper.check_capabilities("call_hierarchy") then
-- return -- return
-- end -- end
@ -85,7 +87,8 @@ function M.incoming_calls(bang, opts)
end end
function M.outgoing_calls(bang, opts) function M.outgoing_calls(bang, opts)
assert(#vim.lsp.buf_get_clients() > 0, 'Must have a client running to use lsp_tags') local bufnr = vim.api.nvim_get_current_buf()
assert(next(vim.lsp.buf_get_clients(bufnr)), 'Must have a client running to use lsp_tags')
local params = vim.lsp.util.make_position_params() local params = vim.lsp.util.make_position_params()
params['levels'] = 2 params['levels'] = 2
params['callee'] = true params['callee'] = true

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

@ -4,13 +4,10 @@
local codelens = require('vim.lsp.codelens') local codelens = require('vim.lsp.codelens')
local log = require('navigator.util').log local log = require('navigator.util').log
local mk_handler = require('navigator.util').mk_handler
local nvim_0_6 = require('navigator.util').nvim_0_6
local trace = require('navigator.util').trace local trace = require('navigator.util').trace
local lsphelper = require('navigator.lspwrapper') local lsphelper = require('navigator.lspwrapper')
local api = vim.api local api = vim.api
local gui = require('navigator.gui')
local M = {} local M = {}
local config = require('navigator').config_values() local config = require('navigator').config_values()
@ -49,8 +46,8 @@ local function _update_sign(line)
end end
end end
local codelens_hdlr = mk_handler(function(err, result, ctx, cfg) local codelens_hdlr = function(err, result, ctx, cfg)
log(ctx, result) trace(ctx, result)
M.codelens_ctx = ctx M.codelens_ctx = ctx
if err or result == nil then if err or result == nil then
if err then if err then
@ -62,7 +59,7 @@ local codelens_hdlr = mk_handler(function(err, result, ctx, cfg)
for _, v in pairs(result) do for _, v in pairs(result) do
_update_sign(v.range.start.line) _update_sign(v.range.start.line)
end end
end) end
function M.setup() function M.setup()
vim.cmd('highlight! link LspCodeLens LspDiagnosticsHint') vim.cmd('highlight! link LspCodeLens LspDiagnosticsHint')
@ -75,28 +72,23 @@ function M.setup()
vim.cmd("autocmd BufEnter,CursorHold,InsertLeave <buffer> lua require('navigator.codelens').refresh()") vim.cmd("autocmd BufEnter,CursorHold,InsertLeave <buffer> lua require('navigator.codelens').refresh()")
vim.cmd('augroup end') vim.cmd('augroup end')
local on_codelens = vim.lsp.handlers['textDocument/codeLens'] local on_codelens = vim.lsp.handlers['textDocument/codeLens']
vim.lsp.handlers['textDocument/codeLens'] = mk_handler(function(err, result, ctx, cfg) vim.lsp.handlers['textDocument/codeLens'] = function(err, result, ctx, cfg)
-- trace(err, result, ctx.client_id, ctx.bufnr, cfg or {}) -- trace(err, result, ctx.client_id, ctx.bufnr, cfg or {})
cfg = cfg or {} cfg = cfg or {}
ctx = ctx or { bufnr = vim.api.nvim_get_current_buf() } ctx = ctx or { bufnr = vim.api.nvim_get_current_buf() }
if nvim_0_6() then on_codelens(err, result, ctx, cfg)
on_codelens(err, result, ctx, cfg) codelens_hdlr(err, result, ctx, cfg)
codelens_hdlr(err, result, ctx, cfg) end
else
on_codelens(err, ctx.method, result, ctx.client_id, ctx.bufnr)
codelens_hdlr(err, nil, result, ctx.client_id or 0, ctx.bufnr or 0)
end
end)
end end
M.lsp_clients = {} M.lsp_clients = {}
function M.refresh() function M.refresh()
if #vim.lsp.buf_get_clients() < 1 then if next(vim.lsp.buf_get_clients(0)) == nil then
log('Must have a client running to use lsp code action') log('Must have a client running to use lsp code action')
return return
end end
if not lsphelper.check_capabilities('code_lens') then if not lsphelper.check_capabilities('codeLensProvider') then
return return
end end
vim.lsp.codelens.refresh() vim.lsp.codelens.refresh()
@ -110,20 +102,16 @@ function M.disable()
is_enabled = false is_enabled = false
end end
function M.run_action() 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('codeaction')
codelens.run() codelens.run()
vim.defer_fn( vim.defer_fn(function()
function () vim.ui.select = original_select
vim.ui.select = original_select end, 1000)
end, 1000
)
end end
M.inline = function() M.inline = function()
@ -134,7 +122,8 @@ M.inline = function()
if vim.fn.getcmdwintype() == ':' then if vim.fn.getcmdwintype() == ':' then
return return
end end
if #vim.lsp.buf_get_clients() == 0 then
if next(vim.lsp.buf_get_clients(0)) == nil then
return return
end end

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

@ -5,10 +5,10 @@ local gui = require('navigator.gui')
local log = util.log local log = util.log
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 = util.mk_handler(function(err, locations, ctx, _) local definition_hdlr = function(err, locations, ctx, _)
-- log(locations) -- log(locations)
if err ~= nil then if err ~= nil then
vim.notify('Defination: ', tostring(err) .. vim.inspect(ctx), vim.lsp.log_levels.WARN) vim.notify('Defination: ' .. tostring(err) .. vim.inspect(ctx), vim.lsp.log_levels.WARN)
return return
end end
if type(locations) == 'number' then if type(locations) == 'number' then
@ -31,7 +31,7 @@ local definition_hdlr = util.mk_handler(function(err, locations, ctx, _)
else else
vim.lsp.util.jump_to_location(locations, oe) vim.lsp.util.jump_to_location(locations, oe)
end end
end) end
local function get_symbol() local function get_symbol()
local currentWord = vim.fn.expand('<cword>') local currentWord = vim.fn.expand('<cword>')
@ -39,7 +39,7 @@ local function get_symbol()
end end
local function def_preview(timeout_ms) local function def_preview(timeout_ms)
assert(#vim.lsp.buf_get_clients() > 0, 'Must have a client running') assert(next(vim.lsp.buf_get_clients(0)), 'Must have a client running')
local method = 'textDocument/definition' local method = 'textDocument/definition'
local params = vim.lsp.util.make_position_params() local params = vim.lsp.util.make_position_params()
local result = vim.lsp.buf_request_sync(0, method, params, timeout_ms or 1000) local result = vim.lsp.buf_request_sync(0, method, params, timeout_ms or 1000)
@ -85,6 +85,9 @@ local function def_preview(timeout_ms)
local ts = require('navigator.treesitter') local ts = require('navigator.treesitter')
local root = parsers.get_parser(bufnr) local root = parsers.get_parser(bufnr)
log(range) log(range)
if ts == nil then
return
end
local def_node = ts.get_node_at_pos({ range['start'].line, range['start'].character }, root) local def_node = ts.get_node_at_pos({ range['start'].line, range['start'].character }, root)
local sr, _, er, _ = ts.get_node_scope(def_node) local sr, _, er, _ = ts.get_node_scope(def_node)
@ -105,7 +108,7 @@ local function def_preview(timeout_ms)
end end
local width = 40 local width = 40
local maxwidth = math.floor(vim.fn.winwidth(0) * 4 / 5) local maxwidth = math.floor(vim.fn.winwidth(0) * 4 / 5)
for key, 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)
width = math.min(maxwidth, width) width = math.min(maxwidth, width)
@ -118,7 +121,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 }, rect = { width = width, height = #definition + 3, pos_y = 2 },
data = definition, data = definition,
enter = true, enter = true,
border = _NgConfigValues.border or 'shadow', border = _NgConfigValues.border or 'shadow',
@ -143,8 +146,9 @@ local def = function()
local bufnr = vim.api.nvim_get_current_buf() local bufnr = 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, client_id, _bufnr) vim.lsp.for_each_buffer_client(bufnr, function(client, _, _bufnr)
if client.resolved_capabilities.goto_definition then -- if client.resolved_capabilities.goto_definition then
if client.server_capabilities.definitionProvider then
client.request('textDocument/definition', ref_params, definition_hdlr, _bufnr) client.request('textDocument/definition', ref_params, definition_hdlr, _bufnr)
end end
end) end)

@ -9,19 +9,13 @@ local trace = require('guihua.log').trace
-- trace = log -- trace = log
local error = util.error local error = util.error
local path_sep = require('navigator.util').path_sep() local path_sep = require('navigator.util').path_sep()
local mk_handler = require('navigator.util').mk_handler
local path_cur = require('navigator.util').path_cur() local path_cur = require('navigator.util').path_cur()
local empty = util.empty local empty = util.empty
diagnostic_list[vim.bo.filetype] = {}
local function clear_diag_VT(bufnr) -- important for clearing out when no more errors
log(bufnr, _NG_VT_DIAG_NS)
if bufnr == nil or _NG_VT_DIAG_NS == nil then
return
end
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1) if not util.nvim_0_6_1() then
_NG_VT_DIAG_NS = nil util.warn('Navigator 0.4+ only support nvim-0.6+, please use Navigator 0.3.x or a newer version of neovim')
end end
diagnostic_list[vim.bo.filetype] = {}
local diag_map = {} local diag_map = {}
if vim.diagnostic then if vim.diagnostic then
@ -33,6 +27,25 @@ if vim.diagnostic then
} }
end end
local diagnostic_cfg = {
-- Enable underline, use default values
underline = _NgConfigValues.lsp.diagnostic.underline,
-- Enable virtual
-- Use a function to dynamically turn signs off
-- and on, using buffer local variables
signs = true,
update_in_insert = _NgConfigValues.lsp.diagnostic.update_in_insert or false,
severity_sort = _NgConfigValues.lsp.diagnostic.severity_sort,
float = {
focusable = false,
style = 'minimal',
border = 'rounded',
source = 'always',
header = '',
prefix = '',
},
}
local function get_count(bufnr, level) local function get_count(bufnr, level)
if vim.diagnostic ~= nil then if vim.diagnostic ~= nil then
return #diagnostic.get(bufnr, { severity = diag_map[level] }) return #diagnostic.get(bufnr, { severity = diag_map[level] })
@ -145,7 +158,7 @@ local function error_marker(result, ctx, config)
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) vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
end end
for i, s in pairs(pos) do for _, s in pairs(pos) do
local hl = 'ErrorMsg' local hl = 'ErrorMsg'
if type(s.severity) == 'number' then if type(s.severity) == 'number' then
if s.severity == 2 then if s.severity == 2 then
@ -180,8 +193,9 @@ local update_err_marker_async = function()
return debounce(400, error_marker) return debounce(400, error_marker)
end end
local diag_hdlr = mk_handler(function(err, result, ctx, config) local diag_hdlr = function(err, result, ctx, config)
require('navigator.lspclient.highlight').diagnositc_config_sign() require('navigator.lspclient.highlight').diagnositc_config_sign()
config = config or diagnostic_cfg
if err ~= nil then if err ~= nil then
log(err, config, result) log(err, config, result)
return return
@ -203,19 +217,14 @@ local diag_hdlr = mk_handler(function(err, result, ctx, config)
trace('diagnostic', result.diagnostics, ctx, config) trace('diagnostic', result.diagnostics, ctx, config)
end end
if util.nvim_0_6() then trace(err, result, ctx, config)
trace(err, result, ctx, config) vim.lsp.diagnostic.on_publish_diagnostics(err, result, ctx, config)
vim.lsp.diagnostic.on_publish_diagnostics(err, result, ctx, config)
else
log('old version of lsp nvim 050')
vim.lsp.diagnostic.on_publish_diagnostics(err, _, result, ctx.client_id, _, config)
end
local uri = result.uri local uri = result.uri
local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]]) local diag_cnt = get_count(bufnr, [[Error]]) + get_count(bufnr, [[Warning]])
if empty(result.diagnostics) and diag_cnt > 0 then if empty(result.diagnostics) and diag_cnt > 0 then
log('no result? ', diag_cnt) trace('no result? ', diag_cnt)
return return
end end
-- trace("diag: ", mode, result, ctx, config) -- trace("diag: ", mode, result, ctx, config)
@ -295,39 +304,38 @@ local diag_hdlr = mk_handler(function(err, result, ctx, config)
vim.api.nvim_buf_clear_namespace(0, _NG_VT_DIAG_NS, 0, -1) vim.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)
local diag_hdlr_async = function()
local debounce = require('navigator.debounce').debounce_trailing
return debounce(100, diag_hdlr)
end end
-- local diag_hdlr_async = function()
-- local debounce = require('navigator.debounce').debounce_trailing
-- return debounce(100, diag_hdlr)
-- end
local M = {} local M = {}
local diagnostic_cfg = {
-- Enable underline, use default values
underline = true,
-- Enable virtual text, override spacing to 3 (prevent overlap)
virtual_text = {
spacing = 3,
prefix = _NgConfigValues.icons.icons and _NgConfigValues.icons.diagnostic_virtual_text or "" },
-- 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 = { reverse = true },
}
if _NgConfigValues.lsp.diagnostic_virtual_text == false then diagnostic_cfg.virtual_text = _NgConfigValues.lsp.diagnostic.virtual_text
diagnostic_cfg.virtual_text = false if type(_NgConfigValues.lsp.diagnostic.virtual_text) == 'table' then
diagnostic_cfg.virtual_text.prefix = _NgConfigValues.icons.diagnostic_virtual_text
end end
-- vim.lsp.handlers["textDocument/publishDiagnostics"] -- vim.lsp.handlers["textDocument/publishDiagnostics"]
M.diagnostic_handler = vim.lsp.with(diag_hdlr, diagnostic_cfg) M.diagnostic_handler = vim.lsp.with(diag_hdlr, diagnostic_cfg)
vim.diagnostic.config(diagnostic_cfg)
local function clear_diag_VT(bufnr) -- important for clearing out when no more errors
bufnr = bufnr or vim.api.nvim_get_current_buf()
log(bufnr, _NG_VT_DIAG_NS)
if _NG_VT_DIAG_NS == nil then
return
end
vim.api.nvim_buf_clear_namespace(bufnr, _NG_VT_DIAG_NS, 0, -1)
_NG_VT_DIAG_NS = nil
end
M.hide_diagnostic = function() M.hide_diagnostic = function()
if _NG_VT_DIAG_NS then if _NG_VT_DIAG_NS then
vim.api.nvim_buf_clear_namespace(0, _NG_VT_DIAG_NS, 0, -1) clear_diag_VT()
_NG_VT_DIAG_NS = nil
end end
end end
@ -342,8 +350,6 @@ end
M.show_buf_diagnostics = function() M.show_buf_diagnostics = function()
if diagnostic_list[vim.bo.filetype] ~= nil then if diagnostic_list[vim.bo.filetype] ~= nil then
-- log(diagnostic_list[vim.bo.filetype])
-- vim.fn.setqflist({}, " ", {title = "LSP", items = diagnostic_list[vim.bo.filetype]})
local results = diagnostic_list[vim.bo.filetype] local results = diagnostic_list[vim.bo.filetype]
local display_items = {} local display_items = {}
for _, client_items in pairs(results) do for _, client_items in pairs(results) do
@ -360,8 +366,13 @@ M.show_buf_diagnostics = function()
api = _NgConfigValues.icons.diagnostic_file .. _NgConfigValues.icons.diagnostic_head .. ' Diagnostic ', api = _NgConfigValues.icons.diagnostic_file .. _NgConfigValues.icons.diagnostic_head .. ' Diagnostic ',
enable_preview_edit = true, enable_preview_edit = true,
}) })
if listview == nil then
return log('nil listview')
end
trace('new buffer', listview.bufnr) trace('new buffer', listview.bufnr)
vim.api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1) if listview.bufnr then
vim.api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1)
end
end end
end end
end end
@ -374,14 +385,15 @@ M.set_diag_loclist = function()
log('great, no errors!') log('great, no errors!')
return return
end end
local clients = vim.lsp.buf_get_clients(0)
local clients = vim.lsp.buf_get_clients(bufnr)
local cfg = { open = diag_cnt > 0 } local cfg = { open = diag_cnt > 0 }
for _, client in pairs(clients) do for _, client in pairs(clients) do
cfg.client_id = client['id'] cfg.client_id = client['id']
break break
end end
if not vim.tbl_isempty(vim.lsp.buf_get_clients(0)) then if not vim.tbl_isempty(vim.lsp.buf_get_clients(bufnr)) then
local err_cnt = get_count(0, [[Error]]) local err_cnt = get_count(0, [[Error]])
if err_cnt > 0 and _NgConfigValues.lsp.disply_diagnostic_qf then if err_cnt > 0 and _NgConfigValues.lsp.disply_diagnostic_qf then
if diagnostic.set_loclist then if diagnostic.set_loclist then
@ -431,11 +443,6 @@ function M.update_err_marker()
marker(result, { bufnr = bufnr, method = 'textDocument/publishDiagnostics' }) marker(result, { bufnr = bufnr, method = 'textDocument/publishDiagnostics' })
end end
-- TODO: update the marker
if _NgConfigValues.diagnostic_scrollbar_sign then
vim.notify('config deprecated, set lsp.diagnostic_scrollbar_sign instead', vim.lsp.log_levels.WARN)
end
if _NgConfigValues.lsp.diagnostic_scrollbar_sign then if _NgConfigValues.lsp.diagnostic_scrollbar_sign then
vim.cmd([[autocmd WinScrolled * lua require'navigator.diagnostics'.update_err_marker()]]) vim.cmd([[autocmd WinScrolled * lua require'navigator.diagnostics'.update_err_marker()]])
end end
@ -462,4 +469,53 @@ function M.show_diagnostics(pos)
end end
end end
function M.treesitter_and_diag_panel()
local Panel = require('guihua.panel')
local ft = vim.bo.filetype
local results = diagnostic_list[ft]
log(diagnostic_list, ft)
local bufnr = vim.api.nvim_get_current_buf()
local p = Panel:new({
header = 'treesitter',
render = function(b)
log('render for ', bufnr, b)
return require('navigator.treesitter').all_ts_nodes(b)
end,
})
p:add_section({
header = 'diagnostic',
render = function(bufnr)
if diagnostic_list[ft] ~= nil then
local display_items = {}
for _, client_items in pairs(results) do
for _, items in pairs(client_items) do
for _, it in pairs(items) do
log(it)
table.insert(display_items, it)
end
end
end
return display_items
else
return {}
end
end,
})
p:open(true)
end
function M.config(cfg)
cfg = cfg or {}
local default_cfg = {
underline = true,
virtual_text = true,
signs = { _NgConfigValues.icons.diagnostic_err },
update_in_insert = false,
}
cfg = vim.tbl_extend('keep', cfg, default_cfg)
vim.diagnostic.config(cfg)
end
return M return M

@ -1,7 +1,6 @@
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 mk_handler = util.mk_handler
local api = vim.api local api = vim.api
local references = {} local references = {}
_NG_hi_list = {} _NG_hi_list = {}
@ -139,7 +138,7 @@ local function before(r1, r2)
return false return false
end end
local handle_document_highlight = mk_handler(function(_, result, ctx) local handle_document_highlight = function(_, result, ctx)
trace(result, ctx) trace(result, ctx)
if not ctx.bufnr then if not ctx.bufnr then
log('ducment highlight error', result, ctx) log('ducment highlight error', result, ctx)
@ -157,7 +156,7 @@ local handle_document_highlight = mk_handler(function(_, result, ctx)
references[ctx.bufnr] = result references[ctx.bufnr] = result
local client_id = ctx.client_id local client_id = ctx.client_id
vim.lsp.util.buf_highlight_references(ctx.bufnr, result, util.encoding(client_id)) vim.lsp.util.buf_highlight_references(ctx.bufnr, result, util.encoding(client_id))
end) end
-- modify from vim-illuminate -- modify from vim-illuminate
local function goto_adjent_reference(opt) local function goto_adjent_reference(opt)
trace(opt) trace(opt)
@ -206,11 +205,11 @@ local function cmd_nohl()
end end
end end
_G.nav_doc_hl = function() local nav_doc_hl = function()
local bufnr = vim.api.nvim_get_current_buf() local bufnr = 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, client_id, bufnr) vim.lsp.for_each_buffer_client(bufnr, function(client, _, _)
if client.resolved_capabilities.document_highlight then if client.server_capabilities.documentHighlightProvider == true then
client.request('textDocument/documentHighlight', ref_params, handle_document_highlight, bufnr) client.request('textDocument/documentHighlight', ref_params, handle_document_highlight, bufnr)
end end
end) end)
@ -219,20 +218,15 @@ end
local function documentHighlight() local function documentHighlight()
api.nvim_exec( api.nvim_exec(
[[ [[
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
augroup lsp_document_highlight augroup lsp_document_highlight
autocmd! * <buffer> autocmd! * <buffer>
autocmd CursorHold <buffer> lua nav_doc_hl() autocmd CursorHold,CursorHoldI <buffer> lua require('navigator.dochighlight').nav_doc_hl()
autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
augroup END augroup END
]], ]],
false false
) )
vim.lsp.handlers['textDocument/documentHighlight'] = mk_handler(function(err, result, ctx) vim.lsp.handlers['textDocument/documentHighlight'] = function(err, result, ctx)
local bufnr = ctx.bufnr or api.nvim_get_current_buf() local bufnr = 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)
@ -255,7 +249,7 @@ local function documentHighlight()
end) end)
references[bufnr] = result references[bufnr] = result
add_locs(bufnr, result) add_locs(bufnr, result)
end) end
end end
return { return {
@ -264,5 +258,6 @@ return {
handle_document_highlight = handle_document_highlight, handle_document_highlight = handle_document_highlight,
hi_symbol = hi_symbol, hi_symbol = hi_symbol,
nohl = nohl, nohl = nohl,
nav_doc_hl = nav_doc_hl,
cmd_nohl = cmd_nohl, cmd_nohl = cmd_nohl,
} }

@ -1,5 +1,4 @@
local log = require"navigator.util".log local log = require('navigator.util').log
local mk_handler = require"navigator.util".mk_handler
local lsp = vim.lsp local lsp = vim.lsp
local api = vim.api local api = vim.api
@ -18,7 +17,7 @@ M.servers_supporting_folding = {
texlab = true, texlab = true,
clangd = false, clangd = false,
gopls = true, gopls = true,
julials = false julials = false,
} }
M.active_folding_clients = {} M.active_folding_clients = {}
@ -29,11 +28,11 @@ function M.on_attach()
end end
function M.setup_plugin() function M.setup_plugin()
api.nvim_command("augroup FoldingCommand") api.nvim_command('augroup FoldingCommand')
api.nvim_command("autocmd! * <buffer>") api.nvim_command('autocmd! * <buffer>')
api.nvim_command("autocmd BufEnter <buffer> lua require'navigator.foldlsp'.update_folds()") api.nvim_command("autocmd BufEnter <buffer> lua require'navigator.foldlsp'.update_folds()")
api.nvim_command("autocmd BufWritePost <buffer> lua require'navigator.foldlsp'.update_folds()") api.nvim_command("autocmd BufWritePost <buffer> lua require'navigator.foldlsp'.update_folds()")
api.nvim_command("augroup end") api.nvim_command('augroup end')
-- vim.cmd([[ -- vim.cmd([[
-- --
@ -43,7 +42,7 @@ function M.setup_plugin()
-- --
-- ]]) -- ]])
local clients = vim.lsp.buf_get_clients() local clients = vim.lsp.buf_get_clients(0)
for _, client in pairs(clients) do for _, client in pairs(clients) do
local client_id = client['id'] local client_id = client['id']
@ -57,7 +56,6 @@ function M.setup_plugin()
M.active_folding_clients[client_id] = server_supports_folding M.active_folding_clients[client_id] = server_supports_folding
end end
end end
-- print(vim.inspect(M.active_folding_clients))
end end
function M.update_folds() function M.update_folds()
@ -73,9 +71,8 @@ function M.update_folds()
-- XXX: better to pass callback in this method or add it directly in the config? -- XXX: better to pass callback in this method or add it directly in the config?
-- client.config.callbacks['textDocument/foldingRange'] = M.fold_handler -- client.config.callbacks['textDocument/foldingRange'] = M.fold_handler
local current_bufnr = api.nvim_get_current_buf() local current_bufnr = api.nvim_get_current_buf()
local params = {uri = vim.uri_from_bufnr(current_bufnr)} local params = { uri = vim.uri_from_bufnr(current_bufnr) }
client.request('textDocument/foldingRange', {textDocument = params}, M.fold_handler, client.request('textDocument/foldingRange', { textDocument = params }, M.fold_handler, current_bufnr)
current_bufnr)
end end
end end
end end
@ -89,11 +86,11 @@ function M.debug_folds()
end end
end end
M.fold_handler = mk_handler(function(err, result, ctx, config) M.fold_handler = function(err, result, ctx, _)
-- params: err, method, result, client_id, bufnr -- params: err, method, result, client_id, bufnr
-- XXX: handle err? -- XXX: handle err?
if err or result == nil or #result == 0 then if err or result == nil or #result == 0 then
vim.notify(string.format("%s %s ", tostring(err), vim.inspect(ctx)), vim.lsp.log_levels.WARN) vim.notify(string.format('%s %s ', tostring(err), vim.inspect(ctx)), vim.lsp.log_levels.WARN)
return return
end end
M.debug_folds() M.debug_folds()
@ -113,7 +110,7 @@ M.fold_handler = mk_handler(function(err, result, ctx, config)
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', 'foldlsp#foldexpr()') api.nvim_win_set_option(current_window, 'foldexpr', 'foldlsp#foldexpr()')
end end
end) end
function M.adjust_foldstart(line_no) function M.adjust_foldstart(line_no)
return line_no + 1 return line_no + 1
@ -160,13 +157,12 @@ function M.get_fold_indic(lnum)
-- without any marker. -- without any marker.
return fold_level return fold_level
elseif is_foldstart then elseif is_foldstart then
return string.format(">%d", fold_level) return string.format('>%d', fold_level)
elseif is_foldend then elseif is_foldend then
return string.format("<%d", fold_level) return string.format('<%d', fold_level)
else else
return fold_level return fold_level
end end
end end
return M return M

@ -1,6 +1,7 @@
-- NOTE: this file is a modified version of fold.lua from nvim-treesitter -- NOTE: this file is a modified version of fold.lua from nvim-treesitter
local log = require('navigator.util').log local log = require('navigator.util').log
local trace = require('navigator.util').trace
local api = vim.api local api = vim.api
local tsutils = require('nvim-treesitter.ts_utils') local tsutils = require('nvim-treesitter.ts_utils')
local query = require('nvim-treesitter.query') local query = require('nvim-treesitter.query')
@ -16,15 +17,14 @@ function M.on_attach()
-- M.update_folds() -- M.update_folds()
end end
function _G.custom_fold_text() 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' return '' .. line .. ': ' .. line_count .. ' lines'
end end
vim.opt.foldtext = custom_fold_text() vim.opt.foldtext = NG_custom_fold_text()
vim.opt.fillchars = { eob = '-', fold = ' ' } vim.opt.fillchars = { eob = '-', fold = ' ' }
vim.opt.viewoptions:remove('options') vim.opt.viewoptions:remove('options')
@ -38,13 +38,13 @@ function M.setup_fold()
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')
vim.opt.foldtext = 'v:lua.custom_fold_text()' vim.opt.foldtext = 'v:lua.NG_custom_fold_text()'
vim.opt.fillchars = { eob = '-', fold = ' ' } vim.opt.fillchars = { eob = '-', 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()
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#foldexpr()') api.nvim_win_set_option(current_window, 'foldexpr', 'folding#ngfoldexpr()')
end 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
@ -61,7 +61,7 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
local parser = parsers.get_parser(bufnr) local parser = parsers.get_parser(bufnr)
if not parser then if not parser then
warn('treesitter parser not loaded') log('treesitter parser not loaded')
return {} return {}
end end
@ -148,12 +148,12 @@ local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr)
levels[lnum + 1] = tostring(trimmed_level) levels[lnum + 1] = tostring(trimmed_level)
else else
-- if levels[lnum + 1] == nil then -- if levels[lnum + 1] == nil then
levels[lnum + 1] = tostring(trimmed_level + 1) levels[lnum + 1] = tostring(trimmed_level + 1)
-- end -- end
end end
end end
end end
log(levels) trace(levels)
return levels return levels
end) end)

@ -1,8 +1,7 @@
-- 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
local mk_handler = require('navigator.util').mk_handler
return { return {
format_hdl = mk_handler(function(err, result, ctx, cfg) -- FIXME: bufnr is nil format_hdl = function(err, result, ctx, _) -- FIXME: bufnr is nil
if err ~= nil or result == nil then if err ~= nil or result == nil then
return return
end end
@ -31,5 +30,5 @@ return {
-- end -- end
end end
end, 100) end, 100)
end), end,
} }

@ -8,11 +8,11 @@ local api = vim.api
local active_list_view -- only one listview at a time local active_list_view -- only one listview at a time
function M.new_list_view(opts) function M.new_list_view(opts)
log(opts) -- log(opts)
local config = require('navigator').config_values() local config = require('navigator').config_values()
if active_list_view ~= nil then if active_list_view ~= nil then
log(active_list_view) trace(active_list_view)
local winnr = active_list_view.win local winnr = active_list_view.win
local bufnr = active_list_view.buf local bufnr = active_list_view.buf
@ -23,40 +23,40 @@ function M.new_list_view(opts)
end end
local items = opts.items local items = opts.items
opts.min_width = opts.min_width or 0.3 opts.height_ratio = opts.height or config.height
opts.min_height = opts.min_height or 0.3 opts.width_ratio = opts.height or config.width
opts.preview_height_ratio = opts.preview_height or config.preview_height
opts.height_ratio = config.height opts.preview_lines = config.preview_lines
opts.width_ratio = config.width
opts.preview_height_ratio = _NgConfigValues.preview_height or 0.3
opts.preview_lines = _NgConfigValues.preview_lines
if opts.rawdata then if opts.rawdata then
opts.data = items opts.data = items
else else
opts.data = require('navigator.render').prepare_for_render(items, opts) opts.data = require('navigator.render').prepare_for_render(items, opts)
end end
opts.border = _NgConfigValues.border or 'shadow' opts.border = config.border or 'shadow'
if vim.fn.hlID('TelescopePromptBorder') > 0 then
opts.border_hl = 'TelescopePromptBorder'
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')
return return
end end
opts.transparency = _NgConfigValues.transparency opts.transparency = config.transparency
if #items >= _NgConfigValues.lines_show_prompt then if #items >= config.lines_show_prompt then
opts.prompt = true opts.prompt = true
end end
opts.external = _NgConfigValues.external opts.external = config.external
opts.preview_lines_before = 3 opts.preview_lines_before = 4
log(opts) if _NgConfigValues.debug then
local logopts = { items = {}, data = {} }
logopts = vim.tbl_deep_extend('keep', logopts, opts)
log(logopts)
end
active_list_view = require('guihua.gui').new_list_view(opts) active_list_view = require('guihua.gui').new_list_view(opts)
return active_list_view return active_list_view
end end
function M.select(items, opts, on_choice)
return
end
return M return M
-- Doc -- Doc

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

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

@ -22,10 +22,16 @@ return {
loader(plugin) loader(plugin)
end end
end end
else
loader = function(plugin)
local cmd = 'packadd ' .. plugin
vim.cmd(cmd)
end
end end
if _NgConfigValues.lsp_installer == true then if _NgConfigValues.lsp_installer == true then
local has_lspinst, lspinst = pcall(require, 'lsp_installer') vim.cmd('packadd nvim-lsp-installer')
local has_lspinst, lspinst = pcall(require, 'nvim-lsp-installer')
log('lsp_installer installed', has_lspinst) log('lsp_installer installed', has_lspinst)
if has_lspinst then if has_lspinst then
lspinst.setup() lspinst.setup()
@ -51,7 +57,7 @@ return {
local lazy_plugins = {} local lazy_plugins = {}
lazy_plugins[plugin_name] = path lazy_plugins[plugin_name] = path
loader = require('packer').loader loader = require('packer').loader
for plugin, url in pairs(lazy_plugins) do for plugin, _ in pairs(lazy_plugins) do
if packer_plugins[plugin] and packer_plugins[plugin].loaded == false then if packer_plugins[plugin] and packer_plugins[plugin].loaded == false then
-- log("loading ", plugin) -- log("loading ", plugin)
pcall(loader, plugin) pcall(loader, plugin)

@ -5,18 +5,13 @@ local util = require('navigator.util')
local log = util.log local log = util.log
local trace = util.trace local trace = util.trace
local diagnostic_map = function(bufnr)
local opts = { noremap = true, silent = true }
api.nvim_buf_set_keymap(bufnr, 'n', ']O', ':lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
end
local M = {} local M = {}
M.on_attach = function(client, bufnr) M.on_attach = function(client, bufnr)
bufnr = bufnr or 0 bufnr = bufnr or 0
if bufnr == 0 then if bufnr == 0 then
vim.notify('no bufnr provided from LSP ', client.name) vim.notify('no bufnr provided from LSP ' .. client.name, vim.log.levels.DEBUG)
end end
local uri = vim.uri_from_bufnr(bufnr) local uri = vim.uri_from_bufnr(bufnr)
@ -29,7 +24,6 @@ M.on_attach = function(client, bufnr)
trace(client) trace(client)
diagnostic_map(bufnr)
-- add highlight for Lspxxx -- add highlight for Lspxxx
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()
@ -38,10 +32,9 @@ M.on_attach = function(client, bufnr)
require('navigator.lspclient.mapping').setup({ require('navigator.lspclient.mapping').setup({
client = client, client = client,
bufnr = bufnr, bufnr = bufnr,
cap = client.resolved_capabilities,
}) })
if client.resolved_capabilities.document_highlight then if client.server_capabilities.documentHighlightProvider == true then
require('navigator.dochighlight').documentHighlight() require('navigator.dochighlight').documentHighlight()
end end
@ -53,15 +46,25 @@ M.on_attach = function(client, bufnr)
log(client.name, 'customized attach for all clients') log(client.name, 'customized attach for all clients')
config.on_attach(client, bufnr) config.on_attach(client, bufnr)
end end
if config.lsp and config.lsp[client.name] and config.lsp[client.name].on_attach ~= nil then if config.lsp and config.lsp[client.name] then
log('lsp client specific attach for', client.name) if type(config.lsp[client.name]) == 'function' then
config.lsp[client.name].on_attach(client, bufnr) local attach = config.lsp[client.name]().on_attach
if attach then
attach(client, bufnr)
end
elseif config.lsp[client.name].on_attach ~= nil then
log(client.name, 'customized attach for this client')
log('lsp client specific attach for', client.name)
config.lsp[client.name].on_attach(client, bufnr)
end
end end
if _NgConfigValues.lsp.code_action.enable then if _NgConfigValues.lsp.code_action.enable then
if client.resolved_capabilities.code_action then if client.server_capabilities.codeActionProvider and client.name ~= 'null-ls' then
log('code action enabled for client', client.resolved_capabilities.code_action) log('code action enabled for client', client.server_capabilities.codeActionProvider)
api.nvim_command('augroup NCodeAction')
vim.cmd([[autocmd CursorHold,CursorHoldI <buffer> lua require'navigator.codeAction'.code_action_prompt()]]) vim.cmd([[autocmd CursorHold,CursorHoldI <buffer> lua require'navigator.codeAction'.code_action_prompt()]])
api.nvim_command('augroup end')
end end
end end
end end

@ -1,9 +1,9 @@
local util = require('navigator.util') -- todo allow config passed in
local log = util.log local ng_util = require('navigator.util')
local trace = util.trace local log = ng_util.log
local uv = vim.loop local trace = ng_util.trace
local empty = util.empty local empty = ng_util.empty
local warn = util.warn local warn = ng_util.warn
_NG_Loaded = {} _NG_Loaded = {}
_LoadedFiletypes = {} _LoadedFiletypes = {}
@ -24,7 +24,25 @@ end
local util = lspconfig.util local util = lspconfig.util
local config = require('navigator').config_values() local config = require('navigator').config_values()
local disabled_ft = {
'NvimTree',
'guihua',
'clap_input',
'clap_spinner',
'vista',
'vista_kind',
'TelescopePrompt',
'guihua_rust',
'csv',
'txt',
'defx',
'packer',
'gitcommit',
'windline',
'notify',
'nofile',
'',
}
-- local cap = vim.lsp.protocol.make_client_capabilities() -- local cap = vim.lsp.protocol.make_client_capabilities()
local on_attach = require('navigator.lspclient.attach').on_attach local on_attach = require('navigator.lspclient.attach').on_attach
-- gopls["ui.completion.usePlaceholders"] = true -- gopls["ui.completion.usePlaceholders"] = true
@ -46,16 +64,14 @@ local luadevcfg = {
local luadev = {} local luadev = {}
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
require('navigator.lazyloader').load('nvim-lsp-installer', 'williamboman/nvim-lsp-installer')
end
local ok, l = pcall(require, 'lua-dev') local ok, l = pcall(require, 'lua-dev')
if ok and l then if ok and l then
luadev = l.setup(luadevcfg) luadev = l.setup(luadevcfg)
end end
local path = vim.split(package.path, ';')
table.insert(path, 'lua/?.lua')
table.insert(path, 'lua/?/init.lua')
local function add(lib) local function add(lib)
for _, p in pairs(vim.fn.expand(lib, false, true)) do for _, p in pairs(vim.fn.expand(lib, false, true)) do
p = vim.loop.fs_realpath(p) p = vim.loop.fs_realpath(p)
@ -113,17 +129,17 @@ local setups = {
elixirls = { elixirls = {
on_attach = on_attach, on_attach = on_attach,
filetypes = { 'elixir', 'eelixir'}, filetypes = { 'elixir', 'eelixir' },
cmd = {'elixir-ls'}, cmd = { 'elixir-ls' },
message_level = vim.lsp.protocol.MessageType.error, message_level = vim.lsp.protocol.MessageType.error,
settings = { settings = {
elixirLS = { elixirLS = {
dialyzerEnabled = true, fetchDeps = false dialyzerEnabled = true,
} fetchDeps = false,
},
}, },
root_dir = function(fname) root_dir = function(fname)
return util.root_pattern('mix.exs', '.git')(fname) return util.root_pattern('mix.exs', '.git')(fname) or util.path.dirname(fname)
or util.path.dirname(fname)
end, end,
}, },
@ -182,9 +198,10 @@ local setups = {
'--cross-file-rename', '--cross-file-rename',
}, },
filetypes = { 'c', 'cpp', 'objc', 'objcpp' }, filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
on_attach = function(client) on_attach = function(client, bufnr)
client.resolved_capabilities.document_formatting = true client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
on_attach(client) or true
on_attach(client, bufnr)
end, end,
}, },
rust_analyzer = { rust_analyzer = {
@ -205,8 +222,8 @@ local setups = {
}, },
sqls = { sqls = {
filetypes = { 'sql' }, filetypes = { 'sql' },
on_attach = function(client, bufnr) on_attach = function(client, _)
client.resolved_capabilities.execute_command = true client.server_capabilities.executeCommandProvider = client.server_capabilities.documentFormattingProvider or true
highlight.diagnositc_config_sign() highlight.diagnositc_config_sign()
require('sqls').setup({ picker = 'telescope' }) -- or default require('sqls').setup({ picker = 'telescope' }) -- or default
end, end,
@ -232,8 +249,6 @@ local setups = {
runtime = { runtime = {
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
version = 'LuaJIT', version = 'LuaJIT',
-- Setup your lua path
path = vim.split(package.path, ';'),
}, },
diagnostics = { diagnostics = {
enable = true, enable = true,
@ -291,6 +306,14 @@ local setups = {
omnisharp = { omnisharp = {
cmd = { 'omnisharp', '--languageserver', '--hostPID', tostring(vim.fn.getpid()) }, 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) setups.sumneko_lua = vim.tbl_deep_extend('force', luadev, setups.sumneko_lua)
@ -333,7 +356,13 @@ local servers = {
'svelte', 'svelte',
'texlab', 'texlab',
'clojure_lsp', 'clojure_lsp',
'elixirls' 'elixirls',
'sourcekit',
'fsautocomplete',
'vls',
'hls',
'tflint',
'terraform_lsp',
} }
local lsp_installer_servers = {} local lsp_installer_servers = {}
@ -359,16 +388,8 @@ local ng_default_cfg = {
flags = { allow_incremental_sync = true, debounce_text_changes = 1000 }, flags = { allow_incremental_sync = true, debounce_text_changes = 1000 },
} }
local configs = {}
-- 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)
-- if _NG_LSPCfgSetup ~= true then
-- log(lspconfig_setup)
-- lspconfig_setup(cfg)
-- _NG_LSPCfgSetup = true
-- end
log(ft, client, loaded) log(ft, client, loaded)
trace(cfg) trace(cfg)
if lspconfig[client] == nil then if lspconfig[client] == nil then
@ -377,7 +398,9 @@ local function load_cfg(ft, client, cfg, loaded)
end end
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 cmd = cfg.cmd local cmd = cfg.cmd
vim.list_extend(lspft, additional_ft)
local should_load = false local should_load = false
if lspft ~= nil and #lspft > 0 then if lspft ~= nil and #lspft > 0 then
@ -396,10 +419,10 @@ local function load_cfg(ft, client, cfg, loaded)
return return
end end
for _, c in pairs(loaded) do for k, c in pairs(loaded) do
if client == c then if client == k then
-- loaded -- loaded
trace(client, 'already been loaded for', ft, loaded) log(client, 'already been loaded for', ft, loaded, c)
return return
end end
end end
@ -414,16 +437,30 @@ local function load_cfg(ft, client, cfg, loaded)
-- log(lspconfig.available_servers()) -- log(lspconfig.available_servers())
-- force reload with config -- force reload with config
lspconfig[client].setup(cfg) lspconfig[client].setup(cfg)
vim.defer_fn(function()
vim.cmd([[doautocmd FileType ]] .. ft)
end, 100)
log(client, 'loading for', ft) log(client, 'loading for', ft)
end end
-- need to verify the lsp server is up -- need to verify the lsp server is up
end end
local function update_capabilities() local function setup_fmt(client, enabled)
if not require('navigator.util').nvim_0_8() then
if enabled == false then
client.resolved_capabilities.document_formatting = enabled
else
client.resolved_capabilities.document_formatting = client.resolved_capabilities.document_formatting or enabled
end
end
if enabled == false then
client.server_capabilities.documentFormattingProvider = false
else
client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider
or enabled
end
end
local function update_capabilities()
trace(vim.o.ft, 'lsp startup')
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
capabilities.textDocument.completion.completionItem.preselectSupport = true capabilities.textDocument.completion.completionItem.preselectSupport = true
@ -431,36 +468,36 @@ local function update_capabilities()
capabilities.textDocument.completion.completionItem.labelDetailsSupport = true capabilities.textDocument.completion.completionItem.labelDetailsSupport = true
capabilities.textDocument.completion.completionItem.deprecatedSupport = true capabilities.textDocument.completion.completionItem.deprecatedSupport = true
capabilities.textDocument.completion.completionItem.commitCharactersSupport = true capabilities.textDocument.completion.completionItem.commitCharactersSupport = true
-- capabilities.textDocument.completion.completionItem.tagSupport = { valueSet = { 1 } } capabilities.textDocument.completion.completionItem.tagSupport = { valueSet = { 1 } }
capabilities.textDocument.completion.completionItem.resolveSupport = { capabilities.textDocument.completion.completionItem.resolveSupport = {
properties = { 'documentation', 'detail', 'additionalTextEdits' }, properties = { 'documentation', 'detail', 'additionalTextEdits' },
} }
capabilities.workspace.configuration = true capabilities.workspace.configuration = true
return capabilities return capabilities
end end
-- run setup for lsp clients -- run setup for lsp clients
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 clients = vim.lsp.get_active_clients() or {}
local loaded = {}
local capabilities = update_capabilities() local capabilities = update_capabilities()
for _, client in ipairs(clients) do
if client ~= nil then
table.insert(loaded, client.name)
end
end
for _, lspclient in ipairs(servers) do for _, lspclient in ipairs(servers) do
local clients = vim.lsp.get_active_clients() or {}
for _, client in ipairs(clients) do
if client ~= nil then
loaded[client.name] = client.id
end
end
-- check should load lsp -- check should load lsp
if type(lspclient) == 'table' then if type(lspclient) == 'table' then
if lspclient.name then if lspclient.name then
lspclient = lspclient.name lspclient = lspclient.name
else else
warn('incorrect set for lspclient', vim.inspect(lspclient)) warn('incorrect set for lspclient' .. vim.inspect(lspclient))
goto continue goto continue
end end
end end
@ -477,22 +514,18 @@ local function lsp_startup(ft, retry, user_lsp_opts)
end end
end end
if _NG_Loaded[lspclient] then
log('client loaded', lspclient)
end
if vim.tbl_contains(config.lsp.disable_lsp or {}, lspclient) then if vim.tbl_contains(config.lsp.disable_lsp or {}, lspclient) then
log('disable lsp', lspclient) log('disable lsp', lspclient)
goto continue goto continue
end end
local default_config = {} local default_config = {}
log(lspclient)
if lspconfig[lspclient] == nil then if lspconfig[lspclient] == nil then
vim.notify( vim.notify(
'lspclient' .. vim.inspect(lspclient) .. 'no longer support by lspconfig, please submit an issue', 'lspclient' .. vim.inspect(lspclient) .. 'no longer support by lspconfig, please submit an issue',
vim.lsp.log_levels.WARN vim.lsp.log_levels.WARN
) )
log('lspclient', lspclient, 'not supported')
goto continue goto continue
end end
@ -505,15 +538,18 @@ local function lsp_startup(ft, retry, user_lsp_opts)
default_config = vim.tbl_deep_extend('force', default_config, ng_default_cfg) default_config = vim.tbl_deep_extend('force', default_config, ng_default_cfg)
local cfg = setups[lspclient] or {} local cfg = setups[lspclient] or {}
cfg = vim.tbl_deep_extend('keep', cfg, default_config) cfg = vim.tbl_deep_extend('keep', cfg, default_config)
-- filetype disabled -- filetype disabled
if not vim.tbl_contains(cfg.filetypes or {}, ft) then if not vim.tbl_contains(cfg.filetypes or {}, ft) then
trace('ft', ft, 'disabled for', lspclient) trace('ft', ft, 'disabled for', lspclient)
goto continue goto continue
end end
local disable_fmt = false local disable_fmt = false
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)
@ -526,19 +562,17 @@ local function lsp_startup(ft, retry, user_lsp_opts)
if user_lsp_opts[lspclient] ~= nil then if user_lsp_opts[lspclient] ~= nil then
-- log(lsp_opts[lspclient], cfg) -- log(lsp_opts[lspclient], cfg)
cfg = vim.tbl_deep_extend('force', cfg, user_lsp_opts[lspclient]) cfg = vim.tbl_deep_extend('force', cfg, user_lsp_opts[lspclient])
if config.combined_attach == nil then -- if config.combined_attach == nil then
cfg.on_attach = function(client, bufnr) -- setup_fmt(client, enable_fmt)
on_attach(client, bufnr) -- end
client.resolved_capabilities.document_formatting = enable_fmt
end
end
if config.combined_attach == 'mine' then if config.combined_attach == 'mine' then
if config.on_attach == nil then if config.on_attach == nil then
error('on attach not provided') error('on attach not provided')
end end
cfg.on_attach = function(client, bufnr) cfg.on_attach = function(client, bufnr)
config.on_attach(client, bufnr) config.on_attach(client, bufnr)
client.resolved_capabilities.document_formatting = enable_fmt
setup_fmt(client, enable_fmt)
require('navigator.lspclient.mapping').setup({ require('navigator.lspclient.mapping').setup({
client = client, client = client,
bufnr = bufnr, bufnr = bufnr,
@ -550,7 +584,7 @@ local function lsp_startup(ft, retry, user_lsp_opts)
cfg.on_attach = function(client, bufnr) cfg.on_attach = function(client, bufnr)
on_attach(client, bufnr) on_attach(client, bufnr)
config.on_attach(client, bufnr) config.on_attach(client, bufnr)
client.resolved_capabilities.document_formatting = enable_fmt setup_fmt(client, enable_fmt)
require('navigator.lspclient.mapping').setup({ require('navigator.lspclient.mapping').setup({
client = client, client = client,
bufnr = bufnr, bufnr = bufnr,
@ -560,7 +594,8 @@ local function lsp_startup(ft, retry, user_lsp_opts)
end end
if config.combined_attach == 'both' then if config.combined_attach == 'both' then
cfg.on_attach = function(client, bufnr) cfg.on_attach = function(client, bufnr)
client.resolved_capabilities.document_formatting = enable_fmt setup_fmt(client, enable_fmt)
if config.on_attach and type(config.on_attach) == 'function' then if config.on_attach and type(config.on_attach) == 'function' then
config.on_attach(client, bufnr) config.on_attach(client, bufnr)
end end
@ -588,7 +623,8 @@ local function lsp_startup(ft, retry, user_lsp_opts)
else else
cfg.on_attach = function(client, bufnr) cfg.on_attach = function(client, bufnr)
on_attach(client, bufnr) on_attach(client, bufnr)
client.resolved_capabilities.document_formatting = enable_fmt
setup_fmt(client, enable_fmt)
end end
end end
@ -597,21 +633,37 @@ local function lsp_startup(ft, retry, user_lsp_opts)
if has_lspinst and _NgConfigValues.lsp_installer then if has_lspinst and _NgConfigValues.lsp_installer then
local installed, installer_cfg = require('nvim-lsp-installer.servers').get_server(lspconfig[lspclient].name) local installed, installer_cfg = require('nvim-lsp-installer.servers').get_server(lspconfig[lspclient].name)
log('lsp installer server config' .. lspconfig[lspclient].name , installer_cfg) log('lsp installer server config ' .. lspconfig[lspclient].name, installer_cfg)
if installed and installer_cfg then if installed and installer_cfg then
log('options', installer_cfg:get_default_options()) local paths = installer_cfg:get_default_options().cmd_env.PATH
-- if cfg.cmd / {lsp_server_name, arg} not present or lsp_server_name is not in PATH paths = vim.split(paths, ':')
if vim.fn.empty(cfg.cmd) == 1 or vim.fn.executable(cfg.cmd[1] or '') == 0 then if vim.fn.empty(cfg.cmd) == 1 then
cfg.cmd = { installer_cfg.root_dir .. path_sep .. installer_cfg.name } cfg.cmd = { installer_cfg.name }
end
if vim.fn.executable(cfg.cmd[1]) == 0 then
for _, path in ipairs(paths) do
log(path)
if vim.fn.isdirectory(path) == 1 and string.find(path, installer_cfg.root_dir) then
cfg.cmd[1] = path .. path_sep .. cfg.cmd[1]
log(cfg.cmd)
break
end
end
log('update cmd', cfg.cmd) log('update cmd', cfg.cmd)
else
log('cmd installed', cfg.cmd)
end end
end end
end end
if vim.fn.executable(cfg.cmd[1]) == 0 then if vim.fn.executable(cfg.cmd[1]) == 0 then
vim.notify('lsp server not installed in path ' .. 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
log('client loaded ?', lspclient)
end
load_cfg(ft, lspclient, cfg, loaded) load_cfg(ft, lspclient, cfg, loaded)
_NG_Loaded[lspclient] = true _NG_Loaded[lspclient] = true
@ -629,7 +681,7 @@ local function lsp_startup(ft, retry, user_lsp_opts)
end, 1000) end, 1000)
log('null-ls loading') log('null-ls loading')
_NG_Loaded['null-ls'] = true _NG_Loaded['null-ls'] = true
configs['null-ls'] = cfg setups['null-ls'] = cfg
end end
end end
@ -648,7 +700,7 @@ local function lsp_startup(ft, retry, user_lsp_opts)
lspconfig.efm.setup(cfg) lspconfig.efm.setup(cfg)
log('efm loading') log('efm loading')
_NG_Loaded['efm'] = true _NG_Loaded['efm'] = true
configs['efm'] = cfg setups['efm'] = cfg
end end
end end
@ -657,6 +709,12 @@ local function lsp_startup(ft, retry, user_lsp_opts)
end end
end end
-- append lsps to servers
local function add_servers(lsps)
vim.validate({ lsps = { lsps, 't' } })
vim.list_extend(servers, lsps)
end
local function get_cfg(client) local function get_cfg(client)
local ng_cfg = ng_default_cfg local ng_cfg = ng_default_cfg
if setups[client] ~= nil then if setups[client] ~= nil then
@ -668,78 +726,76 @@ local function get_cfg(client)
end end
end end
local function setup(user_opts) local function ft_disabled(ft)
local ft = vim.bo.filetype for i = 1, #disabled_ft do
if ft == disabled_ft[i] then
return true
end
end
end
local function setup(user_opts, cnt)
user_opts = user_opts or {}
local ft = vim.bo.filetype
local bufnr = user_opts.bufnr or vim.api.nvim_get_current_buf() local bufnr = user_opts.bufnr or vim.api.nvim_get_current_buf()
if ft == '' or ft == nil then
log('nil filetype, callback')
local ext = vim.fn.expand('%:e')
if ext ~= '' then
cnt = cnt or 0
local opts = vim.deepcopy(user_opts)
if cnt > 3 then
log('failed to load filetype, skip')
return
else
cnt = cnt + 1
end
vim.defer_fn(function()
log('defer_fn', ext, ft)
setup(opts, cnt)
end, 200)
return
else
log('no filetype, no ext return')
return
end
end
local uri = vim.uri_from_bufnr(bufnr) local uri = vim.uri_from_bufnr(bufnr)
if uri == 'file://' or uri == 'file:///' then if uri == 'file://' or uri == 'file:///' then
log('skip loading for ft ', ft, uri) log('skip loading for ft ', ft, uri)
return return
end end
log(user_opts) if _LoadedFiletypes[ft .. tostring(bufnr)] == true then
log(uri) log('navigator was loaded for ft', ft, bufnr)
if _LoadedFiletypes[ft .. tostring(bufnr)] then
log('navigator was loaded for ft', ft)
return return
end end
local disable_ft = {
'NvimTree',
'guihua',
'clap_input',
'clap_spinner',
'vista',
'vista_kind',
'TelescopePrompt',
'guihua_rust',
'csv',
'txt',
'defx',
'packer',
'gitcommit',
}
for i = 1, #disable_ft do
if ft == disable_ft[i] or _LoadedFiletypes[ft] then
trace('navigator disabled for ft or it is loaded', ft)
return
end
end
if user_opts ~= nil then if ft_disabled(ft) then
log('navigator user setup', user_opts) trace('navigator disabled for ft or it is loaded', ft)
else return
user_opts = {} end
if _NgConfigValues.lsp.servers then
add_servers(_NgConfigValues.lsp.servers)
_NgConfigValues.lsp.servers = nil
end end
trace(debug.traceback()) trace(debug.traceback())
local clients = vim.lsp.buf_get_clients(bufnr) local clients = vim.lsp.buf_get_clients(bufnr)
for key, client in pairs(clients) do for key, client in pairs(clients) do
if client.name ~= "null_ls" and client.name ~= "efm" then if client.name ~= 'null_ls' and client.name ~= 'efm' then
if vim.tbl_contains(client.filetypes, vim.o.ft) then if vim.tbl_contains(client.filetypes or {}, vim.o.ft) then
log('client already loaded', client.name) log('client already loaded', client.name)
end end
end end
end end
_LoadedFiletypes[ft] = true user_opts = vim.tbl_extend('keep', user_opts, config) -- incase setup was triggered from autocmd
user_opts = vim.list_extend(user_opts, config) -- incase setup was triggered from autocmd
if ft == nil then
ft = vim.api.nvim_buf_get_option(bufnr, 'filetype')
end
if ft == nil or ft == '' then log('running lsp setup', ft, bufnr)
log('nil filetype, callback')
vim.cmd([[e]])
vim.defer_fn(function()
setup(user_opts)
end, 200)
return
end
local retry = true local retry = true
trace('setup', user_opts)
log('loading for ft ', ft, uri) log('loading for ft ', ft, uri)
highlight.diagnositc_config_sign() highlight.diagnositc_config_sign()
highlight.add_highlight() highlight.add_highlight()
@ -762,17 +818,12 @@ local function setup(user_opts)
lsp_startup(ft, retry, lsp_opts) lsp_startup(ft, retry, lsp_opts)
--- if code line enabled --- if code lens enabled
if _NgConfigValues.lsp.code_lens then if _NgConfigValues.lsp.code_lens_action.enable then
require('navigator.codelens').setup() require('navigator.codelens').setup()
end end
end -- _LoadedFiletypes[ft .. tostring(bufnr)] = true -- may prevent lsp config when reboot lsp
-- append lsps to servers
local function add_servers(lsps)
vim.validate({ lsps = { lsps, 't' } })
vim.list_extend(servers, lsps)
end end
local function on_filetype() local function on_filetype()
@ -794,7 +845,15 @@ local function on_filetype()
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 })
end end
return { setup = setup, get_cfg = get_cfg, lsp = servers, add_servers = add_servers, on_filetype = on_filetype } return {
setup = setup,
get_cfg = get_cfg,
lsp = servers,
add_servers = add_servers,
on_filetype = on_filetype,
disabled_ft = disabled_ft,
ft_disabled = ft_disabled,
}

@ -1,6 +1,6 @@
local lsp = require("vim.lsp") local lsp = require("vim.lsp")
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

@ -1,6 +1,6 @@
local M = {} local M = {}
local log = require"navigator.util".log -- local log = require('navigator.util').log
local api = vim.api local api = vim.api
-- lsp sign          ﮻         ﯭ        ﳀ   -- lsp sign          ﮻         ﯭ        ﳀ  
@ -10,80 +10,56 @@ function M.diagnositc_config_sign()
end end
local icons = _NgConfigValues.icons local icons = _NgConfigValues.icons
local sign_name = "NavigatorLightBulb" local sign_name = 'NavigatorLightBulb'
if vim.fn.sign_getdefined(sign_name).text == nil then if vim.fn.sign_getdefined(sign_name).text == nil then
vim.fn.sign_define(sign_name, { text = icons.code_action_icon, texthl = 'LspDiagnosticsSignHint' })
vim.fn sign_name = 'NavigatorCodeLensLightBulb'
.sign_define(sign_name, {text = icons.code_action_icon, texthl = "LspDiagnosticsSignHint"}) vim.fn.sign_define(sign_name, { text = icons.code_lens_action_icon, texthl = 'LspDiagnosticsSignHint' })
sign_name = "NavigatorCodeLensLightBulb"
vim.fn.sign_define(sign_name,
{text = icons.code_lens_action_icon, texthl = "LspDiagnosticsSignHint"})
end end
local e, w, i, h = icons.diagnostic_err, icons.diagnostic_warn, icons.diagnostic_info, local e, w, i, h = icons.diagnostic_err, icons.diagnostic_warn, icons.diagnostic_info, icons.diagnostic_hint
icons.diagnostic_hint local t = vim.fn.sign_getdefined('DiagnosticSignWarn')
if vim.diagnostic ~= nil then if vim.tbl_isempty(t) or t[1].text == 'W ' and icons.icons == true then
local t = vim.fn.sign_getdefined('DiagnosticSignWarn') vim.fn.sign_define('DiagnosticSignError', { text = e, texthl = 'DiagnosticError', linehl = '', numhl = '' })
if (vim.tbl_isempty(t) or t[1].text == "W ") and icons.icons == true then vim.fn.sign_define('DiagnosticSignWarn', { text = w, texthl = 'DiagnosticWarn', linehl = '', numhl = '' })
vim.fn.sign_define('DiagnosticSignInfo', { text = i, texthl = 'DiagnosticInfo', linehl = '', numhl = '' })
vim.fn.sign_define('DiagnosticSignError', vim.fn.sign_define('DiagnosticSignHint', { text = h, texthl = 'DiagnosticHint', linehl = '', numhl = '' })
{text = e, texthl = 'DiagnosticError', linehl = '', numhl = ''})
vim.fn.sign_define('DiagnosticSignWarn',
{text = w, texthl = 'DiagnosticWarn', linehl = '', numhl = ''})
vim.fn.sign_define('DiagnosticSignInfo',
{text = i, texthl = 'DiagnosticInfo', linehl = '', numhl = ''})
vim.fn.sign_define('DiagnosticSignHint',
{text = h, texthl = 'DiagnosticHint', linehl = '', numhl = ''})
t = vim.fn.sign_getdefined('DiagnosticSignWarn') t = vim.fn.sign_getdefined('DiagnosticSignWarn')
end
else
local t = vim.fn.sign_getdefined('LspDiagnosticSignWarn')
if (vim.tbl_isempty(t) or t[1].text == "W ") and icons.icons == true then
vim.fn.sign_define('LspDiagnosticsSignError',
{text = e, texthl = 'LspDiagnosticsSignError', linehl = '', numhl = ''})
vim.fn.sign_define('LspDiagnosticsSignWarning',
{text = w, texthl = 'LspDiagnosticsSignWarning', linehl = '', numhl = ''})
vim.fn.sign_define('LspDiagnosticsSignInformation', {
text = i,
texthl = 'LspDiagnosticsSignInformation',
linehl = '',
numhl = ''
})
vim.fn.sign_define('LspDiagnosticsSignHint',
{text = h, texthl = 'LspDiagnosticsSignHint', linehl = '', numhl = ''})
end
end end
M.configed = true M.configed = true
end end
function M.add_highlight() function M.add_highlight()
-- lsp system default -- lsp system default
api.nvim_command("hi! link LspDiagnosticsUnderlineError SpellBad") api.nvim_command('hi! link DiagnosticUnderlineError SpellBad')
api.nvim_command("hi! link LspDiagnosticsUnderlineWarning SpellRare") api.nvim_command('hi! link DiagnosticUnderlineWarning SpellRare')
api.nvim_command("hi! link LspDiagnosticsUnderlineInformation SpellRare") api.nvim_command('hi! link DiagnosticUnderlineInformation SpellRare')
api.nvim_command("hi! link LspDiagnosticsUnderlineHint SpellRare") api.nvim_command('hi! link DiagnosticUnderlineHint SpellRare')
api.nvim_command('hi def link NGPreviewTitle Title')
api.nvim_command("hi! link DiagnosticUnderlineError SpellBad")
api.nvim_command("hi! link DiagnosticUnderlineWarning SpellRare")
api.nvim_command("hi! link DiagnosticUnderlineInformation SpellRare")
api.nvim_command("hi! link DiagnosticUnderlineHint SpellRare")
api.nvim_command("hi def link NGPreviewTitle Title")
local colors = { local colors = {
{'#aefe00', '#aede00', '#aebe00', '#4e7efe'}, {'#ff00e0', '#df00e0', '#af00e0', '#fedefe'}, { '#aefe00', '#aede00', '#aebe00', '#4e7efe' },
{'#1000ef', '#2000df', '#2000cf', '#f0f040'}, {'#d8a8a3', '#c8a8a3', '#b8a8a3', '#4e2c33'}, { '#ff00e0', '#df00e0', '#af00e0', '#fedefe' },
{'#ffa724', '#efa024', '#dfa724', '#0040ff'}, {'#afdc2b', '#09dc4b', '#08d04b', '#ef4f8f'} { '#1000ef', '#2000df', '#2000cf', '#f0f040' },
{ '#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, local cmd = string.format('hi! default NGHiReference_%i_%i guibg=%s guifg=%s ', i, j, colors[i][j], colors[i][4])
colors[i][j], colors[i][4])
vim.cmd(cmd) vim.cmd(cmd)
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
return M return M

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

@ -1,6 +1,6 @@
local log = require('navigator.util').log local util = require('navigator.util')
local trace = require('navigator.util').trace local log = util.log
local trace = util.trace
local event_hdlrs = { local event_hdlrs = {
{ ev = 'BufWritePre', func = [[require "navigator.diagnostics".set_diag_loclist()]] }, { ev = 'BufWritePre', func = [[require "navigator.diagnostics".set_diag_loclist()]] },
{ ev = 'CursorHold', func = 'document_highlight()' }, { ev = 'CursorHold', func = 'document_highlight()' },
@ -8,26 +8,34 @@ local event_hdlrs = {
{ ev = 'CursorMoved', func = 'clear_references()' }, { ev = 'CursorMoved', func = 'clear_references()' },
} }
if vim.lsp.buf.format == nil then
vim.lsp.buf.format = vim.lsp.buf.formatting
end
if vim.diagnostic == nil then
util.error('Please update nvim to 0.6.1+')
end
local double = { '', '', '', '', '', '', '', '' } local double = { '', '', '', '', '', '', '', '' }
local single = { '', '', '', '', '', '', '', '' } 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').reference()" }, { key = 'gr', func = "require('navigator.reference').async_ref()" },
{ key = 'Gr', func = "require('navigator.reference').async_ref()" }, { key = '<Leader>gr', func = "require('navigator.reference').reference()" }, -- reference deprecated
{ mode = 'i', key = '<M-k>', func = 'signature_help()' }, { mode = 'i', key = '<M-k>', func = 'signature_help()' },
{ key = '<c-k>', func = 'signature_help()' }, { key = '<c-k>', func = 'signature_help()' },
{ key = 'g0', func = "require('navigator.symbols').document_symbols()" }, { key = 'g0', func = "require('navigator.symbols').document_symbols()" },
{ key = 'gW', func = "require('navigator.workspace').workspace_symbol()" }, { key = 'gW', func = "require('navigator.workspace').workspace_symbol_live()" },
{ key = '<c-]>', func = "require('navigator.definition').definition()" }, { key = '<c-]>', func = "require('navigator.definition').definition()" },
{ key = 'gd', func = "require('navigator.definition').definition()" }, { key = 'gd', func = "require('navigator.definition').definition()" },
{ key = 'gD', func = "declaration({ border = 'rounded', max_width = 80 })" }, { key = 'gD', func = "declaration({ border = 'rounded', max_width = 80 })" },
{ key = 'gp', func = "require('navigator.definition').definition_preview()" }, { key = 'gp', func = "require('navigator.definition').definition_preview()" },
{ key = '<Leader>gt', func = "require('navigator.treesitter').buf_ts()" }, { key = '<Leader>gt', func = "require('navigator.treesitter').buf_ts()" },
{ key = '<Leader>gT', func = "require('navigator.treesitter').bufs_ts()" }, { key = '<Leader>gT', func = "require('navigator.treesitter').bufs_ts()" },
{ key = '<Leader>ct', func = "require('navigator.ctags').ctags()" },
{ key = 'K', func = 'hover({ popup_opts = { border = single, max_width = 80 }})' }, { key = 'K', func = 'hover({ popup_opts = { border = single, max_width = 80 }})' },
{ key = '<Space>ca', mode = 'n', func = "require('navigator.codeAction').code_action()" }, { key = '<Space>ca', mode = 'n', func = "require('navigator.codeAction').code_action()" },
{ key = '<Space>cA', mode = 'v', func = 'range_code_action()' }, { key = '<Space>ca', mode = 'v', func = "require('navigator.codeAction').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()" },
{ key = '<Leader>gi', func = 'incoming_calls()' }, { key = '<Leader>gi', func = 'incoming_calls()' },
@ -39,6 +47,7 @@ local key_maps = {
{ key = '<Leader>dt', func = "require('navigator.diagnostics').toggle_diagnostics()" }, { key = '<Leader>dt', func = "require('navigator.diagnostics').toggle_diagnostics()" },
{ key = ']d', func = "diagnostic.goto_next({ border = 'rounded', max_width = 80})" }, { key = ']d', func = "diagnostic.goto_next({ border = 'rounded', max_width = 80})" },
{ key = '[d', func = "diagnostic.goto_prev({ border = 'rounded', max_width = 80})" }, { key = '[d', func = "diagnostic.goto_prev({ border = 'rounded', max_width = 80})" },
{ key = ']O', func = 'diagnostic.set_loclist()' },
{ key = ']r', func = "require('navigator.treesitter').goto_next_usage()" }, { key = ']r', func = "require('navigator.treesitter').goto_next_usage()" },
{ key = '[r', func = "require('navigator.treesitter').goto_previous_usage()" }, { key = '[r', func = "require('navigator.treesitter').goto_previous_usage()" },
{ key = '<C-LeftMouse>', func = 'definition()' }, { key = '<C-LeftMouse>', func = 'definition()' },
@ -46,12 +55,23 @@ local key_maps = {
{ key = '<Leader>k', func = "require('navigator.dochighlight').hi_symbol()" }, { key = '<Leader>k', func = "require('navigator.dochighlight').hi_symbol()" },
{ key = '<Space>wa', func = "require('navigator.workspace').add_workspace_folder()" }, { key = '<Space>wa', func = "require('navigator.workspace').add_workspace_folder()" },
{ key = '<Space>wr', func = "require('navigator.workspace').remove_workspace_folder()" }, { key = '<Space>wr', func = "require('navigator.workspace').remove_workspace_folder()" },
{ key = '<Space>ff', func = 'formatting()', mode = 'n' }, { key = '<Space>ff', func = 'format({async = true})', mode = 'n' },
{ key = '<Space>ff', func = 'range_formatting()', mode = 'v' }, { key = '<Space>ff', func = 'range_formatting()', mode = 'v' },
{ key = '<Space>wl', func = "require('navigator.workspace').list_workspace_folders()" }, { key = '<Space>wl', func = "require('navigator.workspace').list_workspace_folders()" },
{ key = '<Space>la', mode = 'n', func = "require('navigator.codelens').run_action()" }, { key = '<Space>la', mode = 'n', func = "require('navigator.codelens').run_action()" },
} }
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=* Calltree lua require'navigator.hierarchy'.calltree(<f-args>)<CR>",
}
local key_maps_help = {} local key_maps_help = {}
-- LuaFormatter on -- LuaFormatter on
local M = {} local M = {}
@ -61,22 +81,28 @@ local ccls_mappings = {
{ key = '<Leader>go', func = "require('navigator.cclshierarchy').outgoing_calls()" }, { key = '<Leader>go', func = "require('navigator.cclshierarchy').outgoing_calls()" },
} }
local check_cap = function(cap) local check_cap = function(opts)
-- log(vim.lsp.buf_get_clients(0)) -- log(vim.lsp.buf_get_clients(0))
local fmt, rfmt, ccls local fmt, rfmt, ccls
if cap and cap.document_formatting then local cap = opts.cap
if cap == nil then
if opts.client and opts.client.server_capabilities then
cap = opts.client.server_capabilities
end
end
if cap and cap.documentFormattingProvider then
fmt = true fmt = true
end end
if cap and cap.document_range_formatting then if cap and cap.documentRangeFormattingProvider then
rfmt = true rfmt = true
end end
for _, value in pairs(vim.lsp.buf_get_clients(0)) do for _, value in pairs(vim.lsp.buf_get_clients(0)) do
trace(value) trace(value)
if value ~= nil and value.resolved_capabilities == nil then if value ~= nil and value.server_capabilities == nil then
if value.resolved_capabilities.document_formatting then if value.server_capabilities.documentFormattingProvider then
fmt = true fmt = true
end end
if value.resolved_capabilities.document_range_formatting then if value.server_capabilities.documentRangeFormattingProvider then
rfmt = true rfmt = true
end end
@ -89,13 +115,23 @@ local check_cap = function(cap)
return fmt, rfmt, ccls return fmt, rfmt, ccls
end end
local function set_mapping(user_opts) local function set_cmds(_)
log('setup mapping') for _, value in pairs(commands) do
local opts = { noremap = true, silent = true } vim.cmd(value)
user_opts = user_opts or {} end
end
-- should works for both 1)attach from known lsp client or from a disabled lsp client
local function set_mapping(lsp_attach_info)
local opts = { noremap = true, silent = true }
vim.validate({
lsp_attach_info = { lsp_attach_info, 'table' },
})
if _NgConfigValues.debug then
log('setup mapping for client', lsp_attach_info.client.name, lsp_attach_info.client.cmd)
end
local user_key = _NgConfigValues.keymaps or {} local user_key = _NgConfigValues.keymaps or {}
local bufnr = user_opts.bufnr or 0 local bufnr = lsp_attach_info.bufnr or 0
local function del_keymap(...) local function del_keymap(...)
vim.api.nvim_buf_del_keymap(bufnr, ...) vim.api.nvim_buf_del_keymap(bufnr, ...)
@ -107,7 +143,7 @@ local function set_mapping(user_opts)
-- 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
local doc_fmt, range_fmt, ccls = check_cap(user_opts.cap) local doc_fmt, range_fmt, ccls = check_cap(lsp_attach_info)
if ccls then if ccls then
vim.list_extend(key_maps, ccls_mappings) vim.list_extend(key_maps, ccls_mappings)
@ -134,25 +170,23 @@ local function set_mapping(user_opts)
local fmtkey, rfmtkey local fmtkey, rfmtkey
for _, value in pairs(key_maps) do for _, value in pairs(key_maps) do
local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>' local f = '<Cmd>lua vim.lsp.buf.' .. value.func .. '<CR>'
if string.find(value.func, 'require') then if string.find(value.func, 'require') or string.find(value.func, 'vim.') then
f = '<Cmd>lua ' .. value.func .. '<CR>' f = '<Cmd>lua ' .. value.func .. '<CR>'
elseif string.find(value.func, 'diagnostic') then elseif string.find(value.func, 'diagnostic') then
local diagnostic = '<Cmd>lua vim.' local diagnostic = '<Cmd>lua vim.'
if vim.lsp.diagnostic ~= nil then diagnostic = '<Cmd>lua vim.'
diagnostic = '<Cmd>lua vim.lsp.'
end
f = diagnostic .. value.func .. '<CR>' f = diagnostic .. value.func .. '<CR>'
elseif string.find(value.func, 'vim.') then -- elseif string.find(value.func, 'vim.') then
f = '<Cmd>lua ' .. value.func .. '<CR>' -- f = '<Cmd>lua ' .. value.func .. '<string.find(value.func, 'vim.')CR>'
end end
local k = value.key local k = value.key
local m = value.mode or 'n' local m = value.mode or 'n'
if string.find(value.func, 'range_formatting') then if string.find(value.func, 'range_formatting') then
rfmtkey = value.key rfmtkey = value.key
elseif string.find(value.func, 'formatting') then elseif string.find(value.func, 'format') then
fmtkey = value.key fmtkey = value.key
end end
log('binding', k, f) trace('binding', k, f)
set_keymap(m, k, f, opts) set_keymap(m, k, f, opts)
end end
@ -166,24 +200,25 @@ local function set_mapping(user_opts)
vim.cmd([[ vim.cmd([[
aug NavigatorAuFormat aug NavigatorAuFormat
au! au!
autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting() autocmd BufWritePre <buffer> lua vim.lsp.buf.format({async = true})
aug END aug END
]]) ]])
elseif fmtkey then elseif fmtkey then
del_keymap('n', fmtkey) del_keymap('n', fmtkey)
end end
if user_opts.cap and user_opts.cap.document_range_formatting then
log('formatting enabled', user_opts.cap) if lsp_attach_info.cap and lsp_attach_info.cap.document_range_formatting then
log('formatting enabled', lsp_attach_info.cap)
end end
if not range_fmt and rfmtkey then if not range_fmt and rfmtkey then
del_keymap('v', rfmtkey) del_keymap('v', rfmtkey)
end end
log('enable format ', doc_fmt, range_fmt) log('enable format ', doc_fmt, range_fmt, _NgConfigValues.lsp.format_on_save)
end end
local function autocmd(user_opts) local function autocmd()
vim.api.nvim_exec( vim.api.nvim_exec(
[[ [[
aug NavigatorDocHlAu aug NavigatorDocHlAu
@ -240,17 +275,26 @@ M.toggle_lspformat = function(on)
end end
end end
function M.setup(user_opts) function M.setup(attach_opts)
user_opts = user_opts or _NgConfigValues if not attach_opts or not attach_opts.client then
set_mapping(user_opts) vim.notify(
'please call require"navigator.mapping".setup({bufnr=bufnr, client=client}) inside on_attach(client,bufnr)',
vim.lsp.log_levels.WARN
)
end
attach_opts = attach_opts or { bufnr = 0, client = {}, cap = {} }
set_mapping(attach_opts)
set_cmds(attach_opts)
autocmd(user_opts) autocmd()
set_event_handler(user_opts) set_event_handler(attach_opts)
local cap = user_opts.cap or vim.lsp.protocol.make_client_capabilities() local client = attach_opts.client or {}
log('lsp cap:', cap) local cap = client.server_capabilities or vim.lsp.protocol.make_client_capabilities()
if cap.call_hierarchy or cap.callHierarchy then log('lsp cap:', cap.codeActionProvider)
if cap.call_hierarchy or cap.callHierarchyProvider then
vim.lsp.handlers['callHierarchy/incomingCalls'] = require('navigator.hierarchy').incoming_calls_handler vim.lsp.handlers['callHierarchy/incomingCalls'] = require('navigator.hierarchy').incoming_calls_handler
vim.lsp.handlers['callHierarchy/outgoingCalls'] = require('navigator.hierarchy').outgoing_calls_handler vim.lsp.handlers['callHierarchy/outgoingCalls'] = require('navigator.hierarchy').outgoing_calls_handler
end end
@ -259,7 +303,7 @@ function M.setup(user_opts)
-- vim.lsp.handlers["textDocument/codeAction"] = require"navigator.codeAction".code_action_handler -- vim.lsp.handlers["textDocument/codeAction"] = require"navigator.codeAction".code_action_handler
vim.lsp.handlers['textDocument/definition'] = require('navigator.definition').definition_handler vim.lsp.handlers['textDocument/definition'] = require('navigator.definition').definition_handler
if cap.declaration then if cap.declarationProvider then
vim.lsp.handlers['textDocument/declaration'] = require('navigator.definition').declaration_handler vim.lsp.handlers['textDocument/declaration'] = require('navigator.definition').declaration_handler
end end
@ -286,8 +330,12 @@ function M.setup(user_opts)
}) })
end end
vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = single }) local border_style = single
if cap.document_formatting then if _NgConfigValues.border == 'double' then
border_style = double
end
vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = border_style })
if cap.documentFormattingProvider then
log('formatting enabled setup hdl') log('formatting enabled setup hdl')
vim.lsp.handlers['textDocument/formatting'] = require('navigator.formatting').format_hdl vim.lsp.handlers['textDocument/formatting'] = require('navigator.formatting').format_hdl
end end

@ -1,7 +1,6 @@
local M = {} local M = {}
local util = require('navigator.util') local util = require('navigator.util')
local nvim_0_6 = util.nvim_0_6()
local gutil = require('guihua.util') local gutil = require('guihua.util')
local lsp = require('vim.lsp') local lsp = require('vim.lsp')
@ -75,7 +74,8 @@ end
function M.symbols_to_items(result) function M.symbols_to_items(result)
local locations = {} local locations = {}
-- log(result) result = result or {}
log(#result)
for i = 1, #result do for i = 1, #result do
local item = result[i].location local item = result[i].location
if item ~= nil and item.range ~= nil then if item ~= nil and item.range ~= nil then
@ -87,8 +87,9 @@ function M.symbols_to_items(result)
if kind ~= nil then if kind ~= nil then
item.text = kind .. ': ' .. item.text item.text = kind .. ': ' .. item.text
end end
item.filename = vim.uri_to_fname(item.uri) if not item.filename then
item.filename = vim.uri_to_fname(item.uri)
end
item.display_filename = item.filename:gsub(cwd .. path_sep, path_cur, 1) item.display_filename = item.filename:gsub(cwd .. path_sep, path_cur, 1)
if item.range == nil or item.range.start == nil then if item.range == nil or item.range.start == nil then
log('range not set', result[i], item) log('range not set', result[i], item)
@ -122,7 +123,8 @@ function M.check_capabilities(feature, client_id)
local supported_client = false local supported_client = false
for _, client in pairs(clients) do for _, client in pairs(clients) do
supported_client = client.resolved_capabilities[feature] -- supported_client = client.resolved_capabilities[feature]
supported_client = client.server_capabilities[feature]
if supported_client then if supported_client then
break break
end end
@ -143,26 +145,24 @@ end
function M.call_sync(method, params, opts, handler) function M.call_sync(method, params, opts, handler)
params = params or {} params = params or {}
opts = opts or {} opts = opts or {}
local results_lsp, err = lsp.buf_request_sync(0, method, params, opts.timeout or vim.g.navtator_timeout or 1000) log(method, params)
local results_lsp, err = lsp.buf_request_sync(opts.bufnr or 0, method, params, opts.timeout or 1000)
if nvim_0_6() then return handler(err, extract_result(results_lsp), { method = method, no_show = opts.no_show }, nil)
handler(err, extract_result(results_lsp), { method = method }, nil)
else
handler(err, method, extract_result(results_lsp), nil, nil)
end
end end
function M.call_async(method, params, handler) function M.call_async(method, params, handler, bufnr)
params = params or {} params = params or {}
local callback = function(...) local callback = function(...)
util.show(...) util.show(...)
handler(...) handler(...)
end end
return lsp.buf_request(0, method, params, callback) bufnr = bufnr or 0
return lsp.buf_request(bufnr, method, params, callback)
-- results_lsp, canceller -- results_lsp, canceller
end end
local function ts_functions(uri) local function ts_functions(uri, optional)
local unload_bufnr local unload_bufnr
local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals') local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals')
if not ts_enabled or not TS_analysis_enabled then if not ts_enabled or not TS_analysis_enabled then
@ -187,6 +187,9 @@ local function ts_functions(uri)
ts_nodes_time:delete(uri) ts_nodes_time:delete(uri)
end end
end end
if optional then
return
end
local unload = false local unload = false
if not api.nvim_buf_is_loaded(bufnr) then if not api.nvim_buf_is_loaded(bufnr) then
trace('! load buf !', uri, bufnr) trace('! load buf !', uri, bufnr)
@ -206,7 +209,7 @@ local function ts_functions(uri)
return funcs, unload_bufnr return funcs, unload_bufnr
end end
local function ts_definition(uri, range) local function ts_definition(uri, range, optional)
local unload_bufnr local unload_bufnr
local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals') local ts_enabled, _ = pcall(require, 'nvim-treesitter.locals')
if not ts_enabled or not TS_analysis_enabled then if not ts_enabled or not TS_analysis_enabled then
@ -224,6 +227,9 @@ local function ts_definition(uri, range)
log('ts def from cache') log('ts def from cache')
return tsnodes return tsnodes
end end
if optional then
return
end
local ts_def = require('navigator.treesitter').find_definition local ts_def = require('navigator.treesitter').find_definition
local bufnr = vim.uri_to_bufnr(uri) local bufnr = vim.uri_to_bufnr(uri)
local x = os.clock() local x = os.clock()
@ -263,6 +269,10 @@ end
local function order_locations(locations) local function order_locations(locations)
table.sort(locations, function(i, j) table.sort(locations, function(i, j)
if i == nil or j == nil or i.uri == nil or j.uri == nil then
-- log(i, j)
return false
end
if i.uri == j.uri then if i.uri == j.uri then
if i.range and i.range.start then if i.range and i.range.start then
return i.range.start.line < j.range.start.line return i.range.start.line < j.range.start.line
@ -294,20 +304,27 @@ local function slice_locations(locations, max_items)
return first_part, second_part return first_part, second_part
end end
local function test_locations() -- local function test_locations()
local locations = { -- local locations = {
{ uri = '1', range = { start = { line = 1 } } }, -- { uri = '1', range = { start = { line = 1 } } },
{ uri = '2', range = { start = { line = 2 } } }, -- { uri = '2', range = { start = { line = 2 } } },
{ uri = '2', range = { start = { line = 3 } } }, -- { uri = '2', range = { start = { line = 3 } } },
{ uri = '1', range = { start = { line = 3 } } }, -- { uri = '1', range = { start = { line = 3 } } },
{ uri = '1', range = { start = { line = 4 } } }, -- { uri = '1', range = { start = { line = 4 } } },
{ uri = '3', range = { start = { line = 4 } } }, -- { uri = '3', range = { start = { line = 4 } } },
{ uri = '3', range = { start = { line = 4 } } }, -- { uri = '3', range = { start = { line = 4 } } },
} -- }
local second_part -- local second_part
order_locations(locations) -- order_locations(locations)
local locations, second_part = slice_locations(locations, 3) -- local locations, second_part = slice_locations(locations, 3)
log(locations, second_part) -- log(locations, second_part)
-- end
local function ts_optional(i, unload_buf_size)
if unload_buf_size then
return unload_buf_size > _NgConfigValues.treesitter_analysis_max_num
end
return i > _NgConfigValues.treesitter_analysis_max_num
end end
function M.locations_to_items(locations, ctx) function M.locations_to_items(locations, ctx)
@ -337,9 +354,9 @@ function M.locations_to_items(locations, ctx)
for i, loc in ipairs(locations) do for i, loc in ipairs(locations) do
local funcs = nil local funcs = nil
local item = lsp.util.locations_to_items({ loc }, enc)[1] local item = lsp.util.locations_to_items({ loc }, enc)[1]
-- log(item)
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
item.definition = locations[i].definition
if is_win then if is_win then
log(item.uri) -- file:///C:/path/to/file log(item.uri) -- file:///C:/path/to/file
@ -349,14 +366,14 @@ function M.locations_to_items(locations, ctx)
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 < 30
local unload, def local unload, def
if TS_analysis_enabled and proj_file then if TS_analysis_enabled and proj_file then
funcs, unload = ts_functions(item.uri) funcs, unload = ts_functions(item.uri, ts_optional(i, #unload_bufnrs))
if unload then if unload then
table.insert(unload_bufnrs, unload) table.insert(unload_bufnrs, unload)
end end
if not uri_def[item.uri] then if not uri_def[item.uri] then
-- find def in file -- find def in file
def, unload = ts_definition(item.uri, item.range) def, unload = ts_definition(item.uri, item.range, ts_optional(i, #unload_bufnrs))
if def and def.start then if def and def.start then
uri_def[item.uri] = def uri_def[item.uri] = def
if def.start then -- find for the 1st time if def.start then -- find for the 1st time
@ -416,7 +433,8 @@ function M.locations_to_items(locations, ctx)
vim.cmd([[set eventignore-=FileType]]) vim.cmd([[set eventignore-=FileType]])
return items, width + 24, second_part -- TODO handle long line? trace(items)
return items, width + 30, second_part -- TODO handle long line?
end end
function M.symbol_to_items(locations) function M.symbol_to_items(locations)
@ -431,6 +449,9 @@ function M.symbol_to_items(locations)
if i.definition then if i.definition then
return true return true
end end
if j.definition then
return false
end
if i.uri == j.uri then if i.uri == j.uri then
if i.range and i.range.start then if i.range and i.range.start then
return i.range.start.line < j.range.start.line return i.range.start.line < j.range.start.line
@ -458,7 +479,7 @@ end
function M.request(method, hdlr) -- e.g textDocument/reference function M.request(method, hdlr) -- e.g textDocument/reference
local bufnr = vim.api.nvim_get_current_buf() local bufnr = 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, client_id, _bufnr) vim.lsp.for_each_buffer_client(bufnr, function(client, _, _)
client.request(method, ref_params, hdlr, bufnr) client.request(method, ref_params, hdlr, bufnr)
end) end)
end end

@ -1,11 +1,9 @@
local util = require('navigator.util') local util = require('navigator.util')
local mk_handler = util.mk_handler
local log = util.log local log = util.log
local lsphelper = require('navigator.lspwrapper') local lsphelper = require('navigator.lspwrapper')
local gui = require('navigator.gui') local gui = require('navigator.gui')
local lsp = require('navigator.lspwrapper') local lsp = require('navigator.lspwrapper')
local trace = require('navigator.util').trace local trace = require('navigator.util').trace
ListViewCtrl = ListViewCtrl or require('guihua.listviewctrl').ListViewCtrl
-- local partial = util.partial -- local partial = util.partial
-- local cwd = vim.loop.cwd() -- local cwd = vim.loop.cwd()
-- local lsphelper = require "navigator.lspwrapper" -- local lsphelper = require "navigator.lspwrapper"
@ -16,35 +14,51 @@ local ref_view = function(err, locations, ctx, cfg)
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)
trace(locations) log(#locations, locations[1])
if ctx.combine then if ctx.combine then
-- wait for both request -- wait for both reference and definition LSP request
if ctx.results == nil then if ctx.results == nil then
return return
end end
if #ctx.results.definitions.result == nil or ctx.results.references.result == nil then if (ctx.results.definitions == nil) or (ctx.results.references == nil) then
log('not all requests returned') log('not all requests returned')
return return
end end
local definitions = ctx.results.definitions local definitions = ctx.results.definitions
local references = ctx.results.references local references = ctx.results.references
if _NgConfigValues.debug then
local logctx = { results = {} }
logctx = vim.tbl_extend('keep', logctx, ctx)
log(logctx, 'result size', 'def', #ctx.results.definitions, 'ref', #ctx.results.references)
end
if definitions.error and references.error then if definitions.error and references.error then
vim.notify('lsp ref callback error' .. vim.inspect(ctx.result), vim.lsp.log_levels.WARN) vim.notify('lsp ref callback error' .. vim.inspect(ctx.result), vim.lsp.log_levels.WARN)
end end
locations = {} locations = {}
if definitions.result then if definitions and definitions.result then
for i, _ in ipairs(definitions.result) do for i, _ in ipairs(definitions.result) do
definitions.result[i].definition = true definitions.result[i].definition = true
end end
vim.list_extend(locations, definitions.result) vim.list_extend(locations, definitions.result)
end end
if references.result then if references and references.result and #references.result > 0 then
vim.list_extend(locations, 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)
end end
ctx = references.ctx or definitions.ctx
err = nil err = nil
cfg = references.config or definitions.config trace(locations)
trace(ctx, locations)
end end
-- log("num", num) -- log("num", num)
-- log("bfnr", bufnr) -- log("bfnr", bufnr)
@ -63,7 +77,7 @@ local ref_view = function(err, locations, ctx, cfg)
return return
end end
if locations == nil or vim.tbl_isempty(locations) then if locations == nil or vim.tbl_isempty(locations) then
vim.notify('References not found', vim.lsp.log_levels.WARN) vim.notify('References not found', vim.lsp.log_levels.INFO)
return return
end end
@ -101,11 +115,13 @@ local ref_view = function(err, locations, ctx, cfg)
if vim.tbl_isempty(second_part) then if vim.tbl_isempty(second_part) then
return return
end end
ctx.max_items = #second_part
local items2 = locations_to_items(second_part, ctx) local items2 = locations_to_items(second_part, ctx)
vim.list_extend(thread_items, items2) vim.list_extend(thread_items, items2)
local data = require('navigator.render').prepare_for_render(thread_items, opts) local data = require('navigator.render').prepare_for_render(thread_items, opts)
log('thread data size', #data)
listview.ctrl:on_data_update(data) listview.ctrl:on_data_update(data)
if nv_ref_async then if nv_ref_async then
vim.loop.close(nv_ref_async) vim.loop.close(nv_ref_async)
@ -123,7 +139,7 @@ local ref_view = function(err, locations, ctx, cfg)
return listview, items, width return listview, items, width
end end
local ref_hdlr = mk_handler(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)
M.async_hdlr = vim.loop.new_async(vim.schedule_wrap(function() M.async_hdlr = vim.loop.new_async(vim.schedule_wrap(function()
@ -133,21 +149,36 @@ local ref_hdlr = mk_handler(function(err, locations, ctx, cfg)
end end
end)) end))
M.async_hdlr:send() M.async_hdlr:send()
end) end
local async_ref = function() local async_ref = function()
local ref_params = vim.lsp.util.make_position_params() local ref_params = vim.lsp.util.make_position_params()
local results = { definitions = {}, references = {} } local results = {}
ref_params.context = { includeDeclaration = false }
lsp.call_async('textDocument/definition', ref_params, function(err, result, ctx, config) lsp.call_async('textDocument/definition', ref_params, function(err, result, ctx, config)
trace(err, result, ctx, config) trace(err, result, ctx, config)
if err ~= nil or result == nil then
log('failed to get def', err, result, ctx, config)
result = {}
end
for i = 1, #result do
if result[i].range == nil and result[i].targetRange then
result[i].range = result[i].targetRange
end
end
results.definitions = { error = err, result = result, ctx = ctx, config = config } results.definitions = { error = err, result = result, ctx = ctx, config = config }
log(result)
ctx = ctx or {} ctx = ctx or {}
ctx.results = results ctx.results = results
ctx.combine = true ctx.combine = true
ref_view(err, result, ctx, config) ref_view(err, result, ctx, config)
end) -- return asyncresult, canceller end) -- return asyncresult, canceller
ref_params.context = { includeDeclaration = false }
lsp.call_async('textDocument/references', ref_params, function(err, result, ctx, config) lsp.call_async('textDocument/references', ref_params, function(err, result, ctx, config)
if err ~= nil or result == nil then
log('failed to get ref', err, result, ctx, config)
result = {}
end
trace(err, result, ctx, config) trace(err, result, ctx, config)
results.references = { error = err, result = result, ctx = ctx, config = config } results.references = { error = err, result = result, ctx = ctx, config = config }
ctx = ctx or {} ctx = ctx or {}
@ -178,20 +209,17 @@ local ref = function()
local bufnr = vim.api.nvim_get_current_buf() local bufnr = 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, client_id, bufnr) vim.lsp.for_each_buffer_client(bufnr, function(client, _, _)
if client.resolved_capabilities.find_references then if client.server_capabilities.referencesProvider then
client.request('textDocument/references', ref_params, ref_hdlr, bufnr) client.request('textDocument/references', ref_params, ref_hdlr, bufnr)
end end
end) end)
end end
return { return {
reference_handler = ref_hdlr, reference_handler = ref_hdlr,
reference = ref_req, reference = ref_req,
ref_view = ref_view, ref_view = ref_view,
async_ref = async_ref, async_ref = async_ref,
all_ref = ref,
} }

@ -1,16 +1,16 @@
local log = require"guihua.log".info local log = require('guihua.log').info
local trace = require"guihua.log".trace local trace = require('guihua.log').trace
local M = {} local M = {}
local clone = require'guihua.util'.clone local clone = require('guihua.util').clone
local function filename(url) local function filename(url)
if url == nil then if url == nil then
return '' return ''
end end
return url:match("^.+/(.+)$") or url return url:match('^.+/(.+)$') or url
end end
local function extension(url) local function extension(url)
local ext = url:match("^.+(%..+)$") or "txt" local ext = url:match('^.+(%..+)$') or 'txt'
return string.sub(ext, 2) return string.sub(ext, 2)
end end
@ -38,7 +38,6 @@ local function get_pads(win_width, text, postfix)
i = i + rem * 10 i = i + rem * 10
-- log(i) -- log(i)
end end
end end
if i > 3 then if i > 3 then
@ -52,40 +51,32 @@ end
function M.prepare_for_render(items, opts) function M.prepare_for_render(items, opts)
opts = opts or {} opts = opts or {}
if items == nil or #items < 1 then if items == nil or #items < 1 then
vim.notify("no item found or empty fields", vim.lsp.log_levels.INFO) vim.notify('no item found or empty fields', vim.lsp.log_levels.INFO)
return return
end end
local item = clone(items[1]) local item = clone(items[1])
local display_items = {item} local display_items = { item }
local last_summary_idx = 1 local last_summary_idx = 1
local total_ref_in_file = 1 local total_ref_in_file = 1
local total = opts.total local total = opts.total
local icon = "" local icon = ''
local lspapi = opts.api or "" local lspapi = opts.api or ''
local ok, devicons = pcall(require, "nvim-web-devicons") local ok, devicons = pcall(require, 'nvim-web-devicons')
if ok then if ok then
local fn = filename(items[1].filename) local fn = filename(items[1].filename)
local ext = extension(fn) local ext = extension(fn)
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
local width = 100 opts.width = opts.width or 100
opts.width = opts.width or width
local win_width = opts.width -- buf local win_width = opts.width -- buf
for i = 1, #items do
if items[i].call_by and #items[i].call_by > 0 then
call_by_presented = true
end
end
-- log(items[1])
for i = 1, #items do for i = 1, #items do
local space local space
local trim local trim
local lspapi_display = lspapi local lspapi_display = lspapi
items[i].symbol_name = items[i].symbol_name or "" -- some LSP API does not have range for this items[i].symbol_name = items[i].symbol_name or '' -- some LSP API does not have range for this
local fn = display_items[last_summary_idx].filename local fn = display_items[last_summary_idx].filename
local dfn = items[i].display_filename local dfn = items[i].display_filename
@ -98,18 +89,23 @@ function M.prepare_for_render(items, opts)
display_items[last_summary_idx].filename_only = true display_items[last_summary_idx].filename_only = true
-- trace(items[i], items[i].filename, last_summary_idx, display_items[last_summary_idx].filename) -- trace(items[i], items[i].filename, last_summary_idx, display_items[last_summary_idx].filename)
-- TODO refact display_filename generate part -- TODO refact display_filename generate part
if items[i].filename == fn then if items[i].filename == fn or opts.hide_filename then
space, trim = get_pads(opts.width, icon .. ' ' .. dfn, lspapi_display .. ' 14 of 33 ') space, trim = get_pads(opts.width, icon .. ' ' .. dfn, lspapi_display .. ' 14 of 33 ')
if trim and opts.width > 50 and #dfn > opts.width - 20 then if trim and opts.width > 50 and #dfn > opts.width - 20 then
local fn1 = string.sub(dfn, 1, opts.width - 50) local fn1 = string.sub(dfn, 1, opts.width - 50)
local fn2 = string.sub(dfn, #dfn - 10, #dfn) local fn2 = string.sub(dfn, #dfn - 10, #dfn)
display_items[last_summary_idx].display_filename = fn1 .. "" .. fn2 display_items[last_summary_idx].display_filename = fn1 .. '' .. fn2
space = ' ' space = ' '
-- log("trim", fn1, fn2) -- log("trim", fn1, fn2)
end end
local api_disp = string.format("%s %s%s%s %i", icon, local api_disp = string.format(
display_items[last_summary_idx].display_filename, space, '%s %s%s%s %i',
lspapi_display, total_ref_in_file) icon,
display_items[last_summary_idx].display_filename,
space,
lspapi_display,
total_ref_in_file
)
if total then if total then
api_disp = api_disp .. ' of: ' .. tostring(total) api_disp = api_disp .. ' of: ' .. tostring(total)
@ -118,20 +114,17 @@ function M.prepare_for_render(items, opts)
display_items[last_summary_idx].text = api_disp display_items[last_summary_idx].text = api_disp
total_ref_in_file = total_ref_in_file + 1 total_ref_in_file = total_ref_in_file + 1
else else
lspapi_display = lspapi lspapi_display = lspapi
item = clone(items[i]) item = clone(items[i])
space, trim = get_pads(opts.width, icon .. ' ' .. item.display_filename, space, trim = get_pads(opts.width, icon .. ' ' .. item.display_filename, lspapi_display .. ' 12 of 33')
lspapi_display .. ' 12 of 33')
if trim and opts.width > 52 and #item.display_filename > opts.width - 20 then if trim and opts.width > 52 and #item.display_filename > opts.width - 20 then
item.display_filename = string.sub(item.display_filename, 1, opts.width - 52) .. "" item.display_filename = string.sub(item.display_filename, 1, opts.width - 52)
.. string.sub(item.display_filename, .. ''
#item.display_filename - 10, .. string.sub(item.display_filename, #item.display_filename - 10, #item.display_filename)
#item.display_filename)
space = ' ' space = ' '
end end
item.text = string.format("%s %s%s%s 1", icon, item.display_filename, space, lspapi_display) item.text = string.format('%s %s%s%s 1', icon, item.display_filename, space, lspapi_display)
trace(item.text) trace(item.text)
table.insert(display_items, item) table.insert(display_items, item)
@ -140,14 +133,17 @@ function M.prepare_for_render(items, opts)
end end
-- content of code lines -- content of code lines
item = clone(items[i]) item = clone(items[i])
item.text = require'navigator.util'.trim_and_pad(item.text) item.text = require('navigator.util').trim_and_pad(item.text)
item.text = string.format("%4i: %s", item.lnum, item.text) item.text = string.format('%4i: %s', item.lnum, item.text)
local ts_report = "" local ts_report = ''
if item.lhs then if item.lhs then
ts_report = _NgConfigValues.icons.value_changed ts_report = _NgConfigValues.icons.value_changed
end end
-- log(item.text, item.symbol_name, item.uri)
-- log(item.text)
if item.definition then if item.definition then
log('definition', item)
ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' ' ts_report = ts_report .. _NgConfigValues.icons.value_definition .. ' '
end end
local header_len = #ts_report + 4 -- magic number 2 local header_len = #ts_report + 4 -- magic number 2
@ -155,7 +151,7 @@ function M.prepare_for_render(items, opts)
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 > 0 then
trace("call_by:", #item.call_by) trace('call_by:', #item.call_by)
for _, value in pairs(item.call_by) do for _, value in pairs(item.call_by) do
if value.node_text then if value.node_text then
local txt = value.node_text:gsub('%s*[%[%(%{]*%s*$', '') local txt = value.node_text:gsub('%s*[%[%(%{]*%s*$', '')
@ -183,15 +179,26 @@ function M.prepare_for_render(items, opts)
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)
if trim then if trim then
item.text = string.sub(item.text, 1, opts.width - 20) .. "" local ts_r = ts_report or ''
item.text = string.sub(item.text, 1, math.max(1, opts.width - math.max(20, #ts_r)))
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 "/'
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) trace('exceeding', #item.text, #ts_report, win_width)
space = ' ' space = ' '
else else
local remain = win_width - #item.text - #ts_report local remain = win_width - #item.text - #ts_report
trace("remain", remain) trace('remain', remain)
space = string.rep(' ', remain) space = string.rep(' ', remain)
end end
end end

@ -1,11 +1,5 @@
local gui = require "navigator.gui"
local util = require "navigator.util" local util = require "navigator.util"
local mk_handler = util.mk_handler
local log = util.log local log = util.log
local partial = util.partial
local lsphelper = require "navigator.lspwrapper"
local cwd = vim.loop.cwd()
local M = {}
--- navigator signature --- navigator signature
local match_parameter = function(result) local match_parameter = function(result)
@ -47,7 +41,7 @@ local match_parameter = function(result)
end end
end end
local signature_handler = mk_handler(function(err, result, ctx, config) local signature_handler = function(err, result, ctx, config)
if config == nil then if config == nil then
log("config nil") log("config nil")
end end
@ -71,5 +65,5 @@ local signature_handler = mk_handler(function(err, result, ctx, config)
local syntax = vim.lsp.util.try_trim_markdown_code_blocks(lines) local syntax = vim.lsp.util.try_trim_markdown_code_blocks(lines)
config.focus_id = ctx.bufnr .. "lsp_signature" config.focus_id = ctx.bufnr .. "lsp_signature"
vim.lsp.util.open_floating_preview(lines, syntax, config) vim.lsp.util.open_floating_preview(lines, syntax, config)
end) end
return {signature_handler = signature_handler} return {signature_handler = signature_handler}

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

@ -1,28 +1,31 @@
--- Note: some of the functions/code coped from treesitter/refactor/navigation.lua and may be modified --- Note: some of the functions/code coped from treesitter/refactor/navigation.lua and may be modified
-- to fit in navigator.lua -- to fit in navigator.lua
local gui = require "navigator.gui" local gui = require('navigator.gui')
local fn = vim.fn local fn = vim.fn
local lru = require('navigator.lru').new(500, 1024 * 1024) local lru = require('navigator.lru').new(500, 1024 * 1024)
local ok, ts_locals = pcall(require, "nvim-treesitter.locals") local ok, ts_locals = pcall(require, 'nvim-treesitter.locals')
if not ok then if not ok then
error("treesitter not installed") error('treesitter not installed')
return nil return nil
end end
local parsers = require "nvim-treesitter.parsers" local parsers = require('nvim-treesitter.parsers')
local utils = require "nvim-treesitter.utils" local utils = require('nvim-treesitter.utils')
local locals = require 'nvim-treesitter.locals' local locals = require('nvim-treesitter.locals')
local ts_utils = require 'nvim-treesitter.ts_utils' local ts_utils = require('nvim-treesitter.ts_utils')
local api = vim.api local api = vim.api
local util = require "navigator.util" local util = require('navigator.util')
local M = {} local M = {}
local cwd = vim.loop.cwd() 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 = require"navigator.util".trace local trace = function(...) end
if vim.fn.has('nvim-0.7') == 1 then
local trace = require('navigator.util').trace
end
local get_icon = function(kind) local get_icon = function(kind)
if kind == nil or _NgConfigValues.icons.match_kinds[kind] == nil then if kind == nil or _NgConfigValues.icons.match_kinds[kind] == nil then
@ -43,7 +46,7 @@ function M.goto_definition(bufnr)
local definition = locals.find_definition(node_at_point, bufnr) local definition = locals.find_definition(node_at_point, bufnr)
if definition ~= node_at_point then if definition ~= node_at_point then
log("def found:", definition:range()) log('def found:', definition:range())
ts_utils.goto_node(definition) ts_utils.goto_node(definition)
end end
end end
@ -53,7 +56,7 @@ local function node_is_definination(node)
return false return false
end end
local nd_type = node:parent():type() local nd_type = node:parent():type()
local decl = {'short_var_declaration', 'short_var_declaration', 'declaration'} local decl = { 'short_var_declaration', 'short_var_declaration', 'declaration' }
if vim.tbl_contains(decl, nd_type) then if vim.tbl_contains(decl, nd_type) then
return true return true
@ -69,25 +72,24 @@ local function node_is_definination(node)
end end
return false return false
end end
-- use lsp range to find def -- use lsp range to find def
function M.find_definition(range, bufnr) function M.find_definition(range, bufnr)
if not range or not range.start then if not range or not range.start then
lerr("find_def incorrect range", range) lerr('find_def incorrect range', range)
return return
end end
bufnr = bufnr or api.nvim_get_current_buf() bufnr = bufnr or api.nvim_get_current_buf()
local parser = parsers.get_parser(bufnr) local parser = parsers.get_parser(bufnr)
local symbolpos = {range.start.line, range.start.character} -- +1 or not? local symbolpos = { range.start.line, range.start.character } -- +1 or not?
local root = ts_utils.get_root_for_position(range.start.line, range.start.character, parser) local root = ts_utils.get_root_for_position(range.start.line, range.start.character, parser)
if not root then if not root then
return return
end end
local node_at_point = root:named_descendant_for_range(symbolpos[1], symbolpos[2], symbolpos[1], symbolpos[2]) local node_at_point = root:named_descendant_for_range(symbolpos[1], symbolpos[2], symbolpos[1], symbolpos[2])
if not node_at_point then if not node_at_point then
lerr("no node at cursor") lerr('no node at cursor')
return return
end end
@ -95,15 +97,15 @@ function M.find_definition(range, bufnr)
if definition ~= node_at_point then -- NOTE: it may not worksfor some of languages. if def not found, ts if definition ~= node_at_point then -- NOTE: it may not worksfor some of languages. if def not found, ts
-- returns current node. if your node is def, then it also return self... then I have no idea weather it is -- returns current node. if your node is def, then it also return self... then I have no idea weather it is
-- def or not -- def or not
trace("info: def found:", definition:range(), definition:type()) trace('info: def found:', definition:range(), definition:type())
local r, c = definition:range() local r, c = definition:range()
return {start = {line = r, character = c}} return { start = { line = r, character = c } }
elseif node_is_definination(node_at_point) then elseif node_is_definination(node_at_point) then
trace("declaraction here ", definition:type()) trace('declaraction here ', definition:type())
local r, c = definition:range() local r, c = definition:range()
return {start = {line = r, character = c}} return { start = { line = r, character = c } }
else else
trace("error: def not found in ", bufnr, definition:range(), definition:type(), definition:parent():type()) trace('error: def not found in ', bufnr, definition:range(), definition:type(), definition:parent():type())
end end
end end
@ -111,16 +113,69 @@ end
--- 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)
local local_nodes = ts_locals.get_locals(bufnr) local local_nodes = ts_locals.get_locals(bufnr)
-- Make sure the nodes are unique. -- Make sure the nodes are unique.
local nodes_set = {} local nodes_set = {}
for _, loc in ipairs(local_nodes) do for _, loc in ipairs(local_nodes) do
trace(loc)
if loc.definition then if loc.definition then
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 _, _, start = node:start() local k, l, start = node:start()
nodes_set[start] = {node = node, type = match or ""} trace(node, match)
trace(k, l, start, node:parent(), node:parent():start(), node:parent():type())
if node and node:parent() and string.find(node:parent():type(), 'parameter_declaration') then
log('parameter_declaration skip')
return
end
nodes_set[start] = { node = node, type = match or '' }
end)
end
if loc.method then -- for go
ts_locals.recurse_local_nodes(loc.method, function(def, node, full_match, match)
local k, l, start = node:start()
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
nodes_set[start] = { node = node, type = 'method' }
end
end)
end
if loc.interface then -- for go using interface can output full method definition
ts_locals.recurse_local_nodes(loc.interface, function(def, node, full_match, match)
local k, l, start = node:start()
trace(k, l, start, def, node, full_match, match, node:parent(), node:parent():start(), node:parent():type())
if nodes_set[start] == nil then
nodes_set[start] = { node = node, type = match or '' }
end
end)
end
if loc.reference then -- for go
ts_locals.recurse_local_nodes(loc.reference, function(def, node, full_match, match)
local k, l, start = node:start()
local p1, p1t = '', ''
local p2, p2t = '', ''
if node:parent() and node:parent():parent() then
p1 = node:parent()
p1t = node:parent():type()
p2 = node:parent():parent()
p2t = node:parent():parent():type()
end
trace(k, l, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, p2t)
if nodes_set[start] == nil then
if -- qualified_type : e.g. io.Reader inside interface
node:parent()
and node:parent():parent()
and node:type() == 'type_identifier'
and node:parent():type() == 'qualified_type'
and string.find(node:parent():parent():type(), 'interface')
then
log('add node', node)
nodes_set[start] = { node = node, type = match or 'field' }
end
end
end) end)
end end
end end
@ -140,7 +195,7 @@ local function prepare_node(node, kind)
local matches = {} local matches = {}
kind = kind or node.type kind = kind or node.type
if node.node then if node.node then
table.insert(matches, {kind = get_icon(kind), def = node.node, type = kind}) table.insert(matches, { kind = get_icon(kind), def = node.node, type = kind })
else else
for name, item in pairs(node) do for name, item in pairs(node) do
vim.list_extend(matches, prepare_node(item, name)) vim.list_extend(matches, prepare_node(item, name))
@ -150,9 +205,7 @@ local function prepare_node(node, kind)
end end
local function get_scope(type, source) local function get_scope(type, source)
local sbl, sbc, sel, sec = source:range()
local current = source local current = source
local result = current
local next = ts_utils.get_next_node(source) local next = ts_utils.get_next_node(source)
local parent = current:parent() local parent = current:parent()
trace(source:type(), source:range(), parent) trace(source:type(), source:range(), parent)
@ -170,7 +223,7 @@ local function get_scope(type, source)
-- for C++ -- for C++
local n = source local n = source
for i = 1, 4, 1 do for _ = 1, 4, 1 do
if n == nil or n:parent() == nil then if n == nil or n:parent() == nil then
break break
end end
@ -182,8 +235,8 @@ local function get_scope(type, source)
return parent, true return parent, true
end end
if type == "var" and next ~= nil then if type == 'var' and next ~= nil then
if next:type() == "function" or next:type() == "arrow_function" or next:type() == "function_definition" then if next:type() == 'function' or next:type() == 'arrow_function' or next:type() == 'function_definition' then
trace(current:type(), current:range()) trace(current:type(), current:range())
return next, true return next, true
elseif parent:type() == 'function_declaration' then elseif parent:type() == 'function_declaration' then
@ -196,7 +249,7 @@ local function get_scope(type, source)
-- M.fun1 = function() end -- M.fun1 = function() end
-- lets work up and see next node, lua -- lets work up and see next node, lua
local n = source local n = source
for i = 1, 4, 1 do for _ = 1, 4, 1 do
if n == nil or n:parent() == nil then if n == nil or n:parent() == nil then
break break
end end
@ -208,10 +261,9 @@ local function get_scope(type, source)
end end
end end
if source:type() == "type_identifier" then if source:type() == 'type_identifier' then
return source:parent(), true return source:parent(), true
end end
end end
local function get_smallest_context(source) local function get_smallest_context(source)
@ -229,10 +281,10 @@ local function get_smallest_context(source)
-- if source:type() == "identifier" then return get_var_context(source) end -- if source:type() == "identifier" then return get_var_context(source) end
end end
local lsp_reference = require"navigator.dochighlight".goto_adjent_reference local lsp_reference = require('navigator.dochighlight').goto_adjent_reference
function M.goto_adjacent_usage(bufnr, delta) function M.goto_adjacent_usage(bufnr, delta)
local opt = {forward = true} local opt = { forward = true }
-- log(delta) -- log(delta)
if delta < 0 then if delta < 0 then
opt.forward = false opt.forward = false
@ -269,7 +321,7 @@ local function key(fname, filter)
end end
local function get_all_nodes(bufnr, filter, summary) local function get_all_nodes(bufnr, filter, summary)
local fname = vim.fn.expand("%:p:f") local fname = vim.fn.expand('%:p:f')
local uri = vim.uri_from_fname(fname) local uri = vim.uri_from_fname(fname)
if bufnr ~= 0 then if bufnr ~= 0 then
uri = vim.uri_from_bufnr(bufnr) uri = vim.uri_from_bufnr(bufnr)
@ -282,7 +334,8 @@ local function get_all_nodes(bufnr, filter, summary)
local result = lru:get(hash) local result = lru:get(hash)
if result ~= nil and result.ftime == ftime then if result ~= nil and result.ftime == ftime then
log("get data from cache") trace('get data from cache', ftime, result)
return result.nodes, result.length return result.nodes, result.length
end end
@ -292,31 +345,36 @@ 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 invalide 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')
if not parsers.has_parser() then if not parsers.has_parser() then
vim.notify("ts not loaded", vim.lsp.log_levels.WARN) if not require('navigator.lspclient.clients').ft_disabled(ft) then
vim.notify('ts not loaded ' .. ft, vim.lsp.log_levels.Debug)
end
return {}
end end
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 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 -- Support completion-nvim customized label map
local customized_labels = vim.g.completion_customize_lsp_label or {} -- local customized_labels = vim.g.completion_customize_lsp_label or {}
-- Force some types to act like they are parents -- Force some types to act like they are parents
-- instead of neighbors of the next nodes. -- instead of neighbors of the next nodes.
local containers = { 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,
["struct"] = true, -- ['var'] = true,
["method"] = true ['struct'] = true,
['method'] = true,
} }
-- check and load buff -- check and load buff
@ -330,15 +388,31 @@ local function get_all_nodes(bufnr, filter, summary)
-- Step 2 find correct completions -- Step 2 find correct completions
local length = 10 local length = 10
local parents = {} -- stack of nodes a clever algorithm from treesiter refactor @Santos Gallegos local parents = {} -- stack of nodes a clever algorithm from treesiter refactor @Santos Gallegos
local loaded_symbol = {}
for _, def in ipairs(get_definitions(bufnr)) do for _, def in ipairs(get_definitions(bufnr)) do
local n = #parents local n = #parents
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]
if ts_utils.is_parent(parent_def.node, def.node) log(parent_def.type, parent_def.node:type(), vim.treesitter.get_node_text(parent_def.node, bufnr))
or (containers[parent_def.type] and ts_utils.is_parent(parent_def.node:parent(), def.node)) then log(def.node:type(), vim.treesitter.get_node_text(def.node, bufnr))
if
ts_utils.is_parent(parent_def.node, def.node)
or (
containers[parent_def.type]
and (
ts_utils.is_parent(parent_def.node:parent(), def.node)
or (
parent_def.node:parent():type():find('dot_index')
and ts_utils.is_parent(parent_def.node:parent():parent(), def.node)
)
)
)
then
log('is parent', i, index)
break break
else else
log('leave node', i, index)
parents[index] = nil parents[index] = nil
end end
end end
@ -351,15 +425,21 @@ local function get_all_nodes(bufnr, filter, summary)
item.type = node.type item.type = node.type
if filter ~= nil and not filter[item.type] then if filter ~= nil and not filter[item.type] then
trace(item.type, item.kind) trace('skipped', item.type, item.kind)
goto continue
end
if item.type == 'associated' then
trace('skipped', item.type, item.kind)
goto continue goto continue
end end
local tsdata = node.def local tsdata = node.def
if node.def == nil then if node.def == nil then
trace('skipped', item.type, item.kind)
goto continue goto continue
end end
item.node_text = ts_utils.get_node_text(tsdata, bufnr)[1] item.node_text = vim.treesitter.get_node_text(tsdata, bufnr) or ''
local scope, is_func local scope, is_func
if summary then if summary then
@ -370,38 +450,64 @@ local function get_all_nodes(bufnr, filter, summary)
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()
if parent ~= nil and parent:type() == 'function_name' or parent:type() == 'function_name_field' then if parent ~= nil and _NgConfigValues.debug == 'trace' then -- for github action failure
item.node_text = ts_utils.get_node_text(parent, bufnr)[1] trace(parent:type(), vim.treesitter.get_node_text(parent, bufnr):sub(1, 30), item.node_text, item.type)
end
if
parent ~= nil
and (
parent:type() == 'function_name'
-- or parent:type() == 'function'
-- or parent:type() == 'function_declaration' -- this bring in too much info
or parent:type() == 'method_name'
or parent:type() == 'function_name_field'
)
then
-- replace function name
item.node_text = vim.treesitter.get_node_text(parent, bufnr)
local cut = item.node_text:find('[\n\r]')
if cut then
item.node_text = item.node_text:sub(1, cut - 1)
end
log(parent:type(), item.node_text) log(parent:type(), item.node_text)
end end
end end
trace(item.node_text, item.kind, item.type) trace(item.node_text, item.kind, item.type)
if scope ~= nil then if scope ~= nil then
-- it is strange..
if not is_func and summary then if not is_func and summary then
log('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)
end end
if item.node_text and vim.trim(item.node_text) == '_' then
goto continue
end
if summary then if summary then
if item.node_scope ~= nil then if item.node_scope ~= nil then
table.insert(all_nodes, item) table.insert(all_nodes, item)
end end
if item.node_scope then if item.node_scope then
trace(item.type, tsdata:type(), item.node_text, item.kind, item.node_text, "range", trace(
item.node_scope.start.line, item.node_scope['end'].line) -- set to log if need to trace result item.type,
tsdata:type(),
item.node_text,
item.kind,
'range',
item.node_scope.start.line,
item.node_scope['end'].line
) -- set to log if need to trace result
end end
goto continue goto continue
end end
item.range = ts_utils.node_to_lsp_range(tsdata) item.range = ts_utils.node_to_lsp_range(tsdata)
local start_line_node, _, _ = tsdata:start() local start_line_node, _, _ = tsdata:start()
if item.node_text == "_" then
goto continue local line_text = api.nvim_buf_get_lines(bufnr, start_line_node, start_line_node + 1, false)[1] or ''
end item.full_text = vim.trim(line_text)
item.full_text = vim.trim(api.nvim_buf_get_lines(bufnr, start_line_node, start_line_node + 1, false)[1] or "")
item.full_text = item.full_text:gsub('%s*[%[%(%{]*%s*$', '') item.full_text = item.full_text:gsub('%s*[%[%(%{]*%s*$', '')
item.uri = uri item.uri = uri
@ -411,45 +517,76 @@ local function get_all_nodes(bufnr, filter, summary)
item.lnum, item.col, _ = def.node:start() item.lnum, item.col, _ = def.node:start()
item.lnum = item.lnum + 1 item.lnum = item.lnum + 1
item.col = item.col + 1 item.col = item.col + 1
local indent = "" local indent = ''
if #parents > 1 then if #parents > 1 then
indent = string.rep(" ", #parents - 1) .. "" indent = string.rep(' ', #parents - 1) .. ''
end
item.indent = indent
item.indent_level = #parents -- maybe use real indent level ?
if item.indent_level <= 1 then
local sp = string.match(line_text, '(%s*)')
log(line_text, #sp)
if sp then
local indent_level = #sp / (vim.o.shiftwidth or 4) + 1
item.indent_level = math.max(item.indent_level, indent_level)
end
end
if #parents > 0 then
log(parents[1].type, vim.treesitter.get_node_text(parents[1].node, bufnr))
if parents[2] then
log(parents[2].type, vim.treesitter.get_node_text(parents[2].node, bufnr))
end
else
log('root node')
end
if #all_nodes >= 1 then
all_nodes[#all_nodes].next_indent_level = #parents
end end
item.text = string.format(" %s %s%-10s\t %s", item.kind, indent, item.node_text, item.full_text) item.text = string.format(' %s %s%-10s\t %s', item.kind, indent, item.node_text, item.full_text)
if #item.text > length then if #item.text > length then
length = #item.text length = #item.text
end end
table.insert(all_nodes, item) if
loaded_symbol[item.node_text .. item.kind] == nil
or not util.range_inside(loaded_symbol[item.node_text .. item.kind], item.node_scope)
then
table.insert(all_nodes, item)
loaded_symbol[item.node_text .. item.kind] = item.node_scope
end
::continue:: ::continue::
end end
end end
trace(all_nodes) trace(all_nodes)
local nd = {nodes = all_nodes, ftime = vim.fn.getftime(fname), length = length} local nd = { nodes = all_nodes, ftime = vim.fn.getftime(fname), length = length }
lru:set(hash, nd) lru:set(hash, nd)
if should_unload then if should_unload then
vim.api.nvim_buf_delete(bufnr, {unload = true}) vim.api.nvim_buf_delete(bufnr, { unload = true })
end end
return all_nodes, length return all_nodes, length
end end
function M.buf_func(bufnr) function M.buf_func(bufnr)
local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype')
if vim.api.nvim_buf_get_option(bufnr, 'buftype') == 'nofile' then
return
end
if not ok or ts_locals == nil then if not ok or ts_locals == nil then
error("treesitter not loaded") error('treesitter not loaded: ' .. ft)
return return
end end
bufnr = bufnr or api.nvim_get_current_buf() bufnr = bufnr or api.nvim_get_current_buf()
local all_nodes, width = get_all_nodes(bufnr, { local all_nodes, width = get_all_nodes(bufnr, {
["function"] = true, ['function'] = true,
["var"] = true, ['var'] = true,
["method"] = true, ['method'] = true,
["class"] = true, ['class'] = true,
["type"] = true ['type'] = true,
}, true) }, true)
if #all_nodes < 1 then if #all_nodes < 1 then
trace("no node found for ", bufnr) -- set to log trace('no node found for ', bufnr) -- set to log
return return
end end
@ -478,34 +615,59 @@ function M.buf_func(bufnr)
end end
return all_nodes, width return all_nodes, width
end end
function M.buf_ts() function M.all_ts_nodes(bufnr)
if ts_locals == nil then if ts_locals == nil then
error("treesitter not loaded") error('treesitter not loaded')
return return
end end
local bufnr = api.nvim_get_current_buf() bufnr = bufnr or api.nvim_get_current_buf()
local all_nodes, width = get_all_nodes(bufnr) local all_nodes, width = get_all_nodes(bufnr)
return all_nodes, width
end
local ft = vim.api.nvim_buf_get_option(bufnr, "ft") function M.side_panel()
gui.new_list_view({ Panel = require('guihua.panel')
local bufnr = api.nvim_get_current_buf()
local panel = Panel:new({
header = 'treesitter',
render = function(b)
local ft = vim.api.nvim_buf_get_option(b, 'buftype')
log('render for ', bufnr, b)
if ft == 'nofile' or ft == 'guihua' then
b = bufnr
end
return require('navigator.treesitter').all_ts_nodes(b)
end,
scope = 'node_scope'
})
panel:open(true)
end
function M.buf_ts()
local all_nodes, width = M.all_ts_nodes()
local bufnr = api.nvim_get_current_buf()
local ft = vim.api.nvim_buf_get_option(bufnr, 'ft')
local listview = gui.new_list_view({
items = all_nodes, items = all_nodes,
prompt = true, prompt = true,
ft = ft, ft = ft,
rawdata = true, rawdata = true,
height = 0.62,
preview_height = 0.12,
width = width + 10, width = width + 10,
api = _NgConfigValues.icons.treesitter_defult api = _NgConfigValues.icons.treesitter_defult,
}) })
return listview, all_nodes, width
end end
M.get_all_nodes = get_all_nodes M.get_all_nodes = get_all_nodes
function M.bufs_ts() function M.bufs_ts()
if ts_locals == nil then if ts_locals == nil then
error("treesitter not loaded") error('treesitter not loaded')
return return
end end
local bufs = vim.api.nvim_list_bufs() local bufs = vim.api.nvim_list_bufs()
@ -528,13 +690,15 @@ function M.bufs_ts()
if #ts_opened > 1 then if #ts_opened > 1 then
trace(ts_opened) trace(ts_opened)
local ft = vim.api.nvim_buf_get_option(0, "ft") local ft = vim.api.nvim_buf_get_option(0, 'ft')
gui.new_list_view({ gui.new_list_view({
items = ts_opened, items = ts_opened,
prompt = true, prompt = true,
ft = ft, ft = ft,
height = 0.62,
preview_height = 0.12,
width = max_length + 10, width = max_length + 10,
api = _NgConfigValues.icons.treesitter_defult api = _NgConfigValues.icons.treesitter_defult,
}) })
end end
end end
@ -543,7 +707,7 @@ local function node_in_range(parser, range)
for _, child in pairs(parser._children) do for _, child in pairs(parser._children) do
if child:contains(range) then if child:contains(range) then
local result = node_in_range(child, range) local result = node_in_range(child, range)
if not vim.tbl_contains({vim.bo.filetype}, result:lang()) then if not vim.tbl_contains({ vim.bo.filetype }, result:lang()) then
-- log("not correct tree embedded or comment?", result:lang()) -- log("not correct tree embedded or comment?", result:lang())
return parser return parser
end end
@ -564,7 +728,7 @@ function M.get_node_at_line(lnum)
lnum = cursor[1] lnum = cursor[1]
end end
local first_non_whitespace_col = fn.match(fn.getline(lnum), '\\S') local first_non_whitespace_col = fn.match(fn.getline(lnum), '\\S')
local range = {lnum - 1, first_non_whitespace_col, lnum - 1, first_non_whitespace_col} local range = { lnum - 1, first_non_whitespace_col, lnum - 1, first_non_whitespace_col }
-- Get the language tree with nodes inside the given range -- Get the language tree with nodes inside the given range
local root = parsers.get_parser() local root = parsers.get_parser()
@ -578,7 +742,7 @@ function M.get_node_at_line(lnum)
return node return node
end end
local usage_namespace = vim.api.nvim_create_namespace("nvim-treesitter-usages") local usage_namespace = vim.api.nvim_create_namespace('nvim-treesitter-usages')
function M.highlight_usages(bufnr) function M.highlight_usages(bufnr)
M.clear_usage_highlights(bufnr) M.clear_usage_highlights(bufnr)
@ -595,12 +759,12 @@ function M.highlight_usages(bufnr)
for _, usage_node in ipairs(usages) do for _, usage_node in ipairs(usages) do
if usage_node ~= node_at_point then if usage_node ~= node_at_point then
ts_utils.highlight_node(usage_node, bufnr, usage_namespace, "TSDefinitionUsage") ts_utils.highlight_node(usage_node, bufnr, usage_namespace, 'TSDefinitionUsage')
end end
end end
if def_node ~= node_at_point then if def_node ~= node_at_point then
ts_utils.highlight_node(def_node, bufnr, usage_namespace, "TSDefinition") ts_utils.highlight_node(def_node, bufnr, usage_namespace, 'TSDefinition')
end end
end end
@ -610,7 +774,7 @@ end
function M.get_node_at_pos(pos, parser) function M.get_node_at_pos(pos, parser)
-- local cursor = api.nvim_win_get_cursor(winnr or 0) -- local cursor = api.nvim_win_get_cursor(winnr or 0)
local cursor_range = {pos[1], pos[2]} local cursor_range = { pos[1], pos[2] }
log(cursor_range) log(cursor_range)
local root = ts_utils.get_root_for_position(unpack(cursor_range), parser) local root = ts_utils.get_root_for_position(unpack(cursor_range), parser)
@ -651,7 +815,6 @@ function M.get_node_scope(node)
end end
return sr, sc, er, ec return sr, sc, er, ec
end end
return M return M

@ -3,8 +3,11 @@
-- Some of function copied from https://github.com/RishabhRD/nvim-lsputils -- Some of function copied from https://github.com/RishabhRD/nvim-lsputils
local M = { log_path = vim.lsp.get_log_path() } local M = { log_path = vim.lsp.get_log_path() }
-- local is_windows = uv.os_uname().version:match("Windows") -- local is_windows = uv.os_uname().version:match("Windows")
local guihua = require('guihua.util')
local nvim_0_6 local nvim_0_6_1
local nvim_0_8
local vfn = vim.fn
local api = vim.api
M.path_sep = function() M.path_sep = function()
local is_win = vim.loop.os_uname().sysname:find('Windows') local is_win = vim.loop.os_uname().sysname:find('Windows')
@ -41,10 +44,10 @@ function M.get_data_from_file(filename, startLine)
end end
local uri = 'file:///' .. filename local uri = 'file:///' .. filename
local bufnr = vim.uri_to_bufnr(uri) local bufnr = vim.uri_to_bufnr(uri)
if not vim.api.nvim_buf_is_loaded(bufnr) then if not api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr) vfn.bufload(bufnr)
end end
local data = vim.api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false) local data = api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false)
if data == nil or vim.tbl_isempty(data) then if data == nil or vim.tbl_isempty(data) then
startLine = nil startLine = nil
else else
@ -58,6 +61,29 @@ 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)
local f = io.open(filename, 'r')
if f == nil then
return nil
end
local content = f:read('*a') -- *a or *all reads the whole file
f:close()
return content
end
function M.rm_file(filename)
return os.remove(filename)
end
function M.file_exists(name)
local f = io.open(name, 'r')
if f ~= nil then
io.close(f)
return true
end
return false
end
M.merge = function(t1, t2) M.merge = function(t1, t2)
for k, v in pairs(t2) do for k, v in pairs(t2) do
t1[k] = v t1[k] = v
@ -76,9 +102,9 @@ M.map = function(modes, key, result, options)
for i = 1, #modes do for i = 1, #modes do
if buffer then if buffer then
vim.api.nvim_buf_set_keymap(0, modes[i], key, result, options) api.nvim_buf_set_keymap(0, modes[i], key, result, options)
else else
vim.api.nvim_set_keymap(modes[i], key, result, options) api.nvim_set_keymap(modes[i], key, result, options)
end end
end end
end end
@ -113,7 +139,13 @@ end
function M.get_relative_path(base_path, my_path) function M.get_relative_path(base_path, my_path)
local base_data = getDir(base_path) local base_data = getDir(base_path)
if base_data == nil then
return
end
local my_data = getDir(my_path) local my_data = getDir(my_path)
if my_data == nil then
return
end
local base_len = #base_data local base_len = #base_data
local my_len = #my_data local my_len = #my_data
@ -151,13 +183,31 @@ if _NgConfigValues.debug_console_output then
default_config.use_console = true default_config.use_console = true
default_config.use_file = false default_config.use_file = false
end end
M._log = require('guihua.log').new(default_config, true) M._log = require('guihua.log').new(default_config, true)
if _NgConfigValues.debug then
-- add log to you lsp.log
-- add log to you lsp.log M.trace = M._log.trace
M.log = M._log.info M.info = M._log.info
M.info = M._log.info M.warn = M._log.warn
M.trace = M._log.trace M.error = M._log.error
M.error = M._log.error M.log = M.info
else
M.log = function(...)
return { ... }
end
M.info = function(...)
return { ... }
end
M.trace = function(...)
return { ... }
end
M.warn = function(...)
return { ... }
end
M.error = M._log.error
end
function M.fmt(...) function M.fmt(...)
M._log.fmt_info(...) M._log.fmt_info(...)
@ -251,7 +301,7 @@ function M.split2(s, sep)
sep = sep or ' ' sep = sep or ' '
local pattern = string.format('([^%s]+)', sep) local pattern = string.format('([^%s]+)', sep)
string.gsub(s, pattern, function(c) _ = string.gsub(s, pattern, function(c)
fields[#fields + 1] = c fields[#fields + 1] = c
end) end)
@ -278,30 +328,18 @@ function M.trim_and_pad(txt)
end end
M.open_file = function(filename) M.open_file = function(filename)
vim.api.nvim_command(string.format('e! %s', filename)) api.nvim_command(string.format('e! %s', filename))
end end
M.open_file_at = function(filename, line, col, split) M.open_file_at = guihua.open_file_at
if split == nil then
-- code
vim.api.nvim_command(string.format('e! +%s %s', line, filename))
elseif split == 'v' then
vim.api.nvim_command(string.format('vsp! +%s %s', line, filename))
elseif split == 's' then
vim.api.nvim_command(string.format('sp! +%s %s', line, filename))
end
-- vim.api.nvim_command(string.format("e! %s", filename))
col = col or 1
vim.fn.cursor(line, col)
end
function M.exists(var) -- function M.exists(var)
for k, _ in pairs(_G) do -- for k, _ in pairs(_G) do
if k == var then -- if k == var then
return true -- return true
end -- end
end -- end
end -- end
local exclude_ft = { 'scrollbar', 'help', 'NvimTree' } local exclude_ft = { 'scrollbar', 'help', 'NvimTree' }
function M.exclude(fname) function M.exclude(fname)
@ -317,7 +355,6 @@ end
-- name space search -- name space search
local nss local nss
local api = vim.api
local bufs local bufs
function M.set_virt_eol(bufnr, lnum, chunks, priority, id) function M.set_virt_eol(bufnr, lnum, chunks, priority, id)
@ -355,40 +392,56 @@ function M.get_current_winid()
return api.nvim_get_current_win() return api.nvim_get_current_win()
end end
function M.nvim_0_6() function M.nvim_0_6_1()
if nvim_0_6 ~= nil then if nvim_0_6_1 ~= nil then
return nvim_0_6 return nvim_0_6_1
end end
if debug.getinfo(vim.lsp.handlers.signature_help).nparams == 4 then nvim_0_6_1 = vfn.has('nvim-0.6.1') == 1
nvim_0_6 = true if nvim_0_6_1 == false then
else M.warn('Please use navigator 0.3 version for neovim version < 0.6.1')
nvim_0_6 = false end
return nvim_0_6_1
end
function M.nvim_0_8()
if nvim_0_8 ~= nil then
return nvim_0_8
end end
return nvim_0_6 nvim_0_8 = vfn.has('nvim-0.8') == 1
if nvim_0_8 == false then
M.log('Please use navigator 0.4 version for neovim version < 0.8')
end
return nvim_0_8
end end
function M.mk_handler(fn) function M.mk_handler(fn)
return function(...) return function(...)
local config_or_client_id = select(4, ...) return fn(...)
local is_new = M.nvim_0_6()
if is_new then
return fn(...)
else
local err = select(1, ...)
local method = select(2, ...)
local result = select(3, ...)
local client_id = select(4, ...)
local bufnr = select(5, ...)
local config = select(6, ...)
return fn(err, result, { method = method, client_id = client_id, bufnr = bufnr }, config)
end
end end
end end
function M.partial(func, arg) function M.partial(func, arg)
return (M.mk_handler(function(...) return function(...)
return func(arg, ...) return func(arg, ...)
end)) end
end
function M.partial2(func, arg1, arg2)
return function(...)
return func(arg1, arg2, ...)
end
end
function M.partial3(func, arg1, arg2, arg3)
return function(...)
return func(arg1, arg2, arg3, ...)
end
end
function M.partial4(func, arg1, arg2, arg3, arg4)
return function(...)
return func(arg1, arg2, arg3, arg4, ...)
end
end end
function M.empty(t) function M.empty(t)
@ -403,18 +456,19 @@ function M.empty(t)
end end
function M.encoding(client) function M.encoding(client)
if type(client) ~= 'table' then if client == nil then
if client == nil then client = 1
client = 1 end
end
client = vim.lsp.get_client_by_id(client) if type(client) == 'number' then
client = vim.lsp.get_client_by_id(client) or {}
end end
local oe = client.offset_encoding local oe = client.offset_encoding
if oe == nil then if oe == nil then
return 'utf-8' return 'utf-8'
end end
if type(oe) == 'table' then if type(oe) == 'table' then
oe = oe[1] or 'utf-8' return oe[1]
end end
return oe return oe
end end
@ -422,15 +476,25 @@ end
-- alternatively: use vim.notify("namespace does not exist or is anonymous", vim.log.levels.ERROR) -- alternatively: use vim.notify("namespace does not exist or is anonymous", vim.log.levels.ERROR)
function M.warn(msg) function M.warn(msg)
vim.api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {}) vim.notify('WRN: ' .. msg, vim.lsp.log_levels.WARN)
end end
function M.error(msg) function M.error(msg)
vim.api.nvim_echo({ { 'ERR: ' .. msg, 'ErrorMsg' } }, true, {}) vim.notify('ERR: ' .. msg, vim.lsp.log_levels.EROR)
end end
function M.info(msg) function M.info(msg)
vim.api.nvim_echo({ { 'Info: ' .. msg } }, true, {}) vim.notify('INF: ' .. msg, vim.lsp.log_levels.INFO)
end
function M.range_inside(outer, inner)
if outer == nil or inner == nil then
return false
end
if outer.start == nil or outer['end'] == nil or inner.start == nil or inner['end'] == nil then
return false
end
return outer.start.line <= inner.start.line and outer['end'].line >= inner['end'].line
end end
return M return M

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

@ -12,13 +12,14 @@ most used plugins for programmer.
- luasnip - luasnip
- aurora (colorscheme used in the screenshot) - aurora (colorscheme used in the screenshot)
There also three folder `js`, `go`, `py`. Those folder have some basic source code you can play with. There are three folders `js`, `go`, `py`. Those folders have some basic source code you can play with.
The init will install the plugins in ``/tmp/nvim`` folder. It will not affect your current setup.
## Install LSP ## Install LSP
The playground has js, py, go folder, so you can install either one your self in your PATH. The playground has js, py, go folder, so you can install either one your self in your PATH.
If you want to try lua, Please check sumneko setup in init.lua make sure it pointed to correct path. By default it If you want to try lua, Please check sumneko setup in init.lua make sure it pointed to correct path. By default it
potint to ~/github/sumneko potint to ~/github/sumneko if not existed in your PATH.
## run init.lua ## run init.lua

@ -10,7 +10,7 @@ local sumneko_root_path = vim.fn.expand('$HOME') .. '/github/sumneko/lua-languag
local sumneko_binary = vim.fn.expand('$HOME') .. '/github/sumneko/lua-language-server/bin/macOS/lua-language-server' local sumneko_binary = vim.fn.expand('$HOME') .. '/github/sumneko/lua-language-server/bin/macOS/lua-language-server'
local lua_cfg = { local lua_cfg = {
cmd = { sumneko_binary, '-E', sumneko_root_path .. '/main.lua' }, -- cmd = { sumneko_binary, '-E', sumneko_root_path .. '/main.lua' },
settings = { settings = {
Lua = { Lua = {
runtime = { version = 'LuaJIT', path = vim.split(package.path, ';') }, runtime = { version = 'LuaJIT', path = vim.split(package.path, ';') },
@ -19,6 +19,10 @@ local lua_cfg = {
}, },
} }
if vim.fn.executable('lua-language-server') == 0 then
lua_cfg.cmd = { sumneko_binary, '-E', sumneko_root_path .. '/main.lua' }
end
local function load_plugins() local function load_plugins()
require('packer').startup({ require('packer').startup({
function(use) function(use)
@ -38,7 +42,7 @@ local function load_plugins()
use({ 'ray-x/aurora' }) use({ 'ray-x/aurora' })
use({ use({
'ray-x/navigator.lua', 'ray-x/navigator.lua',
-- '~/github/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({

@ -0,0 +1,61 @@
vim.cmd([[set runtimepath=$VIMRUNTIME]])
vim.cmd([[set packpath=/tmp/nvim/site]])
local package_root = '/tmp/nvim/site/pack'
local install_path = package_root .. '/packer/start/packer.nvim'
vim.g.coq_settings = {
['auto_start'] = 'shut-up',
}
local function load_plugins()
require('packer').startup({
function(use)
use('wbthomason/packer.nvim')
use('neovim/nvim-lspconfig')
use({
'williamboman/nvim-lsp-installer',
config = function()
local lsp_installer = require('nvim-lsp-installer')
lsp_installer.setup{}
end,
})
use({
'ray-x/navigator.lua',
config = function()
require('navigator').setup({
debug = true,
lsp_installer = true,
keymaps = { { key = 'gR', func = "require('navigator.reference').async_ref()" } },
})
end,
})
use('ray-x/guihua.lua')
-- -- COQ (Autocompletion)
use('ms-jpq/coq_nvim')
use('ms-jpq/coq.artifacts')
use('ms-jpq/coq.thirdparty')
use('ray-x/aurora')
end,
config = {
package_root = package_root,
compile_path = install_path .. '/plugin/packer_compiled.lua',
},
})
-- navigator/LSP setup
end
if vim.fn.isdirectory(install_path) == 0 then
print('install packer')
vim.fn.system({
'git',
'clone',
'https://github.com/wbthomason/packer.nvim',
install_path,
})
load_plugins()
require('packer').sync()
vim.cmd('colorscheme aurora')
else
load_plugins()
vim.cmd('colorscheme aurora')
end

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

@ -0,0 +1,14 @@
from random import shuffle
a = list(range(5))
def go(beg, c, b):
if beg >= len(a):
print(a )
for i in range(beg, len(a)):
a[beg], a[i] = a[i], a[beg]
go(beg + 1)
a[beg], a[i] = a[i], a[beg]
print(a, b)
go(0, 1, 4)
shuffle([1, 2,3 ])

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

@ -1,13 +1,13 @@
local helpers = {} local helpers = {}
local busted = require("plenary/busted") local busted = require('plenary/busted')
local eq = assert.are.same local eq = assert.are.same
local cur_dir = vim.fn.expand("%:p:h") local cur_dir = vim.fn.expand('%:p:h')
-- local status = require("plenary.reload").reload_module("go.nvim") -- local status = require("plenary.reload").reload_module("go.nvim")
-- status = require("plenary.reload").reload_module("nvim-treesitter") -- status = require("plenary.reload").reload_module("nvim-treesitter")
-- local ulog = require('go.utils').log -- local ulog = require('go.utils').log
describe("should run lsp reference", function() describe('should run lsp reference', function()
-- vim.fn.readfile('minimal.vim') -- vim.fn.readfile('minimal.vim')
local nvim_6 = true local nvim_6 = true
if debug.getinfo(vim.lsp.handlers.signature_help).nparams > 4 then if debug.getinfo(vim.lsp.handlers.signature_help).nparams > 4 then
@ -15,113 +15,90 @@ describe("should run lsp reference", function()
end end
local result = { local result = {
{ {
range = {['end'] = {character = 6, line = 14}, start = {character = 1, line = 14}}, range = { ['end'] = { character = 6, line = 14 }, start = { character = 1, line = 14 } },
uri = "file://" .. cur_dir .. "/tests/fixtures/interface.go" uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
}, { },
range = {['end'] = {character = 15, line = 24}, start = {character = 10, line = 24}}, {
uri = "file://" .. cur_dir .. "/tests/fixtures/interface.go" range = { ['end'] = { character = 15, line = 24 }, start = { character = 10, line = 24 } },
}, { uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
range = {['end'] = {character = 17, line = 28}, start = {character = 12, line = 28}}, },
uri = "file://" .. cur_dir .. "/tests/fixtures/interface.go" {
}, { range = { ['end'] = { character = 17, line = 28 }, start = { character = 12, line = 28 } },
range = {['end'] = {character = 19, line = 51}, start = {character = 14, line = 51}}, uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
uri = "file://" .. cur_dir .. "/tests/fixtures/interface.go" },
}, { {
range = {['end'] = {character = 19, line = 55}, start = {character = 14, line = 55}}, range = { ['end'] = { character = 19, line = 51 }, start = { character = 14, line = 51 } },
uri = "file://" .. cur_dir .. "/tests/fixtures/interface.go" uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
}, { },
range = {['end'] = {character = 16, line = 59}, start = {character = 11, line = 59}}, {
range = { ['end'] = { character = 19, line = 55 }, start = { character = 14, line = 55 } },
uri = "file://" .. cur_dir .. "/tests/fixtures/interface.go" uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
}, { },
range = {['end'] = {character = 16, line = 5}, start = {character = 11, line = 5}}, {
uri = "file://" .. cur_dir .. "/tests/fixtures/interface_test.go" range = { ['end'] = { character = 16, line = 59 }, start = { character = 11, line = 59 } },
}
}
it("should show references", function()
local status = require("plenary.reload").reload_module("navigator")
local status = require("plenary.reload").reload_module("guihua")
local status = require("plenary.reload").reload_module("lspconfig")
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. "/tests/fixtures/interface.go" -- %:p:h ? %:p
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr("")
-- require'lspconfig'.gopls.setup {}
require'navigator'.setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = {code_action_icon = "A "},
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
border = 'none'
})
-- allow gopls start uri = 'file://' .. cur_dir .. '/tests/fixtures/interface.go',
for i = 1, 10 do },
vim.wait(400, function() {
end) range = { ['end'] = { character = 16, line = 5 }, start = { character = 11, line = 5 } },
local clients = vim.lsp.get_active_clients() uri = 'file://' .. cur_dir .. '/tests/fixtures/interface_test.go',
print("lsp clients: ", #clients) },
if #clients > 0 then }
local status = require('plenary.reload').reload_module('navigator')
status = require('plenary.reload').reload_module('guihua')
status = require('plenary.reload').reload_module('lspconfig')
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. '/tests/fixtures/interface.go' -- %:p:h ? %:p
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr('')
-- require'lspconfig'.gopls.setup {}
require('navigator').setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = { code_action_icon = 'A ' },
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
border = 'none',
})
if vim.fn.has('nvim-0.7') then
_NgConfigValues.treesitter_analysis = true
else
_NgConfigValues.treesitter_analysis = false
end
-- allow gopls start
for _ = 1, 20 do
vim.wait(400, function() end)
local found = false
for _, client in ipairs(vim.lsp.get_active_clients()) do
if client.name == 'gopls' then
found = true
break break
end end
end end
if found then
break
end
end
it('should show references', function()
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
vim.fn.setpos(".", {bufn, 15, 4, 0}) -- width vim.bo.filetype = 'go'
vim.lsp.buf.references()
vim.bo.filetype = "go"
-- vim.lsp.buf.references()
eq(1, 1) eq(1, 1)
end) end)
it("reference handler should return items", function() it('reference handler should return items', function()
vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width
local status = require("plenary.reload").reload_module("navigator")
local status = require("plenary.reload").reload_module("guihua")
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. "/tests/fixtures/interface.go" -- %:p:h ? %:p
print(path)
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
-- vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr("")
vim.fn.setpos(".", {bufn, 15, 4, 0}) -- width
vim.bo.filetype = "go"
require'navigator'.setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = {code_action_icon = "A "},
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
debug_console_output = true,
border = 'none'
})
_NgConfigValues.debug_console_output = true
vim.bo.filetype = "go"
-- allow gopls start
for i = 1, 10 do
vim.wait(400, function()
end)
local clients = vim.lsp.get_active_clients()
print("clients ", #clients)
if #clients > 0 then
break
end
end
vim.bo.filetype = 'go'
-- allow gopls start -- allow gopls start
vim.wait(200, function() vim.wait(200, function() end)
end)
local win, items, width local win, items, width
@ -129,65 +106,22 @@ describe("should run lsp reference", function()
win, items, width = require('navigator.reference').ref_view(nil, result, { win, items, width = require('navigator.reference').ref_view(nil, result, {
method = 'textDocument/references', method = 'textDocument/references',
bufnr = 1, bufnr = 1,
client_id = 1 client_id = 1,
}, {}) }, {})
else else
win, items, width = require('navigator.reference').reference_handler(nil, "textDocument/references", result, 1, 1) win, items, width = require('navigator.reference').reference_handler(nil, 'textDocument/references', result, 1, 1)
end end
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, './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')
-- eq(width, 60) -- eq(width, 60)
end) end)
it("reference handler should return items with thread", function() it('reference handler should return items with thread', function()
vim.wait(200, function() end)
local status = require("plenary.reload").reload_module("navigator")
local status = require("plenary.reload").reload_module("guihua")
vim.cmd([[packadd navigator.lua]])
vim.cmd([[packadd guihua.lua]])
local path = cur_dir .. "/tests/fixtures/interface.go" -- %:p:h ? %:p
print(path)
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.cmd([[cd %:p:h]])
local bufn = vim.fn.bufnr("")
vim.fn.setpos(".", {bufn, 15, 4, 0}) -- width
vim.bo.filetype = "go"
require'navigator'.setup({
debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log
icons = {code_action_icon = "A "},
width = 0.75, -- max width ratio (number of cols for the floating window) / (window width)
height = 0.3, -- max list window height, 0.3 by default
preview_height = 0.35, -- max height of preview windows
debug_console_output = true,
border = 'none'
})
_NgConfigValues.debug_console_output = true
vim.bo.filetype = "go"
-- allow gopls start
for i = 1, 10 do
vim.wait(400, function()
end)
local clients = vim.lsp.get_active_clients()
print("clients ", #clients)
if #clients > 0 then
break
end
end
-- allow gopls start
vim.wait(200, function()
end)
local win, items, width local win, items, width
@ -195,18 +129,15 @@ describe("should run lsp reference", function()
win, items, width = require('navigator.reference').ref_view(nil, result, { win, items, width = require('navigator.reference').ref_view(nil, result, {
method = 'textDocument/references', method = 'textDocument/references',
bufnr = 1, bufnr = 1,
client_id = 1 client_id = 1,
}, {truncate = 2}) }, { truncate = 2 })
else else
win, items, width = require('navigator.reference').reference_handler(nil, "textDocument/references", result, 1, 1) win, items, width = require('navigator.reference').reference_handler(nil, 'textDocument/references', result, 1, 1)
end end
-- 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, './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")

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